mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 07:17:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
453
widget/windows/AudioSession.cpp
Normal file
453
widget/windows/AudioSession.cpp
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
/* -*- 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 <windows.h>
|
||||
#include <audiopolicy.h>
|
||||
#include <mmdeviceapi.h>
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
#include "nsIXULAppInfo.h"
|
||||
|
||||
//#include "AudioSession.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include <objbase.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
/*
|
||||
* To take advantage of what Vista+ have to offer with respect to audio,
|
||||
* we need to maintain an audio session. This class wraps IAudioSessionControl
|
||||
* and implements IAudioSessionEvents (for callbacks from Windows)
|
||||
*/
|
||||
class AudioSession final : public IAudioSessionEvents {
|
||||
private:
|
||||
AudioSession();
|
||||
~AudioSession();
|
||||
public:
|
||||
static AudioSession* GetSingleton();
|
||||
|
||||
// COM IUnknown
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP QueryInterface(REFIID, void**);
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IAudioSessionEvents
|
||||
STDMETHODIMP OnChannelVolumeChanged(DWORD aChannelCount,
|
||||
float aChannelVolumeArray[],
|
||||
DWORD aChangedChannel,
|
||||
LPCGUID aContext);
|
||||
STDMETHODIMP OnDisplayNameChanged(LPCWSTR aDisplayName, LPCGUID aContext);
|
||||
STDMETHODIMP OnGroupingParamChanged(LPCGUID aGroupingParam, LPCGUID aContext);
|
||||
STDMETHODIMP OnIconPathChanged(LPCWSTR aIconPath, LPCGUID aContext);
|
||||
STDMETHODIMP OnSessionDisconnected(AudioSessionDisconnectReason aReason);
|
||||
private:
|
||||
nsresult OnSessionDisconnectedInternal();
|
||||
public:
|
||||
STDMETHODIMP OnSimpleVolumeChanged(float aVolume,
|
||||
BOOL aMute,
|
||||
LPCGUID aContext);
|
||||
STDMETHODIMP OnStateChanged(AudioSessionState aState);
|
||||
|
||||
nsresult Start();
|
||||
nsresult Stop();
|
||||
void StopInternal();
|
||||
|
||||
nsresult GetSessionData(nsID& aID,
|
||||
nsString& aSessionName,
|
||||
nsString& aIconPath);
|
||||
|
||||
nsresult SetSessionData(const nsID& aID,
|
||||
const nsString& aSessionName,
|
||||
const nsString& aIconPath);
|
||||
|
||||
enum SessionState {
|
||||
UNINITIALIZED, // Has not been initialized yet
|
||||
STARTED, // Started
|
||||
CLONED, // SetSessionInfoCalled, Start not called
|
||||
FAILED, // The audio session failed to start
|
||||
STOPPED, // Stop called
|
||||
AUDIO_SESSION_DISCONNECTED // Audio session disconnected
|
||||
};
|
||||
protected:
|
||||
RefPtr<IAudioSessionControl> mAudioSessionControl;
|
||||
nsString mDisplayName;
|
||||
nsString mIconPath;
|
||||
nsID mSessionGroupingParameter;
|
||||
SessionState mState;
|
||||
|
||||
ThreadSafeAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
static AudioSession* sService;
|
||||
};
|
||||
|
||||
nsresult
|
||||
StartAudioSession()
|
||||
{
|
||||
return AudioSession::GetSingleton()->Start();
|
||||
}
|
||||
|
||||
nsresult
|
||||
StopAudioSession()
|
||||
{
|
||||
return AudioSession::GetSingleton()->Stop();
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetAudioSessionData(nsID& aID,
|
||||
nsString& aSessionName,
|
||||
nsString& aIconPath)
|
||||
{
|
||||
return AudioSession::GetSingleton()->GetSessionData(aID,
|
||||
aSessionName,
|
||||
aIconPath);
|
||||
}
|
||||
|
||||
nsresult
|
||||
RecvAudioSessionData(const nsID& aID,
|
||||
const nsString& aSessionName,
|
||||
const nsString& aIconPath)
|
||||
{
|
||||
return AudioSession::GetSingleton()->SetSessionData(aID,
|
||||
aSessionName,
|
||||
aIconPath);
|
||||
}
|
||||
|
||||
AudioSession* AudioSession::sService = nullptr;
|
||||
|
||||
AudioSession::AudioSession()
|
||||
{
|
||||
mState = UNINITIALIZED;
|
||||
}
|
||||
|
||||
AudioSession::~AudioSession()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AudioSession*
|
||||
AudioSession::GetSingleton()
|
||||
{
|
||||
if (!(AudioSession::sService)) {
|
||||
RefPtr<AudioSession> service = new AudioSession();
|
||||
service.forget(&AudioSession::sService);
|
||||
}
|
||||
|
||||
// We don't refcount AudioSession on the Gecko side, we hold one single ref
|
||||
// as long as the appshell is running.
|
||||
return AudioSession::sService;
|
||||
}
|
||||
|
||||
// It appears Windows will use us on a background thread ...
|
||||
NS_IMPL_ADDREF(AudioSession)
|
||||
NS_IMPL_RELEASE(AudioSession)
|
||||
|
||||
STDMETHODIMP
|
||||
AudioSession::QueryInterface(REFIID iid, void **ppv)
|
||||
{
|
||||
const IID IID_IAudioSessionEvents = __uuidof(IAudioSessionEvents);
|
||||
if ((IID_IUnknown == iid) ||
|
||||
(IID_IAudioSessionEvents == iid)) {
|
||||
*ppv = static_cast<IAudioSessionEvents*>(this);
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
// Once we are started Windows will hold a reference to us through our
|
||||
// IAudioSessionEvents interface that will keep us alive until the appshell
|
||||
// calls Stop.
|
||||
nsresult
|
||||
AudioSession::Start()
|
||||
{
|
||||
MOZ_ASSERT(mState == UNINITIALIZED ||
|
||||
mState == CLONED ||
|
||||
mState == AUDIO_SESSION_DISCONNECTED,
|
||||
"State invariants violated");
|
||||
|
||||
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
|
||||
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
|
||||
const IID IID_IAudioSessionManager = __uuidof(IAudioSessionManager);
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// There's a matching CoUninit in Stop() for this tied to a state of
|
||||
// UNINITIALIZED.
|
||||
hr = CoInitialize(nullptr);
|
||||
MOZ_ASSERT(SUCCEEDED(hr), "CoInitialize failure in audio session control, unexpected");
|
||||
|
||||
if (mState == UNINITIALIZED) {
|
||||
mState = FAILED;
|
||||
|
||||
// Content processes should be CLONED
|
||||
if (XRE_IsContentProcess()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Should only get here in a chrome process!");
|
||||
|
||||
nsCOMPtr<nsIStringBundleService> bundleService =
|
||||
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(bundleService, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsIStringBundle> bundle;
|
||||
bundleService->CreateBundle("chrome://branding/locale/brand.properties",
|
||||
getter_AddRefs(bundle));
|
||||
NS_ENSURE_TRUE(bundle, NS_ERROR_FAILURE);
|
||||
|
||||
bundle->GetStringFromName(u"brandFullName",
|
||||
getter_Copies(mDisplayName));
|
||||
|
||||
wchar_t *buffer;
|
||||
mIconPath.GetMutableData(&buffer, MAX_PATH);
|
||||
::GetModuleFileNameW(nullptr, buffer, MAX_PATH);
|
||||
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
||||
do_GetService("@mozilla.org/uuid-generator;1");
|
||||
NS_ENSURE_TRUE(uuidgen, NS_ERROR_FAILURE);
|
||||
uuidgen->GenerateUUIDInPlace(&mSessionGroupingParameter);
|
||||
}
|
||||
|
||||
mState = FAILED;
|
||||
|
||||
MOZ_ASSERT(!mDisplayName.IsEmpty() || !mIconPath.IsEmpty(),
|
||||
"Should never happen ...");
|
||||
|
||||
RefPtr<IMMDeviceEnumerator> enumerator;
|
||||
hr = ::CoCreateInstance(CLSID_MMDeviceEnumerator,
|
||||
nullptr,
|
||||
CLSCTX_ALL,
|
||||
IID_IMMDeviceEnumerator,
|
||||
getter_AddRefs(enumerator));
|
||||
if (FAILED(hr))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
RefPtr<IMMDevice> device;
|
||||
hr = enumerator->GetDefaultAudioEndpoint(EDataFlow::eRender,
|
||||
ERole::eMultimedia,
|
||||
getter_AddRefs(device));
|
||||
if (FAILED(hr)) {
|
||||
if (hr == E_NOTFOUND)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<IAudioSessionManager> manager;
|
||||
hr = device->Activate(IID_IAudioSessionManager,
|
||||
CLSCTX_ALL,
|
||||
nullptr,
|
||||
getter_AddRefs(manager));
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
hr = manager->GetAudioSessionControl(&GUID_NULL,
|
||||
0,
|
||||
getter_AddRefs(mAudioSessionControl));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
hr = mAudioSessionControl->SetGroupingParam((LPGUID)&mSessionGroupingParameter,
|
||||
nullptr);
|
||||
if (FAILED(hr)) {
|
||||
StopInternal();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
hr = mAudioSessionControl->SetDisplayName(mDisplayName.get(), nullptr);
|
||||
if (FAILED(hr)) {
|
||||
StopInternal();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
hr = mAudioSessionControl->SetIconPath(mIconPath.get(), nullptr);
|
||||
if (FAILED(hr)) {
|
||||
StopInternal();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Increments refcount of 'this'.
|
||||
hr = mAudioSessionControl->RegisterAudioSessionNotification(this);
|
||||
if (FAILED(hr)) {
|
||||
StopInternal();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mState = STARTED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
AudioSession::StopInternal()
|
||||
{
|
||||
if (mAudioSessionControl &&
|
||||
(mState == STARTED || mState == STOPPED)) {
|
||||
// Decrement refcount of 'this'
|
||||
mAudioSessionControl->UnregisterAudioSessionNotification(this);
|
||||
}
|
||||
mAudioSessionControl = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioSession::Stop()
|
||||
{
|
||||
MOZ_ASSERT(mState == STARTED ||
|
||||
mState == UNINITIALIZED || // XXXremove this
|
||||
mState == FAILED,
|
||||
"State invariants violated");
|
||||
SessionState state = mState;
|
||||
mState = STOPPED;
|
||||
|
||||
{
|
||||
RefPtr<AudioSession> kungFuDeathGrip;
|
||||
kungFuDeathGrip.swap(sService);
|
||||
|
||||
StopInternal();
|
||||
}
|
||||
|
||||
if (state != UNINITIALIZED) {
|
||||
::CoUninitialize();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void CopynsID(nsID& lhs, const nsID& rhs)
|
||||
{
|
||||
lhs.m0 = rhs.m0;
|
||||
lhs.m1 = rhs.m1;
|
||||
lhs.m2 = rhs.m2;
|
||||
for (int i = 0; i < 8; i++ ) {
|
||||
lhs.m3[i] = rhs.m3[i];
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioSession::GetSessionData(nsID& aID,
|
||||
nsString& aSessionName,
|
||||
nsString& aIconPath)
|
||||
{
|
||||
MOZ_ASSERT(mState == FAILED ||
|
||||
mState == STARTED ||
|
||||
mState == CLONED,
|
||||
"State invariants violated");
|
||||
|
||||
CopynsID(aID, mSessionGroupingParameter);
|
||||
aSessionName = mDisplayName;
|
||||
aIconPath = mIconPath;
|
||||
|
||||
if (mState == FAILED)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioSession::SetSessionData(const nsID& aID,
|
||||
const nsString& aSessionName,
|
||||
const nsString& aIconPath)
|
||||
{
|
||||
MOZ_ASSERT(mState == UNINITIALIZED,
|
||||
"State invariants violated");
|
||||
MOZ_ASSERT(!XRE_IsParentProcess(),
|
||||
"Should never get here in a chrome process!");
|
||||
mState = CLONED;
|
||||
|
||||
CopynsID(mSessionGroupingParameter, aID);
|
||||
mDisplayName = aSessionName;
|
||||
mIconPath = aIconPath;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
AudioSession::OnChannelVolumeChanged(DWORD aChannelCount,
|
||||
float aChannelVolumeArray[],
|
||||
DWORD aChangedChannel,
|
||||
LPCGUID aContext)
|
||||
{
|
||||
return S_OK; // NOOP
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
AudioSession::OnDisplayNameChanged(LPCWSTR aDisplayName,
|
||||
LPCGUID aContext)
|
||||
{
|
||||
return S_OK; // NOOP
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
AudioSession::OnGroupingParamChanged(LPCGUID aGroupingParam,
|
||||
LPCGUID aContext)
|
||||
{
|
||||
return S_OK; // NOOP
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
AudioSession::OnIconPathChanged(LPCWSTR aIconPath,
|
||||
LPCGUID aContext)
|
||||
{
|
||||
return S_OK; // NOOP
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
AudioSession::OnSessionDisconnected(AudioSessionDisconnectReason aReason)
|
||||
{
|
||||
// Run our code asynchronously. Per MSDN we can't do anything interesting
|
||||
// in this callback.
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NewRunnableMethod(this, &AudioSession::OnSessionDisconnectedInternal);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioSession::OnSessionDisconnectedInternal()
|
||||
{
|
||||
if (!mAudioSessionControl)
|
||||
return NS_OK;
|
||||
|
||||
// When successful, UnregisterAudioSessionNotification will decrement the
|
||||
// refcount of 'this'. Start will re-increment it. In the interim,
|
||||
// we'll need to reference ourselves.
|
||||
RefPtr<AudioSession> kungFuDeathGrip(this);
|
||||
mAudioSessionControl->UnregisterAudioSessionNotification(this);
|
||||
mAudioSessionControl = nullptr;
|
||||
|
||||
mState = AUDIO_SESSION_DISCONNECTED;
|
||||
CoUninitialize();
|
||||
Start(); // If it fails there's not much we can do.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
AudioSession::OnSimpleVolumeChanged(float aVolume,
|
||||
BOOL aMute,
|
||||
LPCGUID aContext)
|
||||
{
|
||||
return S_OK; // NOOP
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
AudioSession::OnStateChanged(AudioSessionState aState)
|
||||
{
|
||||
return S_OK; // NOOP
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
30
widget/windows/AudioSession.h
Normal file
30
widget/windows/AudioSession.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- 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 "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
// Start the audio session in the current process
|
||||
nsresult StartAudioSession();
|
||||
|
||||
// Pass the information necessary to start an audio session in another process
|
||||
nsresult GetAudioSessionData(nsID& aID,
|
||||
nsString& aSessionName,
|
||||
nsString& aIconPath);
|
||||
|
||||
// Receive the information necessary to start an audio session in a non-chrome
|
||||
// process
|
||||
nsresult RecvAudioSessionData(const nsID& aID,
|
||||
const nsString& aSessionName,
|
||||
const nsString& aIconPath);
|
||||
|
||||
// Stop the audio session in the current process
|
||||
nsresult StopAudioSession();
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
78
widget/windows/CompositorWidgetChild.cpp
Normal file
78
widget/windows/CompositorWidgetChild.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- 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 "CompositorWidgetChild.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/widget/CompositorWidgetVsyncObserver.h"
|
||||
#include "nsBaseWidget.h"
|
||||
#include "VsyncDispatcher.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
CompositorWidgetChild::CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
|
||||
RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver)
|
||||
: mVsyncDispatcher(aVsyncDispatcher),
|
||||
mVsyncObserver(aVsyncObserver)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
}
|
||||
|
||||
CompositorWidgetChild::~CompositorWidgetChild()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CompositorWidgetChild::EnterPresentLock()
|
||||
{
|
||||
Unused << SendEnterPresentLock();
|
||||
}
|
||||
|
||||
void
|
||||
CompositorWidgetChild::LeavePresentLock()
|
||||
{
|
||||
Unused << SendLeavePresentLock();
|
||||
}
|
||||
|
||||
void
|
||||
CompositorWidgetChild::OnDestroyWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CompositorWidgetChild::UpdateTransparency(nsTransparencyMode aMode)
|
||||
{
|
||||
Unused << SendUpdateTransparency(static_cast<int32_t>(aMode));
|
||||
}
|
||||
|
||||
void
|
||||
CompositorWidgetChild::ClearTransparentWindow()
|
||||
{
|
||||
Unused << SendClearTransparentWindow();
|
||||
}
|
||||
|
||||
HDC
|
||||
CompositorWidgetChild::GetTransparentDC() const
|
||||
{
|
||||
// Not supported in out-of-process mode.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorWidgetChild::RecvObserveVsync()
|
||||
{
|
||||
mVsyncDispatcher->SetCompositorVsyncObserver(mVsyncObserver);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorWidgetChild::RecvUnobserveVsync()
|
||||
{
|
||||
mVsyncDispatcher->SetCompositorVsyncObserver(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
45
widget/windows/CompositorWidgetChild.h
Normal file
45
widget/windows/CompositorWidgetChild.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef widget_windows_CompositorWidgetChild_h
|
||||
#define widget_windows_CompositorWidgetChild_h
|
||||
|
||||
#include "WinCompositorWidget.h"
|
||||
#include "mozilla/widget/PCompositorWidgetChild.h"
|
||||
#include "mozilla/widget/CompositorWidgetVsyncObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
class CompositorVsyncDispatcher;
|
||||
|
||||
namespace widget {
|
||||
|
||||
class CompositorWidgetChild final
|
||||
: public PCompositorWidgetChild,
|
||||
public CompositorWidgetDelegate
|
||||
{
|
||||
public:
|
||||
CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
|
||||
RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver);
|
||||
~CompositorWidgetChild() override;
|
||||
|
||||
void EnterPresentLock() override;
|
||||
void LeavePresentLock() override;
|
||||
void OnDestroyWindow() override;
|
||||
void UpdateTransparency(nsTransparencyMode aMode) override;
|
||||
void ClearTransparentWindow() override;
|
||||
HDC GetTransparentDC() const override;
|
||||
|
||||
bool RecvObserveVsync() override;
|
||||
bool RecvUnobserveVsync() override;
|
||||
|
||||
private:
|
||||
RefPtr<CompositorVsyncDispatcher> mVsyncDispatcher;
|
||||
RefPtr<CompositorWidgetVsyncObserver> mVsyncObserver;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // widget_windows_CompositorWidgetChild_h
|
||||
81
widget/windows/CompositorWidgetParent.cpp
Normal file
81
widget/windows/CompositorWidgetParent.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- 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 "CompositorWidgetParent.h"
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
CompositorWidgetParent::CompositorWidgetParent(const CompositorWidgetInitData& aInitData)
|
||||
: WinCompositorWidget(aInitData)
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
|
||||
}
|
||||
|
||||
CompositorWidgetParent::~CompositorWidgetParent()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorWidgetParent::RecvEnterPresentLock()
|
||||
{
|
||||
EnterPresentLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorWidgetParent::RecvLeavePresentLock()
|
||||
{
|
||||
LeavePresentLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorWidgetParent::RecvUpdateTransparency(const int32_t& aMode)
|
||||
{
|
||||
UpdateTransparency(static_cast<nsTransparencyMode>(aMode));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorWidgetParent::RecvClearTransparentWindow()
|
||||
{
|
||||
ClearTransparentWindow();
|
||||
return true;
|
||||
}
|
||||
|
||||
nsIWidget*
|
||||
CompositorWidgetParent::RealWidget()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorWidgetParent::ObserveVsync(VsyncObserver* aObserver)
|
||||
{
|
||||
if (aObserver) {
|
||||
Unused << SendObserveVsync();
|
||||
} else {
|
||||
Unused << SendUnobserveVsync();
|
||||
}
|
||||
mVsyncObserver = aObserver;
|
||||
}
|
||||
|
||||
RefPtr<VsyncObserver>
|
||||
CompositorWidgetParent::GetVsyncObserver() const
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
|
||||
return mVsyncObserver;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorWidgetParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
40
widget/windows/CompositorWidgetParent.h
Normal file
40
widget/windows/CompositorWidgetParent.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef _widget_windows_WinCompositorWidget_h__
|
||||
#define _widget_windows_WinCompositorWidget_h__
|
||||
|
||||
#include "WinCompositorWidget.h"
|
||||
#include "mozilla/widget/PCompositorWidgetParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class CompositorWidgetParent final
|
||||
: public PCompositorWidgetParent,
|
||||
public WinCompositorWidget
|
||||
{
|
||||
public:
|
||||
CompositorWidgetParent(const CompositorWidgetInitData& aInitData);
|
||||
~CompositorWidgetParent() override;
|
||||
|
||||
bool RecvEnterPresentLock() override;
|
||||
bool RecvLeavePresentLock() override;
|
||||
bool RecvUpdateTransparency(const int32_t& aMode) override;
|
||||
bool RecvClearTransparentWindow() override;
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
nsIWidget* RealWidget() override;
|
||||
void ObserveVsync(VsyncObserver* aObserver) override;
|
||||
RefPtr<VsyncObserver> GetVsyncObserver() const override;
|
||||
|
||||
private:
|
||||
RefPtr<VsyncObserver> mVsyncObserver;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // _widget_windows_WinCompositorWidget_h__
|
||||
1450
widget/windows/GfxInfo.cpp
Normal file
1450
widget/windows/GfxInfo.cpp
Normal file
File diff suppressed because it is too large
Load diff
102
widget/windows/GfxInfo.h
Normal file
102
widget/windows/GfxInfo.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef __mozilla_widget_GfxInfo_h__
|
||||
#define __mozilla_widget_GfxInfo_h__
|
||||
|
||||
#include "GfxInfoBase.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class GfxInfo : public GfxInfoBase
|
||||
{
|
||||
~GfxInfo() {}
|
||||
public:
|
||||
GfxInfo();
|
||||
|
||||
// We only declare the subset of nsIGfxInfo that we actually implement. The
|
||||
// rest is brought forward from GfxInfoBase.
|
||||
NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled) override;
|
||||
NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled) override;
|
||||
NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion) override;
|
||||
NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams) override;
|
||||
NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription) override;
|
||||
NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver) override;
|
||||
NS_IMETHOD GetAdapterVendorID(nsAString & aAdapterVendorID) override;
|
||||
NS_IMETHOD GetAdapterDeviceID(nsAString & aAdapterDeviceID) override;
|
||||
NS_IMETHOD GetAdapterSubsysID(nsAString & aAdapterSubsysID) override;
|
||||
NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM) override;
|
||||
NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) override;
|
||||
NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate) override;
|
||||
NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription) override;
|
||||
NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver) override;
|
||||
NS_IMETHOD GetAdapterVendorID2(nsAString & aAdapterVendorID) override;
|
||||
NS_IMETHOD GetAdapterDeviceID2(nsAString & aAdapterDeviceID) override;
|
||||
NS_IMETHOD GetAdapterSubsysID2(nsAString & aAdapterSubsysID) override;
|
||||
NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM) override;
|
||||
NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) override;
|
||||
NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate) override;
|
||||
NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active) override;
|
||||
using GfxInfoBase::GetFeatureStatus;
|
||||
using GfxInfoBase::GetFeatureSuggestedDriverVersion;
|
||||
using GfxInfoBase::GetWebGLParameter;
|
||||
|
||||
virtual nsresult Init() override;
|
||||
|
||||
virtual uint32_t OperatingSystemVersion() override { return mWindowsVersion; }
|
||||
|
||||
nsresult FindMonitors(JSContext* cx, JS::HandleObject array) override;
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIGFXINFODEBUG
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
virtual nsresult GetFeatureStatusImpl(int32_t aFeature,
|
||||
int32_t *aStatus,
|
||||
nsAString & aSuggestedDriverVersion,
|
||||
const nsTArray<GfxDriverInfo>& aDriverInfo,
|
||||
nsACString& aFailureId,
|
||||
OperatingSystem* aOS = nullptr) override;
|
||||
virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() override;
|
||||
|
||||
void DescribeFeatures(JSContext* cx, JS::Handle<JSObject*> aOut) override;
|
||||
|
||||
private:
|
||||
|
||||
void AddCrashReportAnnotations();
|
||||
|
||||
nsString mDeviceString;
|
||||
nsString mDeviceID;
|
||||
nsString mDriverVersion;
|
||||
nsString mDriverDate;
|
||||
nsString mDeviceKey;
|
||||
nsString mDeviceKeyDebug;
|
||||
nsString mAdapterVendorID;
|
||||
nsString mAdapterDeviceID;
|
||||
nsString mAdapterSubsysID;
|
||||
nsString mDeviceString2;
|
||||
nsString mDriverVersion2;
|
||||
nsString mDeviceID2;
|
||||
nsString mDriverDate2;
|
||||
nsString mDeviceKey2;
|
||||
nsString mAdapterVendorID2;
|
||||
nsString mAdapterDeviceID2;
|
||||
nsString mAdapterSubsysID2;
|
||||
uint32_t mWindowsVersion;
|
||||
bool mHasDualGPU;
|
||||
bool mIsGPU2Active;
|
||||
bool mHasDriverVersionMismatch;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __mozilla_widget_GfxInfo_h__ */
|
||||
173
widget/windows/IEnumFE.cpp
Normal file
173
widget/windows/IEnumFE.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/* -*- 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 "IEnumFE.h"
|
||||
#include "nsAlgorithm.h"
|
||||
#include <algorithm>
|
||||
|
||||
CEnumFormatEtc::CEnumFormatEtc() :
|
||||
mRefCnt(0),
|
||||
mCurrentIdx(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Constructor used by Clone()
|
||||
CEnumFormatEtc::CEnumFormatEtc(nsTArray<FormatEtc>& aArray) :
|
||||
mRefCnt(0),
|
||||
mCurrentIdx(0)
|
||||
{
|
||||
// a deep copy, calls FormatEtc's copy constructor on each
|
||||
mFormatList.AppendElements(aArray);
|
||||
}
|
||||
|
||||
CEnumFormatEtc::~CEnumFormatEtc()
|
||||
{
|
||||
}
|
||||
|
||||
/* IUnknown impl. */
|
||||
|
||||
STDMETHODIMP
|
||||
CEnumFormatEtc::QueryInterface(REFIID riid, LPVOID *ppv)
|
||||
{
|
||||
*ppv = nullptr;
|
||||
|
||||
if (IsEqualIID(riid, IID_IUnknown) ||
|
||||
IsEqualIID(riid, IID_IEnumFORMATETC))
|
||||
*ppv = (LPVOID)this;
|
||||
|
||||
if (*ppv == nullptr)
|
||||
return E_NOINTERFACE;
|
||||
|
||||
// AddRef any interface we'll return.
|
||||
((LPUNKNOWN)*ppv)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CEnumFormatEtc::AddRef()
|
||||
{
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "CEnumFormatEtc",sizeof(*this));
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CEnumFormatEtc::Release()
|
||||
{
|
||||
uint32_t refReturn;
|
||||
|
||||
refReturn = --mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "CEnumFormatEtc");
|
||||
|
||||
if (mRefCnt == 0)
|
||||
delete this;
|
||||
|
||||
return refReturn;
|
||||
}
|
||||
|
||||
/* IEnumFORMATETC impl. */
|
||||
|
||||
STDMETHODIMP
|
||||
CEnumFormatEtc::Next(ULONG aMaxToFetch, FORMATETC *aResult, ULONG *aNumFetched)
|
||||
{
|
||||
// If the method retrieves the number of items requested, the return
|
||||
// value is S_OK. Otherwise, it is S_FALSE.
|
||||
|
||||
if (aNumFetched)
|
||||
*aNumFetched = 0;
|
||||
|
||||
// aNumFetched can be null if aMaxToFetch is 1
|
||||
if (!aNumFetched && aMaxToFetch > 1)
|
||||
return S_FALSE;
|
||||
|
||||
if (!aResult)
|
||||
return S_FALSE;
|
||||
|
||||
// We're done walking the list
|
||||
if (mCurrentIdx >= mFormatList.Length())
|
||||
return S_FALSE;
|
||||
|
||||
uint32_t left = mFormatList.Length() - mCurrentIdx;
|
||||
|
||||
if (!aMaxToFetch)
|
||||
return S_FALSE;
|
||||
|
||||
uint32_t count = std::min(static_cast<uint32_t>(aMaxToFetch), left);
|
||||
|
||||
uint32_t idx = 0;
|
||||
while (count > 0) {
|
||||
// Copy out to aResult
|
||||
mFormatList[mCurrentIdx++].CopyOut(&aResult[idx++]);
|
||||
count--;
|
||||
}
|
||||
|
||||
if (aNumFetched)
|
||||
*aNumFetched = idx;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CEnumFormatEtc::Skip(ULONG aSkipNum)
|
||||
{
|
||||
// If the method skips the number of items requested, the return value is S_OK.
|
||||
// Otherwise, it is S_FALSE.
|
||||
|
||||
if ((mCurrentIdx + aSkipNum) >= mFormatList.Length())
|
||||
return S_FALSE;
|
||||
|
||||
mCurrentIdx += aSkipNum;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CEnumFormatEtc::Reset(void)
|
||||
{
|
||||
mCurrentIdx = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CEnumFormatEtc::Clone(LPENUMFORMATETC *aResult)
|
||||
{
|
||||
// Must return a new IEnumFORMATETC interface with the same iterative state.
|
||||
|
||||
if (!aResult)
|
||||
return E_INVALIDARG;
|
||||
|
||||
CEnumFormatEtc * pEnumObj = new CEnumFormatEtc(mFormatList);
|
||||
|
||||
if (!pEnumObj)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
pEnumObj->AddRef();
|
||||
pEnumObj->SetIndex(mCurrentIdx);
|
||||
|
||||
*aResult = pEnumObj;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* utils */
|
||||
|
||||
void
|
||||
CEnumFormatEtc::AddFormatEtc(LPFORMATETC aFormat)
|
||||
{
|
||||
if (!aFormat)
|
||||
return;
|
||||
FormatEtc * etc = mFormatList.AppendElement();
|
||||
// Make a copy of aFormat
|
||||
if (etc)
|
||||
etc->CopyIn(aFormat);
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
void
|
||||
CEnumFormatEtc::SetIndex(uint32_t aIdx)
|
||||
{
|
||||
mCurrentIdx = aIdx;
|
||||
}
|
||||
90
widget/windows/IEnumFE.h
Normal file
90
widget/windows/IEnumFE.h
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef IEnumeFE_h__
|
||||
#define IEnumeFE_h__
|
||||
|
||||
/*
|
||||
* CEnumFormatEtc - implements IEnumFORMATETC
|
||||
*/
|
||||
|
||||
#include <ole2.h>
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
// FORMATETC container
|
||||
class FormatEtc
|
||||
{
|
||||
public:
|
||||
FormatEtc() { memset(&mFormat, 0, sizeof(FORMATETC)); }
|
||||
FormatEtc(const FormatEtc& copy) { CopyIn(©.mFormat); }
|
||||
~FormatEtc() { if (mFormat.ptd) CoTaskMemFree(mFormat.ptd); }
|
||||
|
||||
void CopyIn(const FORMATETC *aSrc) {
|
||||
if (!aSrc) {
|
||||
memset(&mFormat, 0, sizeof(FORMATETC));
|
||||
return;
|
||||
}
|
||||
mFormat = *aSrc;
|
||||
if (aSrc->ptd) {
|
||||
mFormat.ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
|
||||
*(mFormat.ptd) = *(aSrc->ptd);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyOut(LPFORMATETC aDest) {
|
||||
if (!aDest)
|
||||
return;
|
||||
*aDest = mFormat;
|
||||
if (mFormat.ptd) {
|
||||
aDest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
|
||||
*(aDest->ptd) = *(mFormat.ptd);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FORMATETC mFormat;
|
||||
};
|
||||
|
||||
/*
|
||||
* CEnumFormatEtc is created within IDataObject::EnumFormatEtc. This object lives
|
||||
* on its own, that is, QueryInterface only knows IUnknown and IEnumFormatEtc,
|
||||
* nothing more. We still use an outer unknown for reference counting, because as
|
||||
* long as this enumerator lives, the data object should live, thereby keeping the
|
||||
* application up.
|
||||
*/
|
||||
|
||||
class CEnumFormatEtc final : public IEnumFORMATETC
|
||||
{
|
||||
public:
|
||||
CEnumFormatEtc(nsTArray<FormatEtc>& aArray);
|
||||
CEnumFormatEtc();
|
||||
~CEnumFormatEtc();
|
||||
|
||||
// IUnknown impl.
|
||||
STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv);
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IEnumFORMATETC impl.
|
||||
STDMETHODIMP Next(ULONG aMaxToFetch, FORMATETC *aResult, ULONG *aNumFetched);
|
||||
STDMETHODIMP Skip(ULONG aSkipNum);
|
||||
STDMETHODIMP Reset();
|
||||
STDMETHODIMP Clone(LPENUMFORMATETC *aResult); // Addrefs
|
||||
|
||||
// Utils
|
||||
void AddFormatEtc(LPFORMATETC aFormat);
|
||||
|
||||
private:
|
||||
nsTArray<FormatEtc> mFormatList; // Formats
|
||||
ULONG mRefCnt; // Object reference count
|
||||
ULONG mCurrentIdx; // Current element
|
||||
|
||||
void SetIndex(uint32_t aIdx);
|
||||
};
|
||||
|
||||
|
||||
#endif //_IENUMFE_H_
|
||||
2910
widget/windows/IMMHandler.cpp
Normal file
2910
widget/windows/IMMHandler.cpp
Normal file
File diff suppressed because it is too large
Load diff
495
widget/windows/IMMHandler.h
Normal file
495
widget/windows/IMMHandler.h
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef IMMHandler_h_
|
||||
#define IMMHandler_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include <windows.h>
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
#include "nsRect.h"
|
||||
#include "WritingModes.h"
|
||||
#include "npapi.h"
|
||||
|
||||
class nsWindow;
|
||||
class nsWindowBase;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
struct MSGResult;
|
||||
|
||||
class IMEContext final
|
||||
{
|
||||
public:
|
||||
IMEContext()
|
||||
: mWnd(nullptr)
|
||||
, mIMC(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
explicit IMEContext(HWND aWnd);
|
||||
explicit IMEContext(nsWindowBase* aWindowBase);
|
||||
|
||||
~IMEContext()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
HIMC get() const
|
||||
{
|
||||
return mIMC;
|
||||
}
|
||||
|
||||
void Init(HWND aWnd);
|
||||
void Init(nsWindowBase* aWindowBase);
|
||||
void Clear();
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return !!mIMC;
|
||||
}
|
||||
|
||||
void SetOpenState(bool aOpen) const
|
||||
{
|
||||
if (!mIMC) {
|
||||
return;
|
||||
}
|
||||
::ImmSetOpenStatus(mIMC, aOpen);
|
||||
}
|
||||
|
||||
bool GetOpenState() const
|
||||
{
|
||||
if (!mIMC) {
|
||||
return false;
|
||||
}
|
||||
return (::ImmGetOpenStatus(mIMC) != FALSE);
|
||||
}
|
||||
|
||||
bool AssociateDefaultContext()
|
||||
{
|
||||
// We assume that there is only default IMC, no new IMC has been created.
|
||||
if (mIMC) {
|
||||
return false;
|
||||
}
|
||||
if (!::ImmAssociateContextEx(mWnd, nullptr, IACE_DEFAULT)) {
|
||||
return false;
|
||||
}
|
||||
mIMC = ::ImmGetContext(mWnd);
|
||||
return (mIMC != nullptr);
|
||||
}
|
||||
|
||||
bool Disassociate()
|
||||
{
|
||||
if (!mIMC) {
|
||||
return false;
|
||||
}
|
||||
if (!::ImmAssociateContextEx(mWnd, nullptr, 0)) {
|
||||
return false;
|
||||
}
|
||||
::ImmReleaseContext(mWnd, mIMC);
|
||||
mIMC = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
IMEContext(const IMEContext& aOther)
|
||||
{
|
||||
MOZ_CRASH("Don't copy IMEContext");
|
||||
}
|
||||
|
||||
HWND mWnd;
|
||||
HIMC mIMC;
|
||||
};
|
||||
|
||||
class IMMHandler final
|
||||
{
|
||||
public:
|
||||
static void Initialize();
|
||||
static void Terminate();
|
||||
|
||||
// If Process*() returns true, the caller shouldn't do anything anymore.
|
||||
static bool ProcessMessage(nsWindow* aWindow, UINT msg,
|
||||
WPARAM& wParam, LPARAM& lParam,
|
||||
MSGResult& aResult);
|
||||
static bool IsComposing()
|
||||
{
|
||||
return IsComposingOnOurEditor();
|
||||
}
|
||||
static bool IsComposingOn(nsWindow* aWindow)
|
||||
{
|
||||
return IsComposing() && IsComposingWindow(aWindow);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* IsIMEAvailable() returns TRUE when current keyboard layout has IME.
|
||||
* Otherwise, FALSE.
|
||||
*/
|
||||
static bool IsIMEAvailable() { return !!::ImmIsIME(::GetKeyboardLayout(0)); }
|
||||
#endif
|
||||
|
||||
// If aForce is TRUE, these methods doesn't check whether we have composition
|
||||
// or not. If you don't set it to TRUE, these method doesn't commit/cancel
|
||||
// the composition on uexpected window.
|
||||
static void CommitComposition(nsWindow* aWindow, bool aForce = false);
|
||||
static void CancelComposition(nsWindow* aWindow, bool aForce = false);
|
||||
static void OnFocusChange(bool aFocus, nsWindow* aWindow);
|
||||
static void OnUpdateComposition(nsWindow* aWindow);
|
||||
static void OnSelectionChange(nsWindow* aWindow,
|
||||
const IMENotification& aIMENotification,
|
||||
bool aIsIMMActive);
|
||||
|
||||
static nsIMEUpdatePreference GetIMEUpdatePreference();
|
||||
|
||||
// Returns NS_SUCCESS_EVENT_CONSUMED if the mouse button event is consumed by
|
||||
// IME. Otherwise, NS_OK.
|
||||
static nsresult OnMouseButtonEvent(nsWindow* aWindow,
|
||||
const IMENotification& aIMENotification);
|
||||
static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
|
||||
static void DefaultProcOfPluginEvent(nsWindow* aWindow,
|
||||
const NPEvent* aEvent);
|
||||
|
||||
protected:
|
||||
static void EnsureHandlerInstance();
|
||||
|
||||
static bool IsComposingOnOurEditor();
|
||||
static bool IsComposingOnPlugin();
|
||||
static bool IsComposingWindow(nsWindow* aWindow);
|
||||
|
||||
static bool IsJapanist2003Active();
|
||||
static bool IsGoogleJapaneseInputActive();
|
||||
|
||||
static bool ShouldDrawCompositionStringOurselves();
|
||||
static bool IsVerticalWritingSupported();
|
||||
// aWindow can be nullptr if it's called without receiving WM_INPUTLANGCHANGE.
|
||||
static void InitKeyboardLayout(nsWindow* aWindow, HKL aKeyboardLayout);
|
||||
static UINT GetKeyboardCodePage();
|
||||
|
||||
/**
|
||||
* Checks whether the window is top level window of the composing window.
|
||||
* In this method, the top level window means in all windows, not only in all
|
||||
* OUR windows. I.e., if the aWindow is embedded, this always returns FALSE.
|
||||
*/
|
||||
static bool IsTopLevelWindowOfComposition(nsWindow* aWindow);
|
||||
|
||||
static bool ProcessInputLangChangeMessage(nsWindow* aWindow,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
static bool ProcessMessageForPlugin(nsWindow* aWindow, UINT msg,
|
||||
WPARAM &wParam, LPARAM &lParam,
|
||||
bool &aRet, MSGResult& aResult);
|
||||
|
||||
IMMHandler();
|
||||
~IMMHandler();
|
||||
|
||||
// On*() methods return true if the caller of message handler shouldn't do
|
||||
// anything anymore. Otherwise, false.
|
||||
static bool OnKeyDownEvent(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
|
||||
bool OnIMEStartComposition(nsWindow* aWindow, MSGResult& aResult);
|
||||
void OnIMEStartCompositionOnPlugin(nsWindow* aWindow,
|
||||
WPARAM wParam, LPARAM lParam);
|
||||
bool OnIMEComposition(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
void OnIMECompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
bool OnIMEEndComposition(nsWindow* aWindow, MSGResult& aResult);
|
||||
void OnIMEEndCompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
bool OnIMERequest(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
bool OnIMECharOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
bool OnChar(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
bool OnCharOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
void OnInputLangChange(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
|
||||
// These message handlers don't use instance members, we should not create
|
||||
// the instance by the messages. So, they should be static.
|
||||
static bool OnIMEChar(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
static bool OnIMESetContext(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
static bool OnIMESetContextOnPlugin(nsWindow* aWindow,
|
||||
WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
static bool OnIMECompositionFull(nsWindow* aWindow, MSGResult& aResult);
|
||||
static bool OnIMENotify(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
static bool OnIMESelect(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
|
||||
// The result of Handle* method mean "Processed" when it's TRUE.
|
||||
void HandleStartComposition(nsWindow* aWindow,
|
||||
const IMEContext& aContext);
|
||||
bool HandleComposition(nsWindow* aWindow,
|
||||
const IMEContext& aContext,
|
||||
LPARAM lParam);
|
||||
// If aCommitString is null, this commits composition with the latest
|
||||
// dispatched data. Otherwise, commits composition with the value.
|
||||
void HandleEndComposition(nsWindow* aWindow,
|
||||
const nsAString* aCommitString = nullptr);
|
||||
bool HandleReconvert(nsWindow* aWindow, LPARAM lParam, LRESULT *oResult);
|
||||
bool HandleQueryCharPosition(nsWindow* aWindow, LPARAM lParam,
|
||||
LRESULT *oResult);
|
||||
bool HandleDocumentFeed(nsWindow* aWindow, LPARAM lParam, LRESULT *oResult);
|
||||
|
||||
/**
|
||||
* When a window's IME context is activating but we have composition on
|
||||
* another window, we should commit our composition because IME context is
|
||||
* shared by all our windows (including plug-ins).
|
||||
* @param aWindow is a new activated window.
|
||||
* If aWindow is our composing window, this method does nothing.
|
||||
* Otherwise, this commits the composition on the previous window.
|
||||
* If this method did commit a composition, this returns TRUE.
|
||||
*/
|
||||
bool CommitCompositionOnPreviousWindow(nsWindow* aWindow);
|
||||
|
||||
/**
|
||||
* ResolveIMECaretPos
|
||||
* Convert the caret rect of a composition event to another widget's
|
||||
* coordinate system.
|
||||
*
|
||||
* @param aReferenceWidget The origin widget of aCursorRect.
|
||||
* Typically, this is mReferenceWidget of the
|
||||
* composing events. If the aCursorRect is in screen
|
||||
* coordinates, set nullptr.
|
||||
* @param aCursorRect The cursor rect.
|
||||
* @param aNewOriginWidget aOutRect will be in this widget's coordinates. If
|
||||
* this is nullptr, aOutRect will be in screen
|
||||
* coordinates.
|
||||
* @param aOutRect The converted cursor rect.
|
||||
*/
|
||||
void ResolveIMECaretPos(nsIWidget* aReferenceWidget,
|
||||
mozilla::LayoutDeviceIntRect& aCursorRect,
|
||||
nsIWidget* aNewOriginWidget,
|
||||
mozilla::LayoutDeviceIntRect& aOutRect);
|
||||
|
||||
bool ConvertToANSIString(const nsAFlatString& aStr,
|
||||
UINT aCodePage,
|
||||
nsACString& aANSIStr);
|
||||
|
||||
bool SetIMERelatedWindowsPos(nsWindow* aWindow,
|
||||
const IMEContext& aContext);
|
||||
void SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
|
||||
const IMEContext& aContext);
|
||||
/**
|
||||
* GetCharacterRectOfSelectedTextAt() returns character rect of the offset
|
||||
* from the selection start or the start of composition string if there is
|
||||
* a composition.
|
||||
*
|
||||
* @param aWindow The window which has focus.
|
||||
* @param aOffset Offset from the selection start or the start of
|
||||
* composition string when there is a composition.
|
||||
* This must be in the selection range or
|
||||
* the composition string.
|
||||
* @param aCharRect The result.
|
||||
* @param aWritingMode The writing mode of current selection. When this
|
||||
* is nullptr, this assumes that the selection is in
|
||||
* horizontal writing mode.
|
||||
* @return true if this succeeded to retrieve the rect.
|
||||
* Otherwise, false.
|
||||
*/
|
||||
bool GetCharacterRectOfSelectedTextAt(
|
||||
nsWindow* aWindow,
|
||||
uint32_t aOffset,
|
||||
mozilla::LayoutDeviceIntRect& aCharRect,
|
||||
mozilla::WritingMode* aWritingMode = nullptr);
|
||||
/**
|
||||
* GetCaretRect() returns caret rect at current selection start.
|
||||
*
|
||||
* @param aWindow The window which has focus.
|
||||
* @param aCaretRect The result.
|
||||
* @param aWritingMode The writing mode of current selection. When this
|
||||
* is nullptr, this assumes that the selection is in
|
||||
* horizontal writing mode.
|
||||
* @return true if this succeeded to retrieve the rect.
|
||||
* Otherwise, false.
|
||||
*/
|
||||
bool GetCaretRect(nsWindow* aWindow,
|
||||
mozilla::LayoutDeviceIntRect& aCaretRect,
|
||||
mozilla::WritingMode* aWritingMode = nullptr);
|
||||
void GetCompositionString(const IMEContext& aContext,
|
||||
DWORD aIndex,
|
||||
nsAString& aCompositionString) const;
|
||||
|
||||
/**
|
||||
* AdjustCompositionFont() makes IME vertical writing mode if it's supported.
|
||||
* If aForceUpdate is true, it will update composition font even if writing
|
||||
* mode isn't being changed.
|
||||
*/
|
||||
void AdjustCompositionFont(nsWindow* aWindow,
|
||||
const IMEContext& aContext,
|
||||
const mozilla::WritingMode& aWritingMode,
|
||||
bool aForceUpdate = false);
|
||||
|
||||
/**
|
||||
* MaybeAdjustCompositionFont() calls AdjustCompositionFont() when the
|
||||
* locale of active IME is CJK. Note that this creates an instance even
|
||||
* when there is no composition but the locale is CJK.
|
||||
*/
|
||||
static void MaybeAdjustCompositionFont(
|
||||
nsWindow* aWindow,
|
||||
const mozilla::WritingMode& aWritingMode,
|
||||
bool aForceUpdate = false);
|
||||
|
||||
/**
|
||||
* Get the current target clause of composition string.
|
||||
* If there are one or more characters whose attribute is ATTR_TARGET_*,
|
||||
* this returns the first character's offset and its length.
|
||||
* Otherwise, e.g., the all characters are ATTR_INPUT, this returns
|
||||
* the composition string range because the all is the current target.
|
||||
*
|
||||
* aLength can be null (default), but aOffset must not be null.
|
||||
*
|
||||
* The aOffset value is offset in the contents. So, when you need offset
|
||||
* in the composition string, you need to subtract mCompositionStart from it.
|
||||
*/
|
||||
bool GetTargetClauseRange(uint32_t *aOffset, uint32_t *aLength = nullptr);
|
||||
|
||||
/**
|
||||
* DispatchEvent() dispatches aEvent if aWidget hasn't been destroyed yet.
|
||||
*/
|
||||
static void DispatchEvent(nsWindow* aWindow, WidgetGUIEvent& aEvent);
|
||||
|
||||
/**
|
||||
* DispatchCompositionChangeEvent() dispatches eCompositionChange event
|
||||
* with clause information (it'll be retrieved by CreateTextRangeArray()).
|
||||
* I.e., this should be called only during composing. If a composition is
|
||||
* being committed, only HandleCompositionEnd() should be called.
|
||||
*
|
||||
* @param aWindow The window which has the composition.
|
||||
* @param aContext Native IME context which has the composition.
|
||||
*/
|
||||
void DispatchCompositionChangeEvent(nsWindow* aWindow,
|
||||
const IMEContext& aContext);
|
||||
|
||||
nsresult EnsureClauseArray(int32_t aCount);
|
||||
nsresult EnsureAttributeArray(int32_t aCount);
|
||||
|
||||
/**
|
||||
* When WM_IME_CHAR is received and passed to DefWindowProc, we need to
|
||||
* record the messages. In other words, we should record the messages
|
||||
* when we receive WM_IME_CHAR on windowless plug-in (if we have focus,
|
||||
* we always eat them). When focus is moved from a windowless plug-in to
|
||||
* our window during composition, WM_IME_CHAR messages were received when
|
||||
* the plug-in has focus. However, WM_CHAR messages are received after the
|
||||
* plug-in lost focus. So, we need to ignore the WM_CHAR messages because
|
||||
* they make unexpected text input events on us.
|
||||
*/
|
||||
nsTArray<MSG> mPassedIMEChar;
|
||||
|
||||
bool IsIMECharRecordsEmpty()
|
||||
{
|
||||
return mPassedIMEChar.IsEmpty();
|
||||
}
|
||||
void ResetIMECharRecords()
|
||||
{
|
||||
mPassedIMEChar.Clear();
|
||||
}
|
||||
void DequeueIMECharRecords(WPARAM &wParam, LPARAM &lParam)
|
||||
{
|
||||
MSG msg = mPassedIMEChar.ElementAt(0);
|
||||
wParam = msg.wParam;
|
||||
lParam = msg.lParam;
|
||||
mPassedIMEChar.RemoveElementAt(0);
|
||||
}
|
||||
void EnqueueIMECharRecords(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
MSG msg;
|
||||
msg.wParam = wParam;
|
||||
msg.lParam = lParam;
|
||||
mPassedIMEChar.AppendElement(msg);
|
||||
}
|
||||
|
||||
TextEventDispatcher* GetTextEventDispatcherFor(nsWindow* aWindow);
|
||||
|
||||
nsWindow* mComposingWindow;
|
||||
RefPtr<TextEventDispatcher> mDispatcher;
|
||||
nsString mCompositionString;
|
||||
InfallibleTArray<uint32_t> mClauseArray;
|
||||
InfallibleTArray<uint8_t> mAttributeArray;
|
||||
|
||||
int32_t mCursorPosition;
|
||||
uint32_t mCompositionStart;
|
||||
|
||||
struct Selection
|
||||
{
|
||||
nsString mString;
|
||||
uint32_t mOffset;
|
||||
mozilla::WritingMode mWritingMode;
|
||||
bool mIsValid;
|
||||
|
||||
Selection()
|
||||
: mOffset(UINT32_MAX)
|
||||
, mIsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
mOffset = UINT32_MAX;
|
||||
mIsValid = false;
|
||||
}
|
||||
uint32_t Length() const { return mString.Length(); }
|
||||
bool Collapsed() const { return !Length(); }
|
||||
|
||||
bool IsValid() const;
|
||||
bool Update(const IMENotification& aIMENotification);
|
||||
bool Init(nsWindow* aWindow);
|
||||
bool EnsureValidSelection(nsWindow* aWindow);
|
||||
private:
|
||||
Selection(const Selection& aOther) = delete;
|
||||
void operator =(const Selection& aOther) = delete;
|
||||
};
|
||||
// mSelection stores the latest selection data only when sHasFocus is true.
|
||||
// Don't access mSelection directly. You should use GetSelection() for
|
||||
// getting proper state.
|
||||
Selection mSelection;
|
||||
|
||||
Selection& GetSelection()
|
||||
{
|
||||
// When IME has focus, mSelection is automatically updated by
|
||||
// NOTIFY_IME_OF_SELECTION_CHANGE.
|
||||
if (sHasFocus) {
|
||||
return mSelection;
|
||||
}
|
||||
// Otherwise, i.e., While IME doesn't have focus, we cannot observe
|
||||
// selection changes. So, in such case, we need to query selection
|
||||
// when it's necessary.
|
||||
static Selection sTempSelection;
|
||||
sTempSelection.Clear();
|
||||
return sTempSelection;
|
||||
}
|
||||
|
||||
bool mIsComposing;
|
||||
bool mIsComposingOnPlugin;
|
||||
bool mNativeCaretIsCreated;
|
||||
|
||||
static mozilla::WritingMode sWritingModeOfCompositionFont;
|
||||
static nsString sIMEName;
|
||||
static UINT sCodePage;
|
||||
static DWORD sIMEProperty;
|
||||
static DWORD sIMEUIProperty;
|
||||
static bool sAssumeVerticalWritingModeNotSupported;
|
||||
static bool sHasFocus;
|
||||
static bool sNativeCaretIsCreatedForPlugin;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // IMMHandler_h_
|
||||
41
widget/windows/InProcessWinCompositorWidget.cpp
Normal file
41
widget/windows/InProcessWinCompositorWidget.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- 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 "InProcessWinCompositorWidget.h"
|
||||
#include "nsWindow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
/* static */ RefPtr<CompositorWidget>
|
||||
CompositorWidget::CreateLocal(const CompositorWidgetInitData& aInitData, nsIWidget* aWidget)
|
||||
{
|
||||
return new InProcessWinCompositorWidget(aInitData, static_cast<nsWindow*>(aWidget));
|
||||
}
|
||||
|
||||
InProcessWinCompositorWidget::InProcessWinCompositorWidget(const CompositorWidgetInitData& aInitData,
|
||||
nsWindow* aWindow)
|
||||
: WinCompositorWidget(aInitData),
|
||||
mWindow(aWindow)
|
||||
{
|
||||
MOZ_ASSERT(mWindow);
|
||||
}
|
||||
|
||||
nsIWidget*
|
||||
InProcessWinCompositorWidget::RealWidget()
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
void
|
||||
InProcessWinCompositorWidget::ObserveVsync(VsyncObserver* aObserver)
|
||||
{
|
||||
if (RefPtr<CompositorVsyncDispatcher> cvd = mWindow->GetCompositorVsyncDispatcher()) {
|
||||
cvd->SetCompositorVsyncObserver(aObserver);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
35
widget/windows/InProcessWinCompositorWidget.h
Normal file
35
widget/windows/InProcessWinCompositorWidget.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef widget_windows_InProcessCompositorWidgetParent_h
|
||||
#define widget_windows_InProcessCompositorWidgetParent_h
|
||||
|
||||
#include "WinCompositorWidget.h"
|
||||
|
||||
class nsWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
// This is the Windows-specific implementation of CompositorWidget. For
|
||||
// the most part it only requires an HWND, however it maintains extra state
|
||||
// for transparent windows, as well as for synchronizing WM_SETTEXT messages
|
||||
// with the compositor.
|
||||
class InProcessWinCompositorWidget final : public WinCompositorWidget
|
||||
{
|
||||
public:
|
||||
InProcessWinCompositorWidget(const CompositorWidgetInitData& aInitData, nsWindow* aWindow);
|
||||
|
||||
void ObserveVsync(VsyncObserver* aObserver) override;
|
||||
nsIWidget* RealWidget() override;
|
||||
|
||||
private:
|
||||
nsWindow* mWindow;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // widget_windows_InProcessCompositorWidgetParent_h
|
||||
253
widget/windows/InkCollector.cpp
Normal file
253
widget/windows/InkCollector.cpp
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* 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 "InkCollector.h"
|
||||
|
||||
// Msinkaut_i.c and Msinkaut.h should both be included
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms695519.aspx
|
||||
#include <msinkaut_i.c>
|
||||
|
||||
StaticAutoPtr<InkCollector> InkCollector::sInkCollector;
|
||||
|
||||
InkCollector::~InkCollector()
|
||||
{
|
||||
Shutdown();
|
||||
MOZ_ASSERT(!mCookie && !mEnabled && !mComInitialized
|
||||
&& !mMarshaller && !mInkCollector
|
||||
&& !mConnectionPoint && !mInkCollectorEvent);
|
||||
}
|
||||
|
||||
void InkCollector::Initialize()
|
||||
{
|
||||
// Possibly, we can use mConnectionPoint for checking,
|
||||
// But if errors exist (perhaps COM object is unavailable),
|
||||
// Initialize() will be called more times.
|
||||
static bool sInkCollectorCreated = false;
|
||||
if (sInkCollectorCreated) {
|
||||
return;
|
||||
}
|
||||
sInkCollectorCreated = true;
|
||||
|
||||
// COM could get uninitialized due to previous initialization.
|
||||
mComInitialized = SUCCEEDED(::CoInitialize(nullptr));
|
||||
|
||||
// Set up instance of InkCollectorEvent.
|
||||
mInkCollectorEvent = new InkCollectorEvent();
|
||||
|
||||
// Set up a free threaded marshaler.
|
||||
if (FAILED(::CoCreateFreeThreadedMarshaler(mInkCollectorEvent, getter_AddRefs(mMarshaller)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the ink collector.
|
||||
if (FAILED(::CoCreateInstance(CLSID_InkCollector, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IInkCollector, getter_AddRefs(mInkCollector)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up connection between sink and InkCollector.
|
||||
RefPtr<IConnectionPointContainer> connPointContainer;
|
||||
|
||||
// Get the connection point container.
|
||||
if (SUCCEEDED(mInkCollector->QueryInterface(IID_IConnectionPointContainer,
|
||||
getter_AddRefs(connPointContainer)))) {
|
||||
|
||||
// Find the connection point for Ink Collector events.
|
||||
if (SUCCEEDED(connPointContainer->FindConnectionPoint(__uuidof(_IInkCollectorEvents),
|
||||
getter_AddRefs(mConnectionPoint)))) {
|
||||
|
||||
// Hook up sink to connection point.
|
||||
if (SUCCEEDED(mConnectionPoint->Advise(mInkCollectorEvent, &mCookie))) {
|
||||
OnInitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InkCollector::Shutdown()
|
||||
{
|
||||
Enable(false);
|
||||
if (mConnectionPoint) {
|
||||
// Remove the connection of the sink to the Ink Collector.
|
||||
mConnectionPoint->Unadvise(mCookie);
|
||||
mCookie = 0;
|
||||
mConnectionPoint = nullptr;
|
||||
}
|
||||
mInkCollector = nullptr;
|
||||
mMarshaller = nullptr;
|
||||
mInkCollectorEvent = nullptr;
|
||||
|
||||
// Let uninitialization get handled in a place where it got inited.
|
||||
if (mComInitialized) {
|
||||
CoUninitialize();
|
||||
mComInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
void InkCollector::OnInitialize()
|
||||
{
|
||||
// Suppress all events to do not allow performance decreasing.
|
||||
// https://msdn.microsoft.com/en-us/library/ms820347.aspx
|
||||
mInkCollector->SetEventInterest(InkCollectorEventInterest::ICEI_AllEvents, VARIANT_FALSE);
|
||||
|
||||
// Sets a value that indicates whether an object or control has interest in a specified event.
|
||||
mInkCollector->SetEventInterest(InkCollectorEventInterest::ICEI_CursorOutOfRange, VARIANT_TRUE);
|
||||
|
||||
// If the MousePointer property is set to IMP_Custom and the MouseIcon property is NULL,
|
||||
// Then the ink collector no longer handles mouse cursor settings.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms700686.aspx
|
||||
mInkCollector->put_MouseIcon(nullptr);
|
||||
mInkCollector->put_MousePointer(InkMousePointer::IMP_Custom);
|
||||
|
||||
// This mode allows an ink collector to collect ink from any tablet attached to the Tablet PC.
|
||||
// The Boolean value that indicates whether to use the mouse as an input device.
|
||||
// If TRUE, the mouse is used for input.
|
||||
// https://msdn.microsoft.com/en-us/library/ms820346.aspx
|
||||
mInkCollector->SetAllTabletsMode(VARIANT_FALSE);
|
||||
|
||||
// Sets the value that specifies whether ink is rendered as it is drawn.
|
||||
// VARIANT_TRUE to render ink as it is drawn on the display.
|
||||
// VARIANT_FALSE to not have the ink appear on the display as strokes are made.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd314598.aspx
|
||||
mInkCollector->put_DynamicRendering(VARIANT_FALSE);
|
||||
}
|
||||
|
||||
// Sets a value that specifies whether the InkCollector object collects pen input.
|
||||
// This property must be set to FALSE before setting or
|
||||
// calling specific properties and methods of the object.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms701721.aspx
|
||||
void InkCollector::Enable(bool aNewState)
|
||||
{
|
||||
if (aNewState != mEnabled) {
|
||||
if (mInkCollector) {
|
||||
if (SUCCEEDED(mInkCollector->put_Enabled(aNewState ? VARIANT_TRUE : VARIANT_FALSE))) {
|
||||
mEnabled = aNewState;
|
||||
} else {
|
||||
NS_WARNING("InkCollector did not change status successfully");
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("InkCollector should be exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HWND InkCollector::GetTarget()
|
||||
{
|
||||
return mTargetWindow;
|
||||
}
|
||||
|
||||
void InkCollector::SetTarget(HWND aTargetWindow)
|
||||
{
|
||||
NS_ASSERTION(aTargetWindow, "aTargetWindow should be exist");
|
||||
if (aTargetWindow && (aTargetWindow != mTargetWindow)) {
|
||||
Initialize();
|
||||
if (mInkCollector) {
|
||||
Enable(false);
|
||||
if (SUCCEEDED(mInkCollector->put_hWnd((LONG_PTR)aTargetWindow))) {
|
||||
mTargetWindow = aTargetWindow;
|
||||
} else {
|
||||
NS_WARNING("InkCollector did not change window property successfully");
|
||||
}
|
||||
Enable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InkCollector::ClearTarget()
|
||||
{
|
||||
if (mTargetWindow && mInkCollector) {
|
||||
Enable(false);
|
||||
if (SUCCEEDED(mInkCollector->put_hWnd(0))) {
|
||||
mTargetWindow = 0;
|
||||
} else {
|
||||
NS_WARNING("InkCollector did not clear window property successfully");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t InkCollector::GetPointerId()
|
||||
{
|
||||
return mPointerId;
|
||||
}
|
||||
|
||||
void InkCollector::SetPointerId(uint16_t aPointerId)
|
||||
{
|
||||
mPointerId = aPointerId;
|
||||
}
|
||||
|
||||
void InkCollector::ClearPointerId()
|
||||
{
|
||||
mPointerId = 0;
|
||||
}
|
||||
|
||||
// The display and the digitizer have quite different properties.
|
||||
// The display has CursorMustTouch, the mouse pointer alway touches the display surface.
|
||||
// The digitizer lists Integrated and HardProximity.
|
||||
// When the stylus is in the proximity of the tablet its movements are also detected.
|
||||
// An external tablet will only list HardProximity.
|
||||
bool InkCollectorEvent::IsHardProximityTablet(IInkTablet* aTablet) const
|
||||
{
|
||||
if (aTablet) {
|
||||
TabletHardwareCapabilities caps;
|
||||
if (SUCCEEDED(aTablet->get_HardwareCapabilities(&caps))) {
|
||||
return (TabletHardwareCapabilities::THWC_HardProximity & caps);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT __stdcall InkCollectorEvent::QueryInterface(REFIID aRiid, void **aObject)
|
||||
{
|
||||
// Validate the input
|
||||
if (!aObject) {
|
||||
return E_POINTER;
|
||||
}
|
||||
HRESULT result = E_NOINTERFACE;
|
||||
// This object supports IUnknown/IDispatch/IInkCollectorEvents
|
||||
if ((IID_IUnknown == aRiid) ||
|
||||
(IID_IDispatch == aRiid) ||
|
||||
(DIID__IInkCollectorEvents == aRiid)) {
|
||||
*aObject = this;
|
||||
// AddRef should be called when we give info about interface
|
||||
NS_ADDREF_THIS();
|
||||
result = S_OK;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT InkCollectorEvent::Invoke(DISPID aDispIdMember, REFIID /*aRiid*/,
|
||||
LCID /*aId*/, WORD /*wFlags*/,
|
||||
DISPPARAMS* aDispParams, VARIANT* /*aVarResult*/,
|
||||
EXCEPINFO* /*aExcepInfo*/, UINT* /*aArgErr*/)
|
||||
{
|
||||
switch (aDispIdMember) {
|
||||
case DISPID_ICECursorOutOfRange: {
|
||||
if (aDispParams && aDispParams->cArgs) {
|
||||
CursorOutOfRange(static_cast<IInkCursor*>(aDispParams->rgvarg[0].pdispVal));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void InkCollectorEvent::CursorOutOfRange(IInkCursor* aCursor) const
|
||||
{
|
||||
IInkTablet* curTablet = nullptr;
|
||||
if (FAILED(aCursor->get_Tablet(&curTablet))) {
|
||||
return;
|
||||
}
|
||||
// All events should be suppressed except
|
||||
// from tablets with hard proximity.
|
||||
if (!IsHardProximityTablet(curTablet)) {
|
||||
return;
|
||||
}
|
||||
// Notify current target window.
|
||||
if (HWND targetWindow = InkCollector::sInkCollector->GetTarget()) {
|
||||
::SendMessage(targetWindow, MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER, 0, 0);
|
||||
}
|
||||
}
|
||||
98
widget/windows/InkCollector.h
Normal file
98
widget/windows/InkCollector.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
#ifndef InkCollector_h__
|
||||
#define InkCollector_h__
|
||||
|
||||
#include <msinkaut.h>
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
#define MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER WM_USER + 0x83
|
||||
|
||||
class InkCollectorEvent : public _IInkCollectorEvents
|
||||
{
|
||||
public:
|
||||
// IUnknown
|
||||
HRESULT __stdcall QueryInterface(REFIID aRiid, void **aObject);
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef() { return ++mRefCount; }
|
||||
virtual ULONG STDMETHODCALLTYPE Release()
|
||||
{
|
||||
MOZ_ASSERT(mRefCount);
|
||||
if (!--mRefCount) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRefCount;
|
||||
}
|
||||
|
||||
protected:
|
||||
// IDispatch
|
||||
STDMETHOD(GetTypeInfoCount)(UINT* aInfo) { return E_NOTIMPL; }
|
||||
STDMETHOD(GetTypeInfo)(UINT aInfo, LCID aId, ITypeInfo** aTInfo) { return E_NOTIMPL; }
|
||||
STDMETHOD(GetIDsOfNames)(REFIID aRiid, LPOLESTR* aStrNames, UINT aNames,
|
||||
LCID aId, DISPID* aDispId) { return E_NOTIMPL; }
|
||||
STDMETHOD(Invoke)(DISPID aDispIdMember, REFIID aRiid,
|
||||
LCID aId, WORD wFlags,
|
||||
DISPPARAMS* aDispParams, VARIANT* aVarResult,
|
||||
EXCEPINFO* aExcepInfo, UINT* aArgErr);
|
||||
|
||||
// InkCollectorEvent
|
||||
void CursorOutOfRange(IInkCursor* aCursor) const;
|
||||
bool IsHardProximityTablet(IInkTablet* aTablet) const;
|
||||
|
||||
private:
|
||||
uint32_t mRefCount = 0;
|
||||
};
|
||||
|
||||
class InkCollector
|
||||
{
|
||||
public:
|
||||
~InkCollector();
|
||||
void Shutdown();
|
||||
|
||||
HWND GetTarget();
|
||||
void SetTarget(HWND aTargetWindow);
|
||||
void ClearTarget();
|
||||
|
||||
uint16_t GetPointerId(); // 0 shows that there is no existing pen.
|
||||
void SetPointerId(uint16_t aPointerId);
|
||||
void ClearPointerId();
|
||||
|
||||
static StaticAutoPtr<InkCollector> sInkCollector;
|
||||
|
||||
protected:
|
||||
void Initialize();
|
||||
void OnInitialize();
|
||||
void Enable(bool aNewState);
|
||||
|
||||
private:
|
||||
RefPtr<IUnknown> mMarshaller;
|
||||
RefPtr<IInkCollector> mInkCollector;
|
||||
RefPtr<IConnectionPoint> mConnectionPoint;
|
||||
RefPtr<InkCollectorEvent> mInkCollectorEvent;
|
||||
|
||||
HWND mTargetWindow = 0;
|
||||
DWORD mCookie = 0;
|
||||
bool mComInitialized = false;
|
||||
bool mEnabled = false;
|
||||
|
||||
// This value holds the previous pointerId of the pen, and is used by the
|
||||
// nsWindow when processing a MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER which
|
||||
// indicates that a pen leaves the digitizer.
|
||||
|
||||
// TODO: If we move our implementation to window pointer input messages, then
|
||||
// we no longer need this value, since the pointerId can be retrieved from the
|
||||
// window message, please refer to
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/hh454916(v=vs.85).aspx
|
||||
|
||||
// NOTE: The pointerId of a pen shouldn't be 0 on a Windows platform, since 0
|
||||
// is reserved of the mouse, please refer to
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320(v=vs.85).aspx
|
||||
uint16_t mPointerId = 0;
|
||||
};
|
||||
|
||||
#endif // InkCollector_h__
|
||||
542
widget/windows/JumpListBuilder.cpp
Normal file
542
widget/windows/JumpListBuilder.cpp
Normal file
|
|
@ -0,0 +1,542 @@
|
|||
/* -*- 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 "JumpListBuilder.h"
|
||||
|
||||
#include "nsError.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "WinTaskbar.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
#include "WinUtils.h"
|
||||
|
||||
// The amount of time, in milliseconds, that our IO thread will stay alive after the last event it processes.
|
||||
#define DEFAULT_THREAD_TIMEOUT_MS 30000
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
static NS_DEFINE_CID(kJumpListItemCID, NS_WIN_JUMPLISTITEM_CID);
|
||||
static NS_DEFINE_CID(kJumpListLinkCID, NS_WIN_JUMPLISTLINK_CID);
|
||||
static NS_DEFINE_CID(kJumpListShortcutCID, NS_WIN_JUMPLISTSHORTCUT_CID);
|
||||
|
||||
// defined in WinTaskbar.cpp
|
||||
extern const wchar_t *gMozillaJumpListIDGeneric;
|
||||
|
||||
bool JumpListBuilder::sBuildingList = false;
|
||||
const char kPrefTaskbarEnabled[] = "browser.taskbar.lists.enabled";
|
||||
|
||||
NS_IMPL_ISUPPORTS(JumpListBuilder, nsIJumpListBuilder, nsIObserver)
|
||||
#define TOPIC_PROFILE_BEFORE_CHANGE "profile-before-change"
|
||||
#define TOPIC_CLEAR_PRIVATE_DATA "clear-private-data"
|
||||
|
||||
JumpListBuilder::JumpListBuilder() :
|
||||
mMaxItems(0),
|
||||
mHasCommit(false)
|
||||
{
|
||||
::CoInitialize(nullptr);
|
||||
|
||||
CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_ICustomDestinationList, getter_AddRefs(mJumpListMgr));
|
||||
|
||||
// Make a lazy thread for any IO
|
||||
mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
|
||||
NS_LITERAL_CSTRING("Jump List"),
|
||||
LazyIdleThread::ManualShutdown);
|
||||
Preferences::AddStrongObserver(this, kPrefTaskbarEnabled);
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this, TOPIC_PROFILE_BEFORE_CHANGE, false);
|
||||
observerService->AddObserver(this, TOPIC_CLEAR_PRIVATE_DATA, false);
|
||||
}
|
||||
}
|
||||
|
||||
JumpListBuilder::~JumpListBuilder()
|
||||
{
|
||||
Preferences::RemoveObserver(this, kPrefTaskbarEnabled);
|
||||
mJumpListMgr = nullptr;
|
||||
::CoUninitialize();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::GetAvailable(int16_t *aAvailable)
|
||||
{
|
||||
*aAvailable = false;
|
||||
|
||||
if (mJumpListMgr)
|
||||
*aAvailable = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::GetIsListCommitted(bool *aCommit)
|
||||
{
|
||||
*aCommit = mHasCommit;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::GetMaxListItems(int16_t *aMaxItems)
|
||||
{
|
||||
if (!mJumpListMgr)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
*aMaxItems = 0;
|
||||
|
||||
if (sBuildingList) {
|
||||
*aMaxItems = mMaxItems;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IObjectArray *objArray;
|
||||
if (SUCCEEDED(mJumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) {
|
||||
*aMaxItems = mMaxItems;
|
||||
|
||||
if (objArray)
|
||||
objArray->Release();
|
||||
|
||||
mJumpListMgr->AbortList();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::InitListBuild(nsIMutableArray *removedItems, bool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(removedItems);
|
||||
|
||||
*_retval = false;
|
||||
|
||||
if (!mJumpListMgr)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if(sBuildingList)
|
||||
AbortListBuild();
|
||||
|
||||
IObjectArray *objArray;
|
||||
|
||||
// The returned objArray of removed items are for manually removed items.
|
||||
// This does not return items which are removed because they were previously
|
||||
// part of the jump list but are no longer part of the jump list.
|
||||
if (SUCCEEDED(mJumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) {
|
||||
if (objArray) {
|
||||
TransferIObjectArrayToIMutableArray(objArray, removedItems);
|
||||
objArray->Release();
|
||||
}
|
||||
|
||||
RemoveIconCacheForItems(removedItems);
|
||||
|
||||
sBuildingList = true;
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Ensures that we don't have old ICO files that aren't in our jump lists
|
||||
// anymore left over in the cache.
|
||||
nsresult JumpListBuilder::RemoveIconCacheForItems(nsIMutableArray *items)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(items);
|
||||
|
||||
nsresult rv;
|
||||
uint32_t length;
|
||||
items->GetLength(&length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
|
||||
//Obtain an IJumpListItem and get the type
|
||||
nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
int16_t type;
|
||||
if (NS_FAILED(item->GetType(&type))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the item is a shortcut, remove its associated icon if any
|
||||
if (type == nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT) {
|
||||
nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(item);
|
||||
if (shortcut) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = shortcut->GetFaviconPageUri(getter_AddRefs(uri));
|
||||
if (NS_SUCCEEDED(rv) && uri) {
|
||||
|
||||
// The local file path is stored inside the nsIURI
|
||||
// Get the nsIURI spec which stores the local path for the icon to remove
|
||||
nsAutoCString spec;
|
||||
nsresult rv = uri->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event
|
||||
= new mozilla::widget::AsyncDeleteIconFromDisk(NS_ConvertUTF8toUTF16(spec));
|
||||
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
// The shortcut was generated from an IShellLinkW so IShellLinkW can
|
||||
// only tell us what the original icon is and not the URI.
|
||||
// So this field was used only temporarily as the actual icon file
|
||||
// path. It should be cleared.
|
||||
shortcut->SetFaviconPageUri(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end for
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Ensures that we have no old ICO files left in the jump list cache
|
||||
nsresult JumpListBuilder::RemoveIconCacheForAllItems()
|
||||
{
|
||||
// Construct the path of our jump list cache
|
||||
nsCOMPtr<nsIFile> jumpListCacheDir;
|
||||
nsresult rv = NS_GetSpecialDirectory("ProfLDS",
|
||||
getter_AddRefs(jumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = jumpListCacheDir->AppendNative(nsDependentCString(
|
||||
mozilla::widget::FaviconHelper::kJumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Loop through each directory entry and remove all ICO files found
|
||||
do {
|
||||
bool hasMore = false;
|
||||
if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
if (NS_FAILED(entries->GetNext(getter_AddRefs(supp))))
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp));
|
||||
nsAutoString path;
|
||||
if (NS_FAILED(currFile->GetPath(path)))
|
||||
continue;
|
||||
|
||||
if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
|
||||
// Check if the cached ICO file exists
|
||||
bool exists;
|
||||
if (NS_FAILED(currFile->Exists(&exists)) || !exists)
|
||||
continue;
|
||||
|
||||
// We found an ICO file that exists, so we should remove it
|
||||
currFile->Remove(false);
|
||||
}
|
||||
} while(true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::AddListToBuild(int16_t aCatType, nsIArray *items, const nsAString &catName, bool *_retval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
*_retval = false;
|
||||
|
||||
if (!mJumpListMgr)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
switch(aCatType) {
|
||||
case nsIJumpListBuilder::JUMPLIST_CATEGORY_TASKS:
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(items);
|
||||
|
||||
HRESULT hr;
|
||||
RefPtr<IObjectCollection> collection;
|
||||
hr = CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr,
|
||||
CLSCTX_INPROC_SERVER, IID_IObjectCollection,
|
||||
getter_AddRefs(collection));
|
||||
if (FAILED(hr))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Build the list
|
||||
uint32_t length;
|
||||
items->GetLength(&length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
|
||||
if (!item)
|
||||
continue;
|
||||
// Check for separators
|
||||
if (IsSeparator(item)) {
|
||||
RefPtr<IShellLinkW> link;
|
||||
rv = JumpListSeparator::GetSeparator(link);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
collection->AddObject(link);
|
||||
continue;
|
||||
}
|
||||
// These should all be ShellLinks
|
||||
RefPtr<IShellLinkW> link;
|
||||
rv = JumpListShortcut::GetShellLink(item, link, mIOThread);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
collection->AddObject(link);
|
||||
}
|
||||
|
||||
// We need IObjectArray to submit
|
||||
RefPtr<IObjectArray> pArray;
|
||||
hr = collection->QueryInterface(IID_IObjectArray, getter_AddRefs(pArray));
|
||||
if (FAILED(hr))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Add the tasks
|
||||
hr = mJumpListMgr->AddUserTasks(pArray);
|
||||
if (SUCCEEDED(hr))
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
break;
|
||||
case nsIJumpListBuilder::JUMPLIST_CATEGORY_RECENT:
|
||||
{
|
||||
if (SUCCEEDED(mJumpListMgr->AppendKnownCategory(KDC_RECENT)))
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
break;
|
||||
case nsIJumpListBuilder::JUMPLIST_CATEGORY_FREQUENT:
|
||||
{
|
||||
if (SUCCEEDED(mJumpListMgr->AppendKnownCategory(KDC_FREQUENT)))
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
break;
|
||||
case nsIJumpListBuilder::JUMPLIST_CATEGORY_CUSTOMLIST:
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(items);
|
||||
|
||||
if (catName.IsEmpty())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
HRESULT hr;
|
||||
RefPtr<IObjectCollection> collection;
|
||||
hr = CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr,
|
||||
CLSCTX_INPROC_SERVER, IID_IObjectCollection,
|
||||
getter_AddRefs(collection));
|
||||
if (FAILED(hr))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
uint32_t length;
|
||||
items->GetLength(&length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
|
||||
if (!item)
|
||||
continue;
|
||||
int16_t type;
|
||||
if (NS_FAILED(item->GetType(&type)))
|
||||
continue;
|
||||
switch(type) {
|
||||
case nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR:
|
||||
{
|
||||
RefPtr<IShellLinkW> shellItem;
|
||||
rv = JumpListSeparator::GetSeparator(shellItem);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
collection->AddObject(shellItem);
|
||||
}
|
||||
break;
|
||||
case nsIJumpListItem::JUMPLIST_ITEM_LINK:
|
||||
{
|
||||
RefPtr<IShellItem2> shellItem;
|
||||
rv = JumpListLink::GetShellItem(item, shellItem);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
collection->AddObject(shellItem);
|
||||
}
|
||||
break;
|
||||
case nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT:
|
||||
{
|
||||
RefPtr<IShellLinkW> shellItem;
|
||||
rv = JumpListShortcut::GetShellLink(item, shellItem, mIOThread);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
collection->AddObject(shellItem);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We need IObjectArray to submit
|
||||
RefPtr<IObjectArray> pArray;
|
||||
hr = collection->QueryInterface(IID_IObjectArray, (LPVOID*)&pArray);
|
||||
if (FAILED(hr))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Add the tasks
|
||||
hr = mJumpListMgr->AppendCategory(reinterpret_cast<const wchar_t*>(catName.BeginReading()), pArray);
|
||||
if (SUCCEEDED(hr))
|
||||
*_retval = true;
|
||||
|
||||
// Get rid of the old icons
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk(true);
|
||||
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::AbortListBuild()
|
||||
{
|
||||
if (!mJumpListMgr)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
mJumpListMgr->AbortList();
|
||||
sBuildingList = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::CommitListBuild(bool *_retval)
|
||||
{
|
||||
*_retval = false;
|
||||
|
||||
if (!mJumpListMgr)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
HRESULT hr = mJumpListMgr->CommitList();
|
||||
sBuildingList = false;
|
||||
|
||||
// XXX We might want some specific error data here.
|
||||
if (SUCCEEDED(hr)) {
|
||||
*_retval = true;
|
||||
mHasCommit = true;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::DeleteActiveList(bool *_retval)
|
||||
{
|
||||
*_retval = false;
|
||||
|
||||
if (!mJumpListMgr)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if(sBuildingList)
|
||||
AbortListBuild();
|
||||
|
||||
nsAutoString uid;
|
||||
if (!WinTaskbar::GetAppUserModelID(uid))
|
||||
return NS_OK;
|
||||
|
||||
if (SUCCEEDED(mJumpListMgr->DeleteList(uid.get())))
|
||||
*_retval = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
bool JumpListBuilder::IsSeparator(nsCOMPtr<nsIJumpListItem>& item)
|
||||
{
|
||||
int16_t type;
|
||||
item->GetType(&type);
|
||||
if (NS_FAILED(item->GetType(&type)))
|
||||
return false;
|
||||
|
||||
if (type == nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TransferIObjectArrayToIMutableArray - used in converting removed items
|
||||
// to our objects.
|
||||
nsresult JumpListBuilder::TransferIObjectArrayToIMutableArray(IObjectArray *objArray, nsIMutableArray *removedItems)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(objArray);
|
||||
NS_ENSURE_ARG_POINTER(removedItems);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
uint32_t count = 0;
|
||||
objArray->GetCount(&count);
|
||||
|
||||
nsCOMPtr<nsIJumpListItem> item;
|
||||
|
||||
for (uint32_t idx = 0; idx < count; idx++) {
|
||||
IShellLinkW * pLink = nullptr;
|
||||
IShellItem * pItem = nullptr;
|
||||
|
||||
if (SUCCEEDED(objArray->GetAt(idx, IID_IShellLinkW, (LPVOID*)&pLink))) {
|
||||
nsCOMPtr<nsIJumpListShortcut> shortcut =
|
||||
do_CreateInstance(kJumpListShortcutCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
rv = JumpListShortcut::GetJumpListShortcut(pLink, shortcut);
|
||||
item = do_QueryInterface(shortcut);
|
||||
}
|
||||
else if (SUCCEEDED(objArray->GetAt(idx, IID_IShellItem, (LPVOID*)&pItem))) {
|
||||
nsCOMPtr<nsIJumpListLink> link =
|
||||
do_CreateInstance(kJumpListLinkCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
rv = JumpListLink::GetJumpListLink(pItem, link);
|
||||
item = do_QueryInterface(link);
|
||||
}
|
||||
|
||||
if (pLink)
|
||||
pLink->Release();
|
||||
if (pItem)
|
||||
pItem->Release();
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
removedItems->AppendElement(item, false);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aTopic);
|
||||
if (strcmp(aTopic, TOPIC_PROFILE_BEFORE_CHANGE) == 0) {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
if (observerService) {
|
||||
observerService->RemoveObserver(this, TOPIC_PROFILE_BEFORE_CHANGE);
|
||||
}
|
||||
mIOThread->Shutdown();
|
||||
} else if (strcmp(aTopic, "nsPref:changed") == 0 &&
|
||||
nsDependentString(aData).EqualsASCII(kPrefTaskbarEnabled)) {
|
||||
bool enabled = Preferences::GetBool(kPrefTaskbarEnabled, true);
|
||||
if (!enabled) {
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk();
|
||||
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
} else if (strcmp(aTopic, TOPIC_CLEAR_PRIVATE_DATA) == 0) {
|
||||
// Delete JumpListCache icons from Disk, if any.
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk(false);
|
||||
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
62
widget/windows/JumpListBuilder.h
Normal file
62
widget/windows/JumpListBuilder.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __JumpListBuilder_h__
|
||||
#define __JumpListBuilder_h__
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#undef NTDDI_VERSION
|
||||
#define NTDDI_VERSION NTDDI_WIN7
|
||||
// Needed for various com interfaces
|
||||
#include <shobjidl.h>
|
||||
#undef LogSeverity // SetupAPI.h #defines this as DWORD
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIMutableArray.h"
|
||||
|
||||
#include "nsIJumpListBuilder.h"
|
||||
#include "nsIJumpListItem.h"
|
||||
#include "JumpListItem.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class JumpListBuilder : public nsIJumpListBuilder,
|
||||
public nsIObserver
|
||||
{
|
||||
virtual ~JumpListBuilder();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIJUMPLISTBUILDER
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
JumpListBuilder();
|
||||
|
||||
protected:
|
||||
static bool sBuildingList;
|
||||
|
||||
private:
|
||||
RefPtr<ICustomDestinationList> mJumpListMgr;
|
||||
uint32_t mMaxItems;
|
||||
bool mHasCommit;
|
||||
nsCOMPtr<nsIThread> mIOThread;
|
||||
|
||||
bool IsSeparator(nsCOMPtr<nsIJumpListItem>& item);
|
||||
nsresult TransferIObjectArrayToIMutableArray(IObjectArray *objArray, nsIMutableArray *removedItems);
|
||||
nsresult RemoveIconCacheForItems(nsIMutableArray *removedItems);
|
||||
nsresult RemoveIconCacheForAllItems();
|
||||
|
||||
friend class WinTaskbar;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __JumpListBuilder_h__ */
|
||||
|
||||
630
widget/windows/JumpListItem.cpp
Normal file
630
widget/windows/JumpListItem.cpp
Normal file
|
|
@ -0,0 +1,630 @@
|
|||
/* -*- 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 "JumpListItem.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
#include <propvarutil.h>
|
||||
#include <propkey.h>
|
||||
|
||||
#include "nsIFile.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "JumpListBuilder.h"
|
||||
#include "WinUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
// ISUPPORTS Impl's
|
||||
NS_IMPL_ISUPPORTS(JumpListItem,
|
||||
nsIJumpListItem)
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(JumpListSeparator,
|
||||
JumpListItem,
|
||||
nsIJumpListSeparator)
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(JumpListLink,
|
||||
JumpListItem,
|
||||
nsIJumpListLink)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JumpListShortcut)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIJumpListShortcut)
|
||||
NS_INTERFACE_MAP_END_INHERITING(JumpListItem)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(JumpListShortcut, mHandlerApp)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(JumpListShortcut)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(JumpListShortcut)
|
||||
|
||||
NS_IMETHODIMP JumpListItem::GetType(int16_t *aType)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aType);
|
||||
|
||||
*aType = mItemType;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListItem::Equals(nsIJumpListItem *aItem, bool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aItem);
|
||||
|
||||
*aResult = false;
|
||||
|
||||
int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY;
|
||||
if (NS_FAILED(aItem->GetType(&theType)))
|
||||
return NS_OK;
|
||||
|
||||
// Make sure the types match.
|
||||
if (Type() != theType)
|
||||
return NS_OK;
|
||||
|
||||
*aResult = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* link impl. */
|
||||
|
||||
NS_IMETHODIMP JumpListLink::GetUri(nsIURI **aURI)
|
||||
{
|
||||
NS_IF_ADDREF(*aURI = mURI);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListLink::SetUri(nsIURI *aURI)
|
||||
{
|
||||
mURI = aURI;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListLink::SetUriTitle(const nsAString &aUriTitle)
|
||||
{
|
||||
mUriTitle.Assign(aUriTitle);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListLink::GetUriTitle(nsAString& aUriTitle)
|
||||
{
|
||||
aUriTitle.Assign(mUriTitle);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListLink::GetUriHash(nsACString& aUriHash)
|
||||
{
|
||||
if (!mURI)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, aUriHash);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListLink::CompareHash(nsIURI *aUri, bool *aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!mURI) {
|
||||
*aResult = !aUri;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aUri);
|
||||
|
||||
nsAutoCString hash1, hash2;
|
||||
|
||||
rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, hash1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, aUri, hash2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = hash1.Equals(hash2);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListLink::Equals(nsIJumpListItem *aItem, bool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aItem);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
*aResult = false;
|
||||
|
||||
int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY;
|
||||
if (NS_FAILED(aItem->GetType(&theType)))
|
||||
return NS_OK;
|
||||
|
||||
// Make sure the types match.
|
||||
if (Type() != theType)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIJumpListLink> link = do_QueryInterface(aItem, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Check the titles
|
||||
nsAutoString title;
|
||||
link->GetUriTitle(title);
|
||||
if (!mUriTitle.Equals(title))
|
||||
return NS_OK;
|
||||
|
||||
// Call the internal object's equals() method to check.
|
||||
nsCOMPtr<nsIURI> theUri;
|
||||
bool equals = false;
|
||||
if (NS_SUCCEEDED(link->GetUri(getter_AddRefs(theUri)))) {
|
||||
if (!theUri) {
|
||||
if (!mURI)
|
||||
*aResult = true;
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_SUCCEEDED(theUri->Equals(mURI, &equals)) && equals) {
|
||||
*aResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* shortcut impl. */
|
||||
|
||||
NS_IMETHODIMP JumpListShortcut::GetApp(nsILocalHandlerApp **aApp)
|
||||
{
|
||||
NS_IF_ADDREF(*aApp = mHandlerApp);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListShortcut::SetApp(nsILocalHandlerApp *aApp)
|
||||
{
|
||||
mHandlerApp = aApp;
|
||||
|
||||
// Confirm the app is present on the system
|
||||
if (!ExecutableExists(mHandlerApp))
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListShortcut::GetIconIndex(int32_t *aIconIndex)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aIconIndex);
|
||||
|
||||
*aIconIndex = mIconIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListShortcut::SetIconIndex(int32_t aIconIndex)
|
||||
{
|
||||
mIconIndex = aIconIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListShortcut::GetFaviconPageUri(nsIURI **aFaviconPageURI)
|
||||
{
|
||||
NS_IF_ADDREF(*aFaviconPageURI = mFaviconPageURI);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListShortcut::SetFaviconPageUri(nsIURI *aFaviconPageURI)
|
||||
{
|
||||
mFaviconPageURI = aFaviconPageURI;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListShortcut::Equals(nsIJumpListItem *aItem, bool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aItem);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
*aResult = false;
|
||||
|
||||
int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY;
|
||||
if (NS_FAILED(aItem->GetType(&theType)))
|
||||
return NS_OK;
|
||||
|
||||
// Make sure the types match.
|
||||
if (Type() != theType)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(aItem, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Check the icon index
|
||||
//int32_t idx;
|
||||
//shortcut->GetIconIndex(&idx);
|
||||
//if (mIconIndex != idx)
|
||||
// return NS_OK;
|
||||
// No need to check the icon page URI either
|
||||
|
||||
// Call the internal object's equals() method to check.
|
||||
nsCOMPtr<nsILocalHandlerApp> theApp;
|
||||
bool equals = false;
|
||||
if (NS_SUCCEEDED(shortcut->GetApp(getter_AddRefs(theApp)))) {
|
||||
if (!theApp) {
|
||||
if (!mHandlerApp)
|
||||
*aResult = true;
|
||||
return NS_OK;
|
||||
}
|
||||
if (NS_SUCCEEDED(theApp->Equals(mHandlerApp, &equals)) && equals) {
|
||||
*aResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* internal helpers */
|
||||
|
||||
// (static) Creates a ShellLink that encapsulate a separator.
|
||||
nsresult JumpListSeparator::GetSeparator(RefPtr<IShellLinkW>& aShellLink)
|
||||
{
|
||||
HRESULT hr;
|
||||
IShellLinkW* psl;
|
||||
|
||||
// Create a IShellLink.
|
||||
hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_IShellLinkW, (LPVOID*)&psl);
|
||||
if (FAILED(hr))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
IPropertyStore* pPropStore = nullptr;
|
||||
hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore);
|
||||
if (FAILED(hr))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
PROPVARIANT pv;
|
||||
InitPropVariantFromBoolean(TRUE, &pv);
|
||||
|
||||
pPropStore->SetValue(PKEY_AppUserModel_IsDestListSeparator, pv);
|
||||
pPropStore->Commit();
|
||||
pPropStore->Release();
|
||||
|
||||
PropVariantClear(&pv);
|
||||
|
||||
aShellLink = dont_AddRef(psl);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// (static) Creates a ShellLink that encapsulate a shortcut to local apps.
|
||||
nsresult JumpListShortcut::GetShellLink(nsCOMPtr<nsIJumpListItem>& item,
|
||||
RefPtr<IShellLinkW>& aShellLink,
|
||||
nsCOMPtr<nsIThread> &aIOThread)
|
||||
{
|
||||
HRESULT hr;
|
||||
IShellLinkW* psl;
|
||||
nsresult rv;
|
||||
|
||||
// Shell links:
|
||||
// http://msdn.microsoft.com/en-us/library/bb776891(VS.85).aspx
|
||||
// http://msdn.microsoft.com/en-us/library/bb774950(VS.85).aspx
|
||||
|
||||
int16_t type;
|
||||
if (NS_FAILED(item->GetType(&type)))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
if (type != nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(item, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsILocalHandlerApp> handlerApp;
|
||||
rv = shortcut->GetApp(getter_AddRefs(handlerApp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create a IShellLink
|
||||
hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_IShellLinkW, (LPVOID*)&psl);
|
||||
if (FAILED(hr))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Retrieve the app path, title, description and optional command line args.
|
||||
nsAutoString appPath, appTitle, appDescription, appArgs;
|
||||
int32_t appIconIndex = 0;
|
||||
|
||||
// Path
|
||||
nsCOMPtr<nsIFile> executable;
|
||||
handlerApp->GetExecutable(getter_AddRefs(executable));
|
||||
|
||||
rv = executable->GetPath(appPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Command line parameters
|
||||
uint32_t count = 0;
|
||||
handlerApp->GetParameterCount(&count);
|
||||
for (uint32_t idx = 0; idx < count; idx++) {
|
||||
if (idx > 0)
|
||||
appArgs.Append(' ');
|
||||
nsAutoString param;
|
||||
rv = handlerApp->GetParameter(idx, param);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
appArgs.Append(param);
|
||||
}
|
||||
|
||||
handlerApp->GetName(appTitle);
|
||||
handlerApp->GetDetailedDescription(appDescription);
|
||||
|
||||
bool useUriIcon = false; // if we want to use the URI icon
|
||||
bool usedUriIcon = false; // if we did use the URI icon
|
||||
shortcut->GetIconIndex(&appIconIndex);
|
||||
|
||||
nsCOMPtr<nsIURI> iconUri;
|
||||
rv = shortcut->GetFaviconPageUri(getter_AddRefs(iconUri));
|
||||
if (NS_SUCCEEDED(rv) && iconUri) {
|
||||
useUriIcon = true;
|
||||
}
|
||||
|
||||
// Store the title of the app
|
||||
if (appTitle.Length() > 0) {
|
||||
IPropertyStore* pPropStore = nullptr;
|
||||
hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore);
|
||||
if (FAILED(hr))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
PROPVARIANT pv;
|
||||
InitPropVariantFromString(appTitle.get(), &pv);
|
||||
|
||||
pPropStore->SetValue(PKEY_Title, pv);
|
||||
pPropStore->Commit();
|
||||
pPropStore->Release();
|
||||
|
||||
PropVariantClear(&pv);
|
||||
}
|
||||
|
||||
// Store the rest of the params
|
||||
psl->SetPath(appPath.get());
|
||||
psl->SetDescription(appDescription.get());
|
||||
psl->SetArguments(appArgs.get());
|
||||
|
||||
if (useUriIcon) {
|
||||
nsString icoFilePath;
|
||||
rv = mozilla::widget::FaviconHelper::ObtainCachedIconFile(iconUri,
|
||||
icoFilePath,
|
||||
aIOThread,
|
||||
false);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Always use the first icon in the ICO file
|
||||
// our encoded icon only has 1 resource
|
||||
psl->SetIconLocation(icoFilePath.get(), 0);
|
||||
usedUriIcon = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't use an ICO via URI so fall back to the app icon
|
||||
if (!usedUriIcon) {
|
||||
psl->SetIconLocation(appPath.get(), appIconIndex);
|
||||
}
|
||||
|
||||
aShellLink = dont_AddRef(psl);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If successful fills in the aSame parameter
|
||||
// aSame will be true if the path is in our icon cache
|
||||
static nsresult IsPathInOurIconCache(nsCOMPtr<nsIJumpListShortcut>& aShortcut,
|
||||
wchar_t *aPath, bool *aSame)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPath);
|
||||
NS_ENSURE_ARG_POINTER(aSame);
|
||||
|
||||
*aSame = false;
|
||||
|
||||
// Construct the path of our jump list cache
|
||||
nsCOMPtr<nsIFile> jumpListCache;
|
||||
nsresult rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(jumpListCache));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = jumpListCache->AppendNative(nsDependentCString(FaviconHelper::kJumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoString jumpListCachePath;
|
||||
rv = jumpListCache->GetPath(jumpListCachePath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Construct the parent path of the passed in path
|
||||
nsCOMPtr<nsIFile> passedInFile = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(passedInFile, NS_ERROR_FAILURE);
|
||||
nsAutoString passedInPath(aPath);
|
||||
rv = passedInFile->InitWithPath(passedInPath);
|
||||
nsCOMPtr<nsIFile> passedInParentFile;
|
||||
passedInFile->GetParent(getter_AddRefs(passedInParentFile));
|
||||
nsAutoString passedInParentPath;
|
||||
rv = jumpListCache->GetPath(passedInParentPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aSame = jumpListCachePath.Equals(passedInParentPath);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// (static) For a given IShellLink, create and return a populated nsIJumpListShortcut.
|
||||
nsresult JumpListShortcut::GetJumpListShortcut(IShellLinkW *pLink, nsCOMPtr<nsIJumpListShortcut>& aShortcut)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(pLink);
|
||||
|
||||
nsresult rv;
|
||||
HRESULT hres;
|
||||
|
||||
nsCOMPtr<nsILocalHandlerApp> handlerApp =
|
||||
do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
wchar_t buf[MAX_PATH];
|
||||
|
||||
// Path
|
||||
hres = pLink->GetPath(buf, MAX_PATH, nullptr, SLGP_UNCPRIORITY);
|
||||
if (FAILED(hres))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsDependentString filepath(buf);
|
||||
rv = NS_NewLocalFile(filepath, false, getter_AddRefs(file));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = handlerApp->SetExecutable(file);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Parameters
|
||||
hres = pLink->GetArguments(buf, MAX_PATH);
|
||||
if (SUCCEEDED(hres)) {
|
||||
LPWSTR *arglist;
|
||||
int32_t numArgs;
|
||||
int32_t idx;
|
||||
|
||||
arglist = ::CommandLineToArgvW(buf, &numArgs);
|
||||
if(arglist) {
|
||||
for (idx = 0; idx < numArgs; idx++) {
|
||||
// szArglist[i] is null terminated
|
||||
nsDependentString arg(arglist[idx]);
|
||||
handlerApp->AppendParameter(arg);
|
||||
}
|
||||
::LocalFree(arglist);
|
||||
}
|
||||
}
|
||||
|
||||
rv = aShortcut->SetApp(handlerApp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Icon index or file location
|
||||
int iconIdx = 0;
|
||||
hres = pLink->GetIconLocation(buf, MAX_PATH, &iconIdx);
|
||||
if (SUCCEEDED(hres)) {
|
||||
// XXX How do we handle converting local files to images here? Do we need to?
|
||||
aShortcut->SetIconIndex(iconIdx);
|
||||
|
||||
// Obtain the local profile directory and construct the output icon file path
|
||||
// We only set the Icon Uri if we're sure it was from our icon cache.
|
||||
bool isInOurCache;
|
||||
if (NS_SUCCEEDED(IsPathInOurIconCache(aShortcut, buf, &isInOurCache)) &&
|
||||
isInOurCache) {
|
||||
nsCOMPtr<nsIURI> iconUri;
|
||||
nsAutoString path(buf);
|
||||
rv = NS_NewURI(getter_AddRefs(iconUri), path);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aShortcut->SetFaviconPageUri(iconUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do we need the title and description? Probably not since handler app doesn't compare
|
||||
// these in equals.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// (static) ShellItems are used to encapsulate links to things. We currently only support URI links,
|
||||
// but more support could be added, such as local file and directory links.
|
||||
nsresult JumpListLink::GetShellItem(nsCOMPtr<nsIJumpListItem>& item, RefPtr<IShellItem2>& aShellItem)
|
||||
{
|
||||
IShellItem2 *psi = nullptr;
|
||||
nsresult rv;
|
||||
|
||||
int16_t type;
|
||||
if (NS_FAILED(item->GetType(&type)))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
if (type != nsIJumpListItem::JUMPLIST_ITEM_LINK)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCOMPtr<nsIJumpListLink> link = do_QueryInterface(item, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = link->GetUri(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = uri->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create the IShellItem
|
||||
if (FAILED(WinUtils::SHCreateItemFromParsingName(
|
||||
NS_ConvertASCIItoUTF16(spec).get(),
|
||||
nullptr, IID_PPV_ARGS(&psi)))) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Set the title
|
||||
nsAutoString linkTitle;
|
||||
link->GetUriTitle(linkTitle);
|
||||
|
||||
IPropertyStore* pPropStore = nullptr;
|
||||
HRESULT hres = psi->GetPropertyStore(GPS_DEFAULT, IID_IPropertyStore, (void**)&pPropStore);
|
||||
if (FAILED(hres))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
PROPVARIANT pv;
|
||||
InitPropVariantFromString(linkTitle.get(), &pv);
|
||||
|
||||
// May fail due to shell item access permissions.
|
||||
pPropStore->SetValue(PKEY_ItemName, pv);
|
||||
pPropStore->Commit();
|
||||
pPropStore->Release();
|
||||
|
||||
PropVariantClear(&pv);
|
||||
|
||||
aShellItem = dont_AddRef(psi);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// (static) For a given IShellItem, create and return a populated nsIJumpListLink.
|
||||
nsresult JumpListLink::GetJumpListLink(IShellItem *pItem, nsCOMPtr<nsIJumpListLink>& aLink)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(pItem);
|
||||
|
||||
// We assume for now these are URI links, but through properties we could
|
||||
// query and create other types.
|
||||
nsresult rv;
|
||||
LPWSTR lpstrName = nullptr;
|
||||
|
||||
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_URL, &lpstrName))) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsAutoString spec(lpstrName);
|
||||
|
||||
rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(spec));
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
aLink->SetUri(uri);
|
||||
|
||||
::CoTaskMemFree(lpstrName);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Confirm the app is on the system
|
||||
bool JumpListShortcut::ExecutableExists(nsCOMPtr<nsILocalHandlerApp>& handlerApp)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!handlerApp)
|
||||
return false;
|
||||
|
||||
nsCOMPtr<nsIFile> executable;
|
||||
rv = handlerApp->GetExecutable(getter_AddRefs(executable));
|
||||
if (NS_SUCCEEDED(rv) && executable) {
|
||||
bool exists;
|
||||
executable->Exists(&exists);
|
||||
return exists;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
132
widget/windows/JumpListItem.h
Normal file
132
widget/windows/JumpListItem.h
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __JumpListItem_h__
|
||||
#define __JumpListItem_h__
|
||||
|
||||
#include <windows.h>
|
||||
#include <shobjidl.h>
|
||||
#undef LogSeverity // SetupAPI.h #defines this as DWORD
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsIJumpListItem.h" // defines nsIJumpListItem
|
||||
#include "nsIMIMEInfo.h" // defines nsILocalHandlerApp
|
||||
#include "nsTArray.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsIThread;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class JumpListItem : public nsIJumpListItem
|
||||
{
|
||||
public:
|
||||
JumpListItem() :
|
||||
mItemType(nsIJumpListItem::JUMPLIST_ITEM_EMPTY)
|
||||
{}
|
||||
|
||||
JumpListItem(int32_t type) :
|
||||
mItemType(type)
|
||||
{}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIJUMPLISTITEM
|
||||
|
||||
static const char kJumpListCacheDir[];
|
||||
|
||||
protected:
|
||||
virtual ~JumpListItem()
|
||||
{}
|
||||
|
||||
short Type() { return mItemType; }
|
||||
short mItemType;
|
||||
|
||||
};
|
||||
|
||||
class JumpListSeparator : public JumpListItem, public nsIJumpListSeparator
|
||||
{
|
||||
~JumpListSeparator() {}
|
||||
|
||||
public:
|
||||
JumpListSeparator() :
|
||||
JumpListItem(nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR)
|
||||
{}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_IMETHOD GetType(int16_t *aType) override { return JumpListItem::GetType(aType); }
|
||||
NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override { return JumpListItem::Equals(item, _retval); }
|
||||
|
||||
static nsresult GetSeparator(RefPtr<IShellLinkW>& aShellLink);
|
||||
};
|
||||
|
||||
class JumpListLink : public JumpListItem, public nsIJumpListLink
|
||||
{
|
||||
~JumpListLink() {}
|
||||
|
||||
public:
|
||||
JumpListLink() :
|
||||
JumpListItem(nsIJumpListItem::JUMPLIST_ITEM_LINK)
|
||||
{}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_IMETHOD GetType(int16_t *aType) override { return JumpListItem::GetType(aType); }
|
||||
NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override;
|
||||
NS_DECL_NSIJUMPLISTLINK
|
||||
|
||||
static nsresult GetShellItem(nsCOMPtr<nsIJumpListItem>& item, RefPtr<IShellItem2>& aShellItem);
|
||||
static nsresult GetJumpListLink(IShellItem *pItem, nsCOMPtr<nsIJumpListLink>& aLink);
|
||||
|
||||
protected:
|
||||
nsString mUriTitle;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsICryptoHash> mCryptoHash;
|
||||
};
|
||||
|
||||
class JumpListShortcut : public JumpListItem, public nsIJumpListShortcut
|
||||
{
|
||||
~JumpListShortcut() {}
|
||||
|
||||
public:
|
||||
JumpListShortcut() :
|
||||
JumpListItem(nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT)
|
||||
{}
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(JumpListShortcut, JumpListItem)
|
||||
NS_IMETHOD GetType(int16_t *aType) override { return JumpListItem::GetType(aType); }
|
||||
NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override;
|
||||
NS_DECL_NSIJUMPLISTSHORTCUT
|
||||
|
||||
static nsresult GetShellLink(nsCOMPtr<nsIJumpListItem>& item,
|
||||
RefPtr<IShellLinkW>& aShellLink,
|
||||
nsCOMPtr<nsIThread> &aIOThread);
|
||||
static nsresult GetJumpListShortcut(IShellLinkW *pLink, nsCOMPtr<nsIJumpListShortcut>& aShortcut);
|
||||
static nsresult GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> &aICOFile);
|
||||
|
||||
protected:
|
||||
int32_t mIconIndex;
|
||||
nsCOMPtr<nsIURI> mFaviconPageURI;
|
||||
nsCOMPtr<nsILocalHandlerApp> mHandlerApp;
|
||||
|
||||
bool ExecutableExists(nsCOMPtr<nsILocalHandlerApp>& handlerApp);
|
||||
static nsresult ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsString &aICOFilePath,
|
||||
nsCOMPtr<nsIThread> &aIOThread);
|
||||
static nsresult CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> aICOFile,
|
||||
nsCOMPtr<nsIThread> &aIOThread);
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __JumpListItem_h__ */
|
||||
5232
widget/windows/KeyboardLayout.cpp
Normal file
5232
widget/windows/KeyboardLayout.cpp
Normal file
File diff suppressed because it is too large
Load diff
1012
widget/windows/KeyboardLayout.h
Normal file
1012
widget/windows/KeyboardLayout.h
Normal file
File diff suppressed because it is too large
Load diff
161
widget/windows/LSPAnnotator.cpp
Normal file
161
widget/windows/LSPAnnotator.cpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/* 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/. */
|
||||
|
||||
/**
|
||||
* LSPs are evil little bits of code that are allowed to inject into our
|
||||
* networking stack by Windows. Once they have wormed into our process
|
||||
* they gnaw at our innards until we crash. Here we force the buggers
|
||||
* into the light by recording them in our crash information.
|
||||
* We do the enumeration on a thread because I'm concerned about startup perf
|
||||
* on machines with several LSPs.
|
||||
*/
|
||||
|
||||
#if _WIN32_WINNT < 0x0600
|
||||
// Redefining _WIN32_WINNT for some Vista APIs that we call
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#endif
|
||||
#include "nsICrashReporter.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include <windows.h>
|
||||
#include <rpc.h>
|
||||
#include <ws2spi.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace crashreporter {
|
||||
|
||||
class LSPAnnotationGatherer : public Runnable
|
||||
{
|
||||
~LSPAnnotationGatherer() {}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
void Annotate();
|
||||
nsCString mString;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(LSPAnnotationGatherer, nsIRunnable)
|
||||
|
||||
void
|
||||
LSPAnnotationGatherer::Annotate()
|
||||
{
|
||||
nsCOMPtr<nsICrashReporter> cr =
|
||||
do_GetService("@mozilla.org/toolkit/crash-reporter;1");
|
||||
bool enabled;
|
||||
if (cr && NS_SUCCEEDED(cr->GetEnabled(&enabled)) && enabled) {
|
||||
cr->AnnotateCrashReport(NS_LITERAL_CSTRING("Winsock_LSP"), mString);
|
||||
}
|
||||
mThread->AsyncShutdown();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LSPAnnotationGatherer::Run()
|
||||
{
|
||||
PR_SetCurrentThreadName("LSP Annotator");
|
||||
|
||||
mThread = NS_GetCurrentThread();
|
||||
|
||||
DWORD size = 0;
|
||||
int err;
|
||||
// Get the size of the buffer we need
|
||||
if (SOCKET_ERROR != WSCEnumProtocols(nullptr, nullptr, &size, &err) ||
|
||||
err != WSAENOBUFS) {
|
||||
// Er, what?
|
||||
NS_NOTREACHED("WSCEnumProtocols suceeded when it should have failed ...");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
auto byteArray = MakeUnique<char[]>(size);
|
||||
WSAPROTOCOL_INFOW* providers =
|
||||
reinterpret_cast<WSAPROTOCOL_INFOW*>(byteArray.get());
|
||||
|
||||
int n = WSCEnumProtocols(nullptr, providers, &size, &err);
|
||||
if (n == SOCKET_ERROR) {
|
||||
// Lame. We provided the right size buffer; we'll just give up now.
|
||||
NS_WARNING("Could not get LSP list");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCString str;
|
||||
for (int i = 0; i < n; i++) {
|
||||
AppendUTF16toUTF8(nsDependentString(providers[i].szProtocol), str);
|
||||
str.AppendLiteral(" : ");
|
||||
str.AppendInt(providers[i].iVersion);
|
||||
str.AppendLiteral(" : ");
|
||||
str.AppendInt(providers[i].iAddressFamily);
|
||||
str.AppendLiteral(" : ");
|
||||
str.AppendInt(providers[i].iSocketType);
|
||||
str.AppendLiteral(" : ");
|
||||
str.AppendInt(providers[i].iProtocol);
|
||||
str.AppendLiteral(" : ");
|
||||
str.AppendPrintf("0x%x", providers[i].dwServiceFlags1);
|
||||
str.AppendLiteral(" : ");
|
||||
str.AppendPrintf("0x%x", providers[i].dwProviderFlags);
|
||||
str.AppendLiteral(" : ");
|
||||
|
||||
wchar_t path[MAX_PATH];
|
||||
int pathLen = MAX_PATH;
|
||||
if (!WSCGetProviderPath(&providers[i].ProviderId, path, &pathLen, &err)) {
|
||||
AppendUTF16toUTF8(nsDependentString(path), str);
|
||||
}
|
||||
|
||||
str.AppendLiteral(" : ");
|
||||
// If WSCGetProviderInfo is available, we should call it to obtain the
|
||||
// category flags for this provider. When present, these flags inform
|
||||
// Windows as to which order to chain the providers.
|
||||
nsModuleHandle ws2_32(LoadLibraryW(L"ws2_32.dll"));
|
||||
if (ws2_32) {
|
||||
decltype(WSCGetProviderInfo)* pWSCGetProviderInfo =
|
||||
reinterpret_cast<decltype(WSCGetProviderInfo)*>(
|
||||
GetProcAddress(ws2_32, "WSCGetProviderInfo"));
|
||||
if (pWSCGetProviderInfo) {
|
||||
DWORD categoryInfo;
|
||||
size_t categoryInfoSize = sizeof(categoryInfo);
|
||||
if (!pWSCGetProviderInfo(&providers[i].ProviderId,
|
||||
ProviderInfoLspCategories,
|
||||
(PBYTE)&categoryInfo, &categoryInfoSize, 0,
|
||||
&err)) {
|
||||
str.AppendPrintf("0x%x", categoryInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLiteral(" : ");
|
||||
if (providers[i].ProtocolChain.ChainLen <= BASE_PROTOCOL) {
|
||||
// If we're dealing with a catalog entry that identifies an individual
|
||||
// base or layer provider, log its provider GUID.
|
||||
RPC_CSTR provIdStr = nullptr;
|
||||
if (UuidToStringA(&providers[i].ProviderId, &provIdStr) == RPC_S_OK) {
|
||||
str.Append(reinterpret_cast<char*>(provIdStr));
|
||||
RpcStringFreeA(&provIdStr);
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 1 != n) {
|
||||
str.AppendLiteral(" \n ");
|
||||
}
|
||||
}
|
||||
|
||||
mString = str;
|
||||
NS_DispatchToMainThread(NewRunnableMethod(this, &LSPAnnotationGatherer::Annotate));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void LSPAnnotate()
|
||||
{
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
do_QueryObject(new LSPAnnotationGatherer());
|
||||
NS_NewThread(getter_AddRefs(thread), runnable);
|
||||
}
|
||||
|
||||
} // namespace crashreporter
|
||||
} // namespace mozilla
|
||||
31
widget/windows/PCompositorWidget.ipdl
Normal file
31
widget/windows/PCompositorWidget.ipdl
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* 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 protocol PCompositorBridge;
|
||||
|
||||
using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
sync protocol PCompositorWidget
|
||||
{
|
||||
manager PCompositorBridge;
|
||||
|
||||
parent:
|
||||
sync EnterPresentLock();
|
||||
sync LeavePresentLock();
|
||||
async UpdateTransparency(int32_t aMode);
|
||||
sync ClearTransparentWindow();
|
||||
async __delete__();
|
||||
|
||||
child:
|
||||
async ObserveVsync();
|
||||
async UnobserveVsync();
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
23
widget/windows/PlatformWidgetTypes.ipdlh
Normal file
23
widget/windows/PlatformWidgetTypes.ipdlh
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* 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/. */
|
||||
|
||||
// This file is a stub, for platforms that do not yet support out-of-process
|
||||
// compositing or do not need specialized types to do so.
|
||||
|
||||
using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
struct CompositorWidgetInitData
|
||||
{
|
||||
WindowsHandle hWnd;
|
||||
uintptr_t widgetKey;
|
||||
int32_t transparencyMode;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
6423
widget/windows/TSFTextStore.cpp
Normal file
6423
widget/windows/TSFTextStore.cpp
Normal file
File diff suppressed because it is too large
Load diff
1045
widget/windows/TSFTextStore.h
Normal file
1045
widget/windows/TSFTextStore.h
Normal file
File diff suppressed because it is too large
Load diff
431
widget/windows/TaskbarPreview.cpp
Normal file
431
widget/windows/TaskbarPreview.cpp
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
/* 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 "TaskbarPreview.h"
|
||||
#include <nsITaskbarPreviewController.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <nsError.h>
|
||||
#include <nsCOMPtr.h>
|
||||
#include <nsIWidget.h>
|
||||
#include <nsIBaseWindow.h>
|
||||
#include <nsIObserverService.h>
|
||||
#include <nsServiceManagerUtils.h>
|
||||
|
||||
#include "nsUXThemeData.h"
|
||||
#include "nsWindow.h"
|
||||
#include "nsAppShell.h"
|
||||
#include "TaskbarPreviewButton.h"
|
||||
#include "WinUtils.h"
|
||||
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
// Defined in dwmapi in a header that needs a higher numbered _WINNT #define
|
||||
#define DWM_SIT_DISPLAYFRAME 0x1
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TaskbarPreview
|
||||
|
||||
TaskbarPreview::TaskbarPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
|
||||
: mTaskbar(aTaskbar),
|
||||
mController(aController),
|
||||
mWnd(aHWND),
|
||||
mVisible(false),
|
||||
mDocShell(do_GetWeakReference(aShell))
|
||||
{
|
||||
// TaskbarPreview may outlive the WinTaskbar that created it
|
||||
::CoInitialize(nullptr);
|
||||
|
||||
WindowHook &hook = GetWindowHook();
|
||||
hook.AddMonitor(WM_DESTROY, MainWindowHook, this);
|
||||
}
|
||||
|
||||
TaskbarPreview::~TaskbarPreview() {
|
||||
// Avoid dangling pointer
|
||||
if (sActivePreview == this)
|
||||
sActivePreview = nullptr;
|
||||
|
||||
// Our subclass should have invoked DetachFromNSWindow already.
|
||||
NS_ASSERTION(!mWnd, "TaskbarPreview::DetachFromNSWindow was not called before destruction");
|
||||
|
||||
// Make sure to release before potentially uninitializing COM
|
||||
mTaskbar = nullptr;
|
||||
|
||||
::CoUninitialize();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreview::SetController(nsITaskbarPreviewController *aController) {
|
||||
NS_ENSURE_ARG(aController);
|
||||
|
||||
mController = aController;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreview::GetController(nsITaskbarPreviewController **aController) {
|
||||
NS_ADDREF(*aController = mController);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreview::GetTooltip(nsAString &aTooltip) {
|
||||
aTooltip = mTooltip;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreview::SetTooltip(const nsAString &aTooltip) {
|
||||
mTooltip = aTooltip;
|
||||
return CanMakeTaskbarCalls() ? UpdateTooltip() : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreview::SetVisible(bool visible) {
|
||||
if (mVisible == visible) return NS_OK;
|
||||
mVisible = visible;
|
||||
|
||||
// If the nsWindow has already been destroyed but the caller is still trying
|
||||
// to use it then just pretend that everything succeeded. The caller doesn't
|
||||
// actually have a way to detect this since it's the same case as when we
|
||||
// CanMakeTaskbarCalls returns false.
|
||||
if (!mWnd)
|
||||
return NS_OK;
|
||||
|
||||
return visible ? Enable() : Disable();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreview::GetVisible(bool *visible) {
|
||||
*visible = mVisible;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreview::SetActive(bool active) {
|
||||
if (active)
|
||||
sActivePreview = this;
|
||||
else if (sActivePreview == this)
|
||||
sActivePreview = nullptr;
|
||||
|
||||
return CanMakeTaskbarCalls() ? ShowActive(active) : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreview::GetActive(bool *active) {
|
||||
*active = sActivePreview == this;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreview::Invalidate() {
|
||||
if (!mVisible)
|
||||
return NS_OK;
|
||||
|
||||
// DWM Composition is required for previews
|
||||
if (!nsUXThemeData::CheckForCompositor())
|
||||
return NS_OK;
|
||||
|
||||
HWND previewWindow = PreviewWindow();
|
||||
return FAILED(WinUtils::dwmInvalidateIconicBitmapsPtr(previewWindow))
|
||||
? NS_ERROR_FAILURE
|
||||
: NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarPreview::UpdateTaskbarProperties() {
|
||||
nsresult rv = UpdateTooltip();
|
||||
|
||||
// If we are the active preview and our window is the active window, restore
|
||||
// our active state - otherwise some other non-preview window is now active
|
||||
// and should be displayed as so.
|
||||
if (sActivePreview == this) {
|
||||
if (mWnd == ::GetActiveWindow()) {
|
||||
nsresult rvActive = ShowActive(true);
|
||||
if (NS_FAILED(rvActive))
|
||||
rv = rvActive;
|
||||
} else {
|
||||
sActivePreview = nullptr;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarPreview::Enable() {
|
||||
nsresult rv = NS_OK;
|
||||
if (CanMakeTaskbarCalls()) {
|
||||
rv = UpdateTaskbarProperties();
|
||||
} else {
|
||||
WindowHook &hook = GetWindowHook();
|
||||
hook.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(), MainWindowHook, this);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarPreview::Disable() {
|
||||
if (!IsWindowAvailable()) {
|
||||
// Window is already destroyed
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
WindowHook &hook = GetWindowHook();
|
||||
(void) hook.RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(), MainWindowHook, this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
TaskbarPreview::IsWindowAvailable() const {
|
||||
if (mWnd) {
|
||||
nsWindow* win = WinUtils::GetNSWindowPtr(mWnd);
|
||||
if(win && !win->Destroyed()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
TaskbarPreview::DetachFromNSWindow() {
|
||||
WindowHook &hook = GetWindowHook();
|
||||
hook.RemoveMonitor(WM_DESTROY, MainWindowHook, this);
|
||||
mWnd = nullptr;
|
||||
}
|
||||
|
||||
LRESULT
|
||||
TaskbarPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (nMsg) {
|
||||
case WM_DWMSENDICONICTHUMBNAIL:
|
||||
{
|
||||
uint32_t width = HIWORD(lParam);
|
||||
uint32_t height = LOWORD(lParam);
|
||||
float aspectRatio = width/float(height);
|
||||
|
||||
nsresult rv;
|
||||
float preferredAspectRatio;
|
||||
rv = mController->GetThumbnailAspectRatio(&preferredAspectRatio);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
uint32_t thumbnailWidth = width;
|
||||
uint32_t thumbnailHeight = height;
|
||||
|
||||
if (aspectRatio > preferredAspectRatio) {
|
||||
thumbnailWidth = uint32_t(thumbnailHeight * preferredAspectRatio);
|
||||
} else {
|
||||
thumbnailHeight = uint32_t(thumbnailWidth / preferredAspectRatio);
|
||||
}
|
||||
|
||||
DrawBitmap(thumbnailWidth, thumbnailHeight, false);
|
||||
}
|
||||
break;
|
||||
case WM_DWMSENDICONICLIVEPREVIEWBITMAP:
|
||||
{
|
||||
uint32_t width, height;
|
||||
nsresult rv;
|
||||
rv = mController->GetWidth(&width);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
rv = mController->GetHeight(&height);
|
||||
if (NS_FAILED(rv))
|
||||
break;
|
||||
|
||||
double scale = nsIWidget::DefaultScaleOverride();
|
||||
if (scale <= 0.0) {
|
||||
scale = WinUtils::LogToPhysFactor(PreviewWindow());
|
||||
}
|
||||
DrawBitmap(NSToIntRound(scale * width), NSToIntRound(scale * height), true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ::DefWindowProcW(PreviewWindow(), nMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
bool
|
||||
TaskbarPreview::CanMakeTaskbarCalls() {
|
||||
// If the nsWindow has already been destroyed and we know it but our caller
|
||||
// clearly doesn't so we can't make any calls.
|
||||
if (!mWnd)
|
||||
return false;
|
||||
// Certain functions like SetTabOrder seem to require a visible window. During
|
||||
// window close, the window seems to be hidden before being destroyed.
|
||||
if (!::IsWindowVisible(mWnd))
|
||||
return false;
|
||||
if (mVisible) {
|
||||
nsWindow *window = WinUtils::GetNSWindowPtr(mWnd);
|
||||
NS_ASSERTION(window, "Could not get nsWindow from HWND");
|
||||
return window->HasTaskbarIconBeenCreated();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
WindowHook&
|
||||
TaskbarPreview::GetWindowHook() {
|
||||
nsWindow *window = WinUtils::GetNSWindowPtr(mWnd);
|
||||
NS_ASSERTION(window, "Cannot use taskbar previews in an embedded context!");
|
||||
|
||||
return window->GetWindowHook();
|
||||
}
|
||||
|
||||
void
|
||||
TaskbarPreview::EnableCustomDrawing(HWND aHWND, bool aEnable) {
|
||||
BOOL enabled = aEnable;
|
||||
WinUtils::dwmSetWindowAttributePtr(
|
||||
aHWND,
|
||||
DWMWA_FORCE_ICONIC_REPRESENTATION,
|
||||
&enabled,
|
||||
sizeof(enabled));
|
||||
|
||||
WinUtils::dwmSetWindowAttributePtr(
|
||||
aHWND,
|
||||
DWMWA_HAS_ICONIC_BITMAP,
|
||||
&enabled,
|
||||
sizeof(enabled));
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
TaskbarPreview::UpdateTooltip() {
|
||||
NS_ASSERTION(CanMakeTaskbarCalls() && mVisible, "UpdateTooltip called on invisible tab preview");
|
||||
|
||||
if (FAILED(mTaskbar->SetThumbnailTooltip(PreviewWindow(), mTooltip.get())))
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
TaskbarPreview::DrawBitmap(uint32_t width, uint32_t height, bool isPreview) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsITaskbarPreviewCallback> callback =
|
||||
do_CreateInstance("@mozilla.org/widget/taskbar-preview-callback;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
((TaskbarPreviewCallback*)callback.get())->SetPreview(this);
|
||||
|
||||
if (isPreview) {
|
||||
((TaskbarPreviewCallback*)callback.get())->SetIsPreview();
|
||||
mController->RequestPreview(callback);
|
||||
} else {
|
||||
mController->RequestThumbnail(callback, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TaskbarPreviewCallback
|
||||
|
||||
NS_IMPL_ISUPPORTS(TaskbarPreviewCallback, nsITaskbarPreviewCallback)
|
||||
|
||||
/* void done (in nsISupports aCanvas, in boolean aDrawBorder); */
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewCallback::Done(nsISupports *aCanvas, bool aDrawBorder) {
|
||||
// We create and destroy TaskbarTabPreviews from front end code in response
|
||||
// to TabOpen and TabClose events. Each TaskbarTabPreview creates and owns a
|
||||
// proxy HWND which it hands to Windows as a tab identifier. When a tab
|
||||
// closes, TaskbarTabPreview Disable() method is called by front end, which
|
||||
// destroys the proxy window and clears mProxyWindow which is the HWND
|
||||
// returned from PreviewWindow(). So, since this is async, we should check to
|
||||
// be sure the tab is still alive before doing all this gfx work and making
|
||||
// dwm calls. To accomplish this we check the result of PreviewWindow().
|
||||
if (!aCanvas || !mPreview || !mPreview->PreviewWindow() ||
|
||||
!mPreview->IsWindowAvailable()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLCanvasElement> domcanvas(do_QueryInterface(aCanvas));
|
||||
dom::HTMLCanvasElement * canvas = ((dom::HTMLCanvasElement*)domcanvas.get());
|
||||
if (!canvas) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<gfx::SourceSurface> source = canvas->GetSurfaceSnapshot();
|
||||
if (!source) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
RefPtr<gfxWindowsSurface> target = new gfxWindowsSurface(source->GetSize(),
|
||||
gfx::SurfaceFormat::A8R8G8B8_UINT32);
|
||||
if (!target) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> srcSurface = source->GetDataSurface();
|
||||
RefPtr<gfxImageSurface> imageSurface = target->GetAsImageSurface();
|
||||
if (!srcSurface || !imageSurface) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
gfx::DataSourceSurface::MappedSurface sourceMap;
|
||||
srcSurface->Map(gfx::DataSourceSurface::READ, &sourceMap);
|
||||
mozilla::gfx::CopySurfaceDataToPackedArray(sourceMap.mData,
|
||||
imageSurface->Data(),
|
||||
srcSurface->GetSize(),
|
||||
sourceMap.mStride,
|
||||
BytesPerPixel(srcSurface->GetFormat()));
|
||||
srcSurface->Unmap();
|
||||
|
||||
HDC hDC = target->GetDC();
|
||||
HBITMAP hBitmap = (HBITMAP)GetCurrentObject(hDC, OBJ_BITMAP);
|
||||
|
||||
DWORD flags = aDrawBorder ? DWM_SIT_DISPLAYFRAME : 0;
|
||||
POINT pptClient = { 0, 0 };
|
||||
HRESULT hr;
|
||||
if (!mIsThumbnail) {
|
||||
hr = WinUtils::dwmSetIconicLivePreviewBitmapPtr(mPreview->PreviewWindow(),
|
||||
hBitmap, &pptClient, flags);
|
||||
} else {
|
||||
hr = WinUtils::dwmSetIconicThumbnailPtr(mPreview->PreviewWindow(),
|
||||
hBitmap, flags);
|
||||
}
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
TaskbarPreview::MainWindowHook(void *aContext,
|
||||
HWND hWnd, UINT nMsg,
|
||||
WPARAM wParam, LPARAM lParam,
|
||||
LRESULT *aResult)
|
||||
{
|
||||
NS_ASSERTION(nMsg == nsAppShell::GetTaskbarButtonCreatedMessage() ||
|
||||
nMsg == WM_DESTROY,
|
||||
"Window hook proc called with wrong message");
|
||||
NS_ASSERTION(aContext, "Null context in MainWindowHook");
|
||||
if (!aContext)
|
||||
return false;
|
||||
TaskbarPreview *preview = reinterpret_cast<TaskbarPreview*>(aContext);
|
||||
if (nMsg == WM_DESTROY) {
|
||||
// nsWindow is being destroyed
|
||||
// We can't really do anything at this point including removing hooks
|
||||
return false;
|
||||
} else {
|
||||
nsWindow *window = WinUtils::GetNSWindowPtr(preview->mWnd);
|
||||
if (window) {
|
||||
window->SetHasTaskbarIconBeenCreated();
|
||||
|
||||
if (preview->mVisible)
|
||||
preview->UpdateTaskbarProperties();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TaskbarPreview *
|
||||
TaskbarPreview::sActivePreview = nullptr;
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
140
widget/windows/TaskbarPreview.h
Normal file
140
widget/windows/TaskbarPreview.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef __mozilla_widget_TaskbarPreview_h__
|
||||
#define __mozilla_widget_TaskbarPreview_h__
|
||||
|
||||
#include <windows.h>
|
||||
#include <shobjidl.h>
|
||||
#undef LogSeverity // SetupAPI.h #defines this as DWORD
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include <nsITaskbarPreview.h>
|
||||
#include <nsITaskbarPreviewController.h>
|
||||
#include <nsString.h>
|
||||
#include <nsWeakPtr.h>
|
||||
#include <nsIDocShell.h>
|
||||
#include "WindowHook.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class TaskbarPreviewCallback;
|
||||
|
||||
class TaskbarPreview : public nsITaskbarPreview
|
||||
{
|
||||
public:
|
||||
TaskbarPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
|
||||
|
||||
friend class TaskbarPreviewCallback;
|
||||
|
||||
NS_DECL_NSITASKBARPREVIEW
|
||||
|
||||
protected:
|
||||
virtual ~TaskbarPreview();
|
||||
|
||||
// Called to update ITaskbarList4 dependent properties
|
||||
virtual nsresult UpdateTaskbarProperties();
|
||||
|
||||
// Invoked when the preview is made visible
|
||||
virtual nsresult Enable();
|
||||
// Invoked when the preview is made invisible
|
||||
virtual nsresult Disable();
|
||||
|
||||
// Detaches this preview from the nsWindow instance it's tied to
|
||||
virtual void DetachFromNSWindow();
|
||||
|
||||
// Determines if the window is available and a destroy has not yet started
|
||||
bool IsWindowAvailable() const;
|
||||
|
||||
// Marks this preview as being active
|
||||
virtual nsresult ShowActive(bool active) = 0;
|
||||
// Gets a reference to the window used to handle the preview messages
|
||||
virtual HWND& PreviewWindow() = 0;
|
||||
|
||||
// Window procedure for the PreviewWindow (hooked for window previews)
|
||||
virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
// Returns whether or not the taskbar icon has been created for mWnd The
|
||||
// ITaskbarList4 API requires that we wait until the icon has been created
|
||||
// before we can call its methods.
|
||||
bool CanMakeTaskbarCalls();
|
||||
|
||||
// Gets the WindowHook for the nsWindow
|
||||
WindowHook &GetWindowHook();
|
||||
|
||||
// Enables/disables custom drawing for the given window
|
||||
static void EnableCustomDrawing(HWND aHWND, bool aEnable);
|
||||
|
||||
// MSCOM Taskbar interface
|
||||
RefPtr<ITaskbarList4> mTaskbar;
|
||||
// Controller for this preview
|
||||
nsCOMPtr<nsITaskbarPreviewController> mController;
|
||||
// The HWND to the nsWindow that this object previews
|
||||
HWND mWnd;
|
||||
// Whether or not this preview is visible
|
||||
bool mVisible;
|
||||
|
||||
private:
|
||||
// Called when the tooltip should be updated
|
||||
nsresult UpdateTooltip();
|
||||
|
||||
// Requests the controller to draw into a canvas of the given width and
|
||||
// height. The resulting bitmap is sent to the DWM to display.
|
||||
void DrawBitmap(uint32_t width, uint32_t height, bool isPreview);
|
||||
|
||||
// WindowHook procedure for hooking mWnd
|
||||
static bool MainWindowHook(void *aContext,
|
||||
HWND hWnd, UINT nMsg,
|
||||
WPARAM wParam, LPARAM lParam,
|
||||
LRESULT *aResult);
|
||||
|
||||
// Docshell corresponding to the <window> the nsWindow contains
|
||||
nsWeakPtr mDocShell;
|
||||
nsString mTooltip;
|
||||
|
||||
// The preview currently marked as active in the taskbar. nullptr if no
|
||||
// preview is active (some other window is).
|
||||
static TaskbarPreview *sActivePreview;
|
||||
};
|
||||
|
||||
/*
|
||||
* Callback object TaskbarPreview hands to preview controllers when we
|
||||
* request async thumbnail or live preview images. Controllers invoke
|
||||
* this interface once they have aquired the requested image.
|
||||
*/
|
||||
class TaskbarPreviewCallback : public nsITaskbarPreviewCallback
|
||||
{
|
||||
public:
|
||||
TaskbarPreviewCallback() :
|
||||
mIsThumbnail(true) {
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITASKBARPREVIEWCALLBACK
|
||||
|
||||
void SetPreview(TaskbarPreview* aPreview) {
|
||||
mPreview = aPreview;
|
||||
}
|
||||
|
||||
void SetIsPreview() {
|
||||
mIsThumbnail = false;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~TaskbarPreviewCallback() {}
|
||||
|
||||
private:
|
||||
RefPtr<TaskbarPreview> mPreview;
|
||||
bool mIsThumbnail;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __mozilla_widget_TaskbarPreview_h__ */
|
||||
|
||||
145
widget/windows/TaskbarPreviewButton.cpp
Normal file
145
widget/windows/TaskbarPreviewButton.cpp
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/* 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 <windows.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "TaskbarWindowPreview.h"
|
||||
#include "TaskbarPreviewButton.h"
|
||||
#include "nsWindowGfx.h"
|
||||
#include <imgIContainer.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
NS_IMPL_ISUPPORTS(TaskbarPreviewButton, nsITaskbarPreviewButton, nsISupportsWeakReference)
|
||||
|
||||
TaskbarPreviewButton::TaskbarPreviewButton(TaskbarWindowPreview* preview, uint32_t index)
|
||||
: mPreview(preview), mIndex(index)
|
||||
{
|
||||
}
|
||||
|
||||
TaskbarPreviewButton::~TaskbarPreviewButton() {
|
||||
SetVisible(false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::GetTooltip(nsAString &aTooltip) {
|
||||
aTooltip = mTooltip;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::SetTooltip(const nsAString &aTooltip) {
|
||||
mTooltip = aTooltip;
|
||||
size_t destLength = sizeof Button().szTip / (sizeof Button().szTip[0]);
|
||||
wchar_t *tooltip = &(Button().szTip[0]);
|
||||
StringCchCopyNW(tooltip,
|
||||
destLength,
|
||||
mTooltip.get(),
|
||||
mTooltip.Length());
|
||||
return Update();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::GetDismissOnClick(bool *dismiss) {
|
||||
*dismiss = (Button().dwFlags & THBF_DISMISSONCLICK) == THBF_DISMISSONCLICK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::SetDismissOnClick(bool dismiss) {
|
||||
if (dismiss)
|
||||
Button().dwFlags |= THBF_DISMISSONCLICK;
|
||||
else
|
||||
Button().dwFlags &= ~THBF_DISMISSONCLICK;
|
||||
return Update();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::GetHasBorder(bool *hasBorder) {
|
||||
*hasBorder = (Button().dwFlags & THBF_NOBACKGROUND) != THBF_NOBACKGROUND;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::SetHasBorder(bool hasBorder) {
|
||||
if (hasBorder)
|
||||
Button().dwFlags &= ~THBF_NOBACKGROUND;
|
||||
else
|
||||
Button().dwFlags |= THBF_NOBACKGROUND;
|
||||
return Update();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::GetDisabled(bool *disabled) {
|
||||
*disabled = (Button().dwFlags & THBF_DISABLED) == THBF_DISABLED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::SetDisabled(bool disabled) {
|
||||
if (disabled)
|
||||
Button().dwFlags |= THBF_DISABLED;
|
||||
else
|
||||
Button().dwFlags &= ~THBF_DISABLED;
|
||||
return Update();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::GetImage(imgIContainer **img) {
|
||||
if (mImage)
|
||||
NS_ADDREF(*img = mImage);
|
||||
else
|
||||
*img = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::SetImage(imgIContainer *img) {
|
||||
if (Button().hIcon)
|
||||
::DestroyIcon(Button().hIcon);
|
||||
if (img) {
|
||||
nsresult rv;
|
||||
rv = nsWindowGfx::CreateIcon(img, false, 0, 0,
|
||||
nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon),
|
||||
&Button().hIcon);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
Button().hIcon = nullptr;
|
||||
}
|
||||
return Update();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::GetVisible(bool *visible) {
|
||||
*visible = (Button().dwFlags & THBF_HIDDEN) != THBF_HIDDEN;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarPreviewButton::SetVisible(bool visible) {
|
||||
if (visible)
|
||||
Button().dwFlags &= ~THBF_HIDDEN;
|
||||
else
|
||||
Button().dwFlags |= THBF_HIDDEN;
|
||||
return Update();
|
||||
}
|
||||
|
||||
THUMBBUTTON&
|
||||
TaskbarPreviewButton::Button() {
|
||||
return mPreview->mThumbButtons[mIndex];
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarPreviewButton::Update() {
|
||||
return mPreview->UpdateButton(mIndex);
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
48
widget/windows/TaskbarPreviewButton.h
Normal file
48
widget/windows/TaskbarPreviewButton.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef __mozilla_widget_TaskbarPreviewButton_h__
|
||||
#define __mozilla_widget_TaskbarPreviewButton_h__
|
||||
|
||||
#include <windows.h>
|
||||
#include <shobjidl.h>
|
||||
#undef LogSeverity // SetupAPI.h #defines this as DWORD
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include <nsITaskbarPreviewButton.h>
|
||||
#include <nsString.h>
|
||||
#include <nsWeakReference.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class TaskbarWindowPreview;
|
||||
class TaskbarPreviewButton : public nsITaskbarPreviewButton, public nsSupportsWeakReference
|
||||
{
|
||||
virtual ~TaskbarPreviewButton();
|
||||
|
||||
public:
|
||||
TaskbarPreviewButton(TaskbarWindowPreview* preview, uint32_t index);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITASKBARPREVIEWBUTTON
|
||||
|
||||
private:
|
||||
THUMBBUTTON& Button();
|
||||
nsresult Update();
|
||||
|
||||
RefPtr<TaskbarWindowPreview> mPreview;
|
||||
uint32_t mIndex;
|
||||
nsString mTooltip;
|
||||
nsCOMPtr<imgIContainer> mImage;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __mozilla_widget_TaskbarPreviewButton_h__ */
|
||||
|
||||
357
widget/windows/TaskbarTabPreview.cpp
Normal file
357
widget/windows/TaskbarTabPreview.cpp
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
/* 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 {
|
||||
NS_NOTREACHED("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
|
||||
|
||||
70
widget/windows/TaskbarTabPreview.h
Normal file
70
widget/windows/TaskbarTabPreview.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef __mozilla_widget_TaskbarTabPreview_h__
|
||||
#define __mozilla_widget_TaskbarTabPreview_h__
|
||||
|
||||
#include "nsITaskbarTabPreview.h"
|
||||
#include "TaskbarPreview.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class TaskbarTabPreview : public nsITaskbarTabPreview,
|
||||
public TaskbarPreview
|
||||
{
|
||||
virtual ~TaskbarTabPreview();
|
||||
|
||||
public:
|
||||
TaskbarTabPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITASKBARTABPREVIEW
|
||||
NS_FORWARD_NSITASKBARPREVIEW(TaskbarPreview::)
|
||||
|
||||
private:
|
||||
virtual nsresult ShowActive(bool active);
|
||||
virtual HWND &PreviewWindow();
|
||||
virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
|
||||
static LRESULT CALLBACK GlobalWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
virtual nsresult UpdateTaskbarProperties();
|
||||
virtual nsresult Enable();
|
||||
virtual nsresult Disable();
|
||||
virtual void DetachFromNSWindow();
|
||||
|
||||
// WindowHook procedure for hooking mWnd
|
||||
static bool MainWindowHook(void *aContext,
|
||||
HWND hWnd, UINT nMsg,
|
||||
WPARAM wParam, LPARAM lParam,
|
||||
LRESULT *aResult);
|
||||
|
||||
// Bug 520807 - we need to update the proxy window style based on the main
|
||||
// window's style to workaround a bug with the way the DWM displays the
|
||||
// previews.
|
||||
void UpdateProxyWindowStyle();
|
||||
|
||||
nsresult UpdateTitle();
|
||||
nsresult UpdateIcon();
|
||||
nsresult UpdateNext();
|
||||
|
||||
// Handle to the toplevel proxy window
|
||||
HWND mProxyWindow;
|
||||
nsString mTitle;
|
||||
nsCOMPtr<imgIContainer> mIconImage;
|
||||
// Cached Windows icon of mIconImage
|
||||
HICON mIcon;
|
||||
// Preview that follows this preview in the taskbar (left-to-right order)
|
||||
nsCOMPtr<nsITaskbarTabPreview> mNext;
|
||||
// True if this preview has been registered with the taskbar
|
||||
bool mRegistered;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __mozilla_widget_TaskbarTabPreview_h__ */
|
||||
326
widget/windows/TaskbarWindowPreview.cpp
Normal file
326
widget/windows/TaskbarWindowPreview.cpp
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/* 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 "mozilla/ArrayUtils.h"
|
||||
|
||||
#include <nsITaskbarPreviewController.h>
|
||||
#include "TaskbarWindowPreview.h"
|
||||
#include "WindowHook.h"
|
||||
#include "nsUXThemeData.h"
|
||||
#include "TaskbarPreviewButton.h"
|
||||
#include "nsWindow.h"
|
||||
#include "nsWindowGfx.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
namespace {
|
||||
bool WindowHookProc(void *aContext, HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT *aResult)
|
||||
{
|
||||
TaskbarWindowPreview *preview = reinterpret_cast<TaskbarWindowPreview*>(aContext);
|
||||
*aResult = preview->WndProc(nMsg, wParam, lParam);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(TaskbarWindowPreview, nsITaskbarWindowPreview,
|
||||
nsITaskbarProgress, nsITaskbarOverlayIconController,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
/**
|
||||
* These correspond directly to the states defined in nsITaskbarProgress.idl, so
|
||||
* they should be kept in sync.
|
||||
*/
|
||||
static TBPFLAG sNativeStates[] =
|
||||
{
|
||||
TBPF_NOPROGRESS,
|
||||
TBPF_INDETERMINATE,
|
||||
TBPF_NORMAL,
|
||||
TBPF_ERROR,
|
||||
TBPF_PAUSED
|
||||
};
|
||||
|
||||
TaskbarWindowPreview::TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
|
||||
: TaskbarPreview(aTaskbar, aController, aHWND, aShell),
|
||||
mCustomDrawing(false),
|
||||
mHaveButtons(false),
|
||||
mState(TBPF_NOPROGRESS),
|
||||
mCurrentValue(0),
|
||||
mMaxValue(0),
|
||||
mOverlayIcon(nullptr)
|
||||
{
|
||||
// Window previews are visible by default
|
||||
(void) SetVisible(true);
|
||||
|
||||
memset(mThumbButtons, 0, sizeof mThumbButtons);
|
||||
for (int32_t i = 0; i < nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS; i++) {
|
||||
mThumbButtons[i].dwMask = THB_FLAGS | THB_ICON | THB_TOOLTIP;
|
||||
mThumbButtons[i].iId = i;
|
||||
mThumbButtons[i].dwFlags = THBF_HIDDEN;
|
||||
}
|
||||
|
||||
WindowHook &hook = GetWindowHook();
|
||||
if (!CanMakeTaskbarCalls())
|
||||
hook.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
|
||||
TaskbarWindowHook, this);
|
||||
}
|
||||
|
||||
TaskbarWindowPreview::~TaskbarWindowPreview() {
|
||||
if (mOverlayIcon) {
|
||||
::DestroyIcon(mOverlayIcon);
|
||||
mOverlayIcon = nullptr;
|
||||
}
|
||||
|
||||
if (IsWindowAvailable()) {
|
||||
DetachFromNSWindow();
|
||||
} else {
|
||||
mWnd = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarWindowPreview::ShowActive(bool active) {
|
||||
return FAILED(mTaskbar->ActivateTab(active ? mWnd : nullptr))
|
||||
? NS_ERROR_FAILURE
|
||||
: NS_OK;
|
||||
|
||||
}
|
||||
|
||||
HWND &
|
||||
TaskbarWindowPreview::PreviewWindow() {
|
||||
return mWnd;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarWindowPreview::GetButton(uint32_t index, nsITaskbarPreviewButton **_retVal) {
|
||||
if (index >= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCOMPtr<nsITaskbarPreviewButton> button(do_QueryReferent(mWeakButtons[index]));
|
||||
|
||||
if (!button) {
|
||||
// Lost reference
|
||||
button = new TaskbarPreviewButton(this, index);
|
||||
if (!button) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mWeakButtons[index] = do_GetWeakReference(button);
|
||||
}
|
||||
|
||||
if (!mHaveButtons) {
|
||||
mHaveButtons = true;
|
||||
|
||||
WindowHook &hook = GetWindowHook();
|
||||
(void) hook.AddHook(WM_COMMAND, WindowHookProc, this);
|
||||
|
||||
if (mVisible && FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
button.forget(_retVal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarWindowPreview::SetEnableCustomDrawing(bool aEnable) {
|
||||
if (aEnable == mCustomDrawing)
|
||||
return NS_OK;
|
||||
mCustomDrawing = aEnable;
|
||||
TaskbarPreview::EnableCustomDrawing(mWnd, aEnable);
|
||||
|
||||
WindowHook &hook = GetWindowHook();
|
||||
if (aEnable) {
|
||||
(void) hook.AddHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this);
|
||||
(void) hook.AddHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this);
|
||||
} else {
|
||||
(void) hook.RemoveHook(WM_DWMSENDICONICLIVEPREVIEWBITMAP, WindowHookProc, this);
|
||||
(void) hook.RemoveHook(WM_DWMSENDICONICTHUMBNAIL, WindowHookProc, this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarWindowPreview::GetEnableCustomDrawing(bool *aEnable) {
|
||||
*aEnable = mCustomDrawing;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarWindowPreview::SetProgressState(nsTaskbarProgressState aState,
|
||||
uint64_t aCurrentValue,
|
||||
uint64_t aMaxValue)
|
||||
{
|
||||
NS_ENSURE_ARG_RANGE(aState,
|
||||
nsTaskbarProgressState(0),
|
||||
nsTaskbarProgressState(ArrayLength(sNativeStates) - 1));
|
||||
|
||||
TBPFLAG nativeState = sNativeStates[aState];
|
||||
if (nativeState == TBPF_NOPROGRESS || nativeState == TBPF_INDETERMINATE) {
|
||||
NS_ENSURE_TRUE(aCurrentValue == 0, NS_ERROR_INVALID_ARG);
|
||||
NS_ENSURE_TRUE(aMaxValue == 0, NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
|
||||
if (aCurrentValue > aMaxValue)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
mState = nativeState;
|
||||
mCurrentValue = aCurrentValue;
|
||||
mMaxValue = aMaxValue;
|
||||
|
||||
// Only update if we can
|
||||
return CanMakeTaskbarCalls() ? UpdateTaskbarProgress() : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TaskbarWindowPreview::SetOverlayIcon(imgIContainer* aStatusIcon,
|
||||
const nsAString& aStatusDescription) {
|
||||
nsresult rv;
|
||||
if (aStatusIcon) {
|
||||
// The image shouldn't be animated
|
||||
bool isAnimated;
|
||||
rv = aStatusIcon->GetAnimated(&isAnimated);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_FALSE(isAnimated, NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
|
||||
HICON hIcon = nullptr;
|
||||
if (aStatusIcon) {
|
||||
rv = nsWindowGfx::CreateIcon(aStatusIcon, false, 0, 0,
|
||||
nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon),
|
||||
&hIcon);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (mOverlayIcon)
|
||||
::DestroyIcon(mOverlayIcon);
|
||||
mOverlayIcon = hIcon;
|
||||
mIconDescription = aStatusDescription;
|
||||
|
||||
// Only update if we can
|
||||
return CanMakeTaskbarCalls() ? UpdateOverlayIcon() : NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarWindowPreview::UpdateTaskbarProperties() {
|
||||
if (mHaveButtons) {
|
||||
if (FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons)))
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv = UpdateTaskbarProgress();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = UpdateOverlayIcon();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return TaskbarPreview::UpdateTaskbarProperties();
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarWindowPreview::UpdateTaskbarProgress() {
|
||||
HRESULT hr = mTaskbar->SetProgressState(mWnd, mState);
|
||||
if (SUCCEEDED(hr) && mState != TBPF_NOPROGRESS &&
|
||||
mState != TBPF_INDETERMINATE)
|
||||
hr = mTaskbar->SetProgressValue(mWnd, mCurrentValue, mMaxValue);
|
||||
|
||||
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarWindowPreview::UpdateOverlayIcon() {
|
||||
HRESULT hr = mTaskbar->SetOverlayIcon(mWnd, mOverlayIcon,
|
||||
mIconDescription.get());
|
||||
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
LRESULT
|
||||
TaskbarWindowPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
|
||||
RefPtr<TaskbarWindowPreview> kungFuDeathGrip(this);
|
||||
switch (nMsg) {
|
||||
case WM_COMMAND:
|
||||
{
|
||||
uint32_t id = LOWORD(wParam);
|
||||
uint32_t index = id;
|
||||
nsCOMPtr<nsITaskbarPreviewButton> button;
|
||||
nsresult rv = GetButton(index, getter_AddRefs(button));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mController->OnClick(button);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return TaskbarPreview::WndProc(nMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
TaskbarWindowPreview::TaskbarWindowHook(void *aContext,
|
||||
HWND hWnd, UINT nMsg,
|
||||
WPARAM wParam, LPARAM lParam,
|
||||
LRESULT *aResult)
|
||||
{
|
||||
NS_ASSERTION(nMsg == nsAppShell::GetTaskbarButtonCreatedMessage(),
|
||||
"Window hook proc called with wrong message");
|
||||
TaskbarWindowPreview *preview =
|
||||
reinterpret_cast<TaskbarWindowPreview*>(aContext);
|
||||
// Now we can make all the calls to mTaskbar
|
||||
preview->UpdateTaskbarProperties();
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarWindowPreview::Enable() {
|
||||
nsresult rv = TaskbarPreview::Enable();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return FAILED(mTaskbar->AddTab(mWnd))
|
||||
? NS_ERROR_FAILURE
|
||||
: NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarWindowPreview::Disable() {
|
||||
nsresult rv = TaskbarPreview::Disable();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return FAILED(mTaskbar->DeleteTab(mWnd))
|
||||
? NS_ERROR_FAILURE
|
||||
: NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
TaskbarWindowPreview::DetachFromNSWindow() {
|
||||
// Remove the hooks we have for drawing
|
||||
SetEnableCustomDrawing(false);
|
||||
|
||||
WindowHook &hook = GetWindowHook();
|
||||
(void) hook.RemoveHook(WM_COMMAND, WindowHookProc, this);
|
||||
(void) hook.RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
|
||||
TaskbarWindowHook, this);
|
||||
|
||||
TaskbarPreview::DetachFromNSWindow();
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarWindowPreview::UpdateButtons() {
|
||||
NS_ASSERTION(mVisible, "UpdateButtons called on invisible preview");
|
||||
|
||||
if (FAILED(mTaskbar->ThumbBarUpdateButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons)))
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TaskbarWindowPreview::UpdateButton(uint32_t index) {
|
||||
if (index >= nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
if (mVisible) {
|
||||
if (FAILED(mTaskbar->ThumbBarUpdateButtons(mWnd, 1, &mThumbButtons[index])))
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
85
widget/windows/TaskbarWindowPreview.h
Normal file
85
widget/windows/TaskbarWindowPreview.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef __mozilla_widget_TaskbarWindowPreview_h__
|
||||
#define __mozilla_widget_TaskbarWindowPreview_h__
|
||||
|
||||
#include "nsITaskbarWindowPreview.h"
|
||||
#include "nsITaskbarProgress.h"
|
||||
#include "nsITaskbarOverlayIconController.h"
|
||||
#include "TaskbarPreview.h"
|
||||
#include <nsWeakReference.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class TaskbarPreviewButton;
|
||||
class TaskbarWindowPreview : public TaskbarPreview,
|
||||
public nsITaskbarWindowPreview,
|
||||
public nsITaskbarProgress,
|
||||
public nsITaskbarOverlayIconController,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
virtual ~TaskbarWindowPreview();
|
||||
|
||||
public:
|
||||
TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITASKBARWINDOWPREVIEW
|
||||
NS_DECL_NSITASKBARPROGRESS
|
||||
NS_DECL_NSITASKBAROVERLAYICONCONTROLLER
|
||||
NS_FORWARD_NSITASKBARPREVIEW(TaskbarPreview::)
|
||||
|
||||
virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) override;
|
||||
private:
|
||||
virtual nsresult ShowActive(bool active) override;
|
||||
virtual HWND &PreviewWindow() override;
|
||||
|
||||
virtual nsresult UpdateTaskbarProperties() override;
|
||||
virtual nsresult Enable() override;
|
||||
virtual nsresult Disable() override;
|
||||
virtual void DetachFromNSWindow() override;
|
||||
nsresult UpdateButton(uint32_t index);
|
||||
nsresult UpdateButtons();
|
||||
|
||||
// Is custom drawing enabled?
|
||||
bool mCustomDrawing;
|
||||
// Have we made any buttons?
|
||||
bool mHaveButtons;
|
||||
// Windows button format
|
||||
THUMBBUTTON mThumbButtons[nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS];
|
||||
// Pointers to our button class (cached instances)
|
||||
nsWeakPtr mWeakButtons[nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS];
|
||||
|
||||
// Called to update ITaskbarList4 dependent properties
|
||||
nsresult UpdateTaskbarProgress();
|
||||
nsresult UpdateOverlayIcon();
|
||||
|
||||
// The taskbar progress
|
||||
TBPFLAG mState;
|
||||
ULONGLONG mCurrentValue;
|
||||
ULONGLONG mMaxValue;
|
||||
|
||||
// Taskbar overlay icon
|
||||
HICON mOverlayIcon;
|
||||
nsString mIconDescription;
|
||||
|
||||
// WindowHook procedure for hooking mWnd for taskbar progress and icon stuff
|
||||
static bool TaskbarWindowHook(void *aContext,
|
||||
HWND hWnd, UINT nMsg,
|
||||
WPARAM wParam, LPARAM lParam,
|
||||
LRESULT *aResult);
|
||||
|
||||
friend class TaskbarPreviewButton;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __mozilla_widget_TaskbarWindowPreview_h__ */
|
||||
|
||||
132
widget/windows/WidgetTraceEvent.cpp
Normal file
132
widget/windows/WidgetTraceEvent.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* Windows widget support for event loop instrumentation.
|
||||
* See toolkit/xre/EventTracer.cpp for more details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/WidgetTraceEvent.h"
|
||||
#include "nsAppShellCID.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAppShellService.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsWindowDefs.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Used for signaling the background thread from the main thread.
|
||||
HANDLE sEventHandle = nullptr;
|
||||
|
||||
// We need a runnable in order to find the hidden window on the main
|
||||
// thread.
|
||||
class HWNDGetter : public mozilla::Runnable {
|
||||
public:
|
||||
HWNDGetter() : hidden_window_hwnd(nullptr) {
|
||||
MOZ_COUNT_CTOR(HWNDGetter);
|
||||
}
|
||||
~HWNDGetter() {
|
||||
MOZ_COUNT_DTOR(HWNDGetter);
|
||||
}
|
||||
|
||||
HWND hidden_window_hwnd;
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
// Jump through some hoops to locate the hidden window.
|
||||
nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
|
||||
nsCOMPtr<nsIXULWindow> hiddenWindow;
|
||||
|
||||
nsresult rv = appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
rv = hiddenWindow->GetDocShell(getter_AddRefs(docShell));
|
||||
if (NS_FAILED(rv) || !docShell) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
|
||||
|
||||
if (!baseWindow)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
baseWindow->GetMainWidget(getter_AddRefs(widget));
|
||||
|
||||
if (!widget)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
hidden_window_hwnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
HWND GetHiddenWindowHWND()
|
||||
{
|
||||
// Need to dispatch this to the main thread because plenty of
|
||||
// the things it wants to access are main-thread-only.
|
||||
RefPtr<HWNDGetter> getter = new HWNDGetter();
|
||||
NS_DispatchToMainThread(getter, NS_DISPATCH_SYNC);
|
||||
return getter->hidden_window_hwnd;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool InitWidgetTracing()
|
||||
{
|
||||
sEventHandle = CreateEventW(nullptr, FALSE, FALSE, nullptr);
|
||||
return sEventHandle != nullptr;
|
||||
}
|
||||
|
||||
void CleanUpWidgetTracing()
|
||||
{
|
||||
CloseHandle(sEventHandle);
|
||||
sEventHandle = nullptr;
|
||||
}
|
||||
|
||||
// This function is called from the main (UI) thread.
|
||||
void SignalTracerThread()
|
||||
{
|
||||
if (sEventHandle != nullptr)
|
||||
SetEvent(sEventHandle);
|
||||
}
|
||||
|
||||
// This function is called from the background tracer thread.
|
||||
bool FireAndWaitForTracerEvent()
|
||||
{
|
||||
MOZ_ASSERT(sEventHandle, "Tracing not initialized!");
|
||||
|
||||
// First, try to find the hidden window.
|
||||
static HWND hidden_window = nullptr;
|
||||
if (hidden_window == nullptr) {
|
||||
hidden_window = GetHiddenWindowHWND();
|
||||
}
|
||||
|
||||
if (hidden_window == nullptr)
|
||||
return false;
|
||||
|
||||
// Post the tracer message into the hidden window's message queue,
|
||||
// and then block until it's processed.
|
||||
PostMessage(hidden_window, MOZ_WM_TRACE, 0, 0);
|
||||
WaitForSingleObject(sEventHandle, INFINITE);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
329
widget/windows/WinCompositorWidget.cpp
Normal file
329
widget/windows/WinCompositorWidget.cpp
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
/* -*- 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 "WinCompositorWidget.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/layers/Compositor.h"
|
||||
#include "mozilla/widget/PlatformWidgetTypes.h"
|
||||
#include "nsWindow.h"
|
||||
#include "VsyncDispatcher.h"
|
||||
|
||||
#include <ddraw.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
WinCompositorWidget::WinCompositorWidget(const CompositorWidgetInitData& aInitData)
|
||||
: mWidgetKey(aInitData.widgetKey()),
|
||||
mWnd(reinterpret_cast<HWND>(aInitData.hWnd())),
|
||||
mTransparencyMode(static_cast<nsTransparencyMode>(aInitData.transparencyMode())),
|
||||
mMemoryDC(nullptr),
|
||||
mCompositeDC(nullptr),
|
||||
mLockedBackBufferData(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
|
||||
|
||||
// mNotDeferEndRemoteDrawing is set on the main thread during init,
|
||||
// but is only accessed after on the compositor thread.
|
||||
mNotDeferEndRemoteDrawing = gfxPrefs::LayersCompositionFrameRate() == 0 ||
|
||||
gfxPlatform::IsInLayoutAsapMode() ||
|
||||
gfxPlatform::ForceSoftwareVsync();
|
||||
}
|
||||
|
||||
void
|
||||
WinCompositorWidget::OnDestroyWindow()
|
||||
{
|
||||
mTransparentSurface = nullptr;
|
||||
mMemoryDC = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
WinCompositorWidget::PreRender(WidgetRenderingContext* aContext)
|
||||
{
|
||||
// This can block waiting for WM_SETTEXT to finish
|
||||
// Using PreRender is unnecessarily pessimistic because
|
||||
// we technically only need to block during the present call
|
||||
// not all of compositor rendering
|
||||
mPresentLock.Enter();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WinCompositorWidget::PostRender(WidgetRenderingContext* aContext)
|
||||
{
|
||||
mPresentLock.Leave();
|
||||
}
|
||||
|
||||
LayoutDeviceIntSize
|
||||
WinCompositorWidget::GetClientSize()
|
||||
{
|
||||
RECT r;
|
||||
if (!::GetClientRect(mWnd, &r)) {
|
||||
return LayoutDeviceIntSize();
|
||||
}
|
||||
return LayoutDeviceIntSize(
|
||||
r.right - r.left,
|
||||
r.bottom - r.top);
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
WinCompositorWidget::StartRemoteDrawing()
|
||||
{
|
||||
MOZ_ASSERT(!mCompositeDC);
|
||||
|
||||
RefPtr<gfxASurface> surf;
|
||||
if (mTransparencyMode == eTransparencyTransparent) {
|
||||
surf = EnsureTransparentSurface();
|
||||
}
|
||||
|
||||
// Must call this after EnsureTransparentSurface(), since it could update
|
||||
// the DC.
|
||||
HDC dc = GetWindowSurface();
|
||||
if (!surf) {
|
||||
if (!dc) {
|
||||
return nullptr;
|
||||
}
|
||||
uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 :
|
||||
gfxWindowsSurface::FLAG_IS_TRANSPARENT;
|
||||
surf = new gfxWindowsSurface(dc, flags);
|
||||
}
|
||||
|
||||
IntSize size = surf->GetSize();
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
if (dc) {
|
||||
FreeWindowSurface(dc);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mCompositeDC);
|
||||
mCompositeDC = dc;
|
||||
|
||||
return mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size);
|
||||
}
|
||||
|
||||
void
|
||||
WinCompositorWidget::EndRemoteDrawing()
|
||||
{
|
||||
MOZ_ASSERT(!mLockedBackBufferData);
|
||||
|
||||
if (mTransparencyMode == eTransparencyTransparent) {
|
||||
MOZ_ASSERT(mTransparentSurface);
|
||||
RedrawTransparentWindow();
|
||||
}
|
||||
if (mCompositeDC) {
|
||||
FreeWindowSurface(mCompositeDC);
|
||||
}
|
||||
mCompositeDC = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
WinCompositorWidget::NeedsToDeferEndRemoteDrawing()
|
||||
{
|
||||
if(mNotDeferEndRemoteDrawing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IDirectDraw7* ddraw = DeviceManagerDx::Get()->GetDirectDraw();
|
||||
if (!ddraw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD scanLine = 0;
|
||||
int height = ::GetSystemMetrics(SM_CYSCREEN);
|
||||
HRESULT ret = ddraw->GetScanLine(&scanLine);
|
||||
if (ret == DDERR_VERTICALBLANKINPROGRESS) {
|
||||
scanLine = 0;
|
||||
} else if (ret != DD_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if there is a risk of tearing with GDI.
|
||||
if (static_cast<int>(scanLine) > height / 2) {
|
||||
// No need to defer.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
WinCompositorWidget::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
|
||||
const LayoutDeviceIntRect& aRect,
|
||||
const LayoutDeviceIntRect& aClearRect)
|
||||
{
|
||||
MOZ_ASSERT(!mLockedBackBufferData);
|
||||
|
||||
RefPtr<gfx::DrawTarget> target =
|
||||
CompositorWidget::GetBackBufferDrawTarget(aScreenTarget, aRect, aClearRect);
|
||||
if (!target) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(target->GetBackendType() == BackendType::CAIRO);
|
||||
|
||||
uint8_t* destData;
|
||||
IntSize destSize;
|
||||
int32_t destStride;
|
||||
SurfaceFormat destFormat;
|
||||
if (!target->LockBits(&destData, &destSize, &destStride, &destFormat)) {
|
||||
// LockBits is not supported. Use original DrawTarget.
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
RefPtr<gfx::DrawTarget> dataTarget =
|
||||
Factory::CreateDrawTargetForData(BackendType::CAIRO,
|
||||
destData,
|
||||
destSize,
|
||||
destStride,
|
||||
destFormat);
|
||||
mLockedBackBufferData = destData;
|
||||
|
||||
return dataTarget.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::SourceSurface>
|
||||
WinCompositorWidget::EndBackBufferDrawing()
|
||||
{
|
||||
if (mLockedBackBufferData) {
|
||||
MOZ_ASSERT(mLastBackBuffer);
|
||||
mLastBackBuffer->ReleaseBits(mLockedBackBufferData);
|
||||
mLockedBackBufferData = nullptr;
|
||||
}
|
||||
return CompositorWidget::EndBackBufferDrawing();
|
||||
}
|
||||
|
||||
bool
|
||||
WinCompositorWidget::InitCompositor(layers::Compositor* aCompositor)
|
||||
{
|
||||
if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_BASIC) {
|
||||
DeviceManagerDx::Get()->InitializeDirectDraw();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
WinCompositorWidget::GetWidgetKey()
|
||||
{
|
||||
return mWidgetKey;
|
||||
}
|
||||
|
||||
void
|
||||
WinCompositorWidget::EnterPresentLock()
|
||||
{
|
||||
mPresentLock.Enter();
|
||||
}
|
||||
|
||||
void
|
||||
WinCompositorWidget::LeavePresentLock()
|
||||
{
|
||||
mPresentLock.Leave();
|
||||
}
|
||||
|
||||
RefPtr<gfxASurface>
|
||||
WinCompositorWidget::EnsureTransparentSurface()
|
||||
{
|
||||
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
|
||||
|
||||
IntSize size = GetClientSize().ToUnknownSize();
|
||||
if (!mTransparentSurface || mTransparentSurface->GetSize() != size) {
|
||||
mTransparentSurface = nullptr;
|
||||
mMemoryDC = nullptr;
|
||||
CreateTransparentSurface(size);
|
||||
}
|
||||
|
||||
RefPtr<gfxASurface> surface = mTransparentSurface;
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WinCompositorWidget::CreateTransparentSurface(const gfx::IntSize& aSize)
|
||||
{
|
||||
MOZ_ASSERT(!mTransparentSurface && !mMemoryDC);
|
||||
RefPtr<gfxWindowsSurface> surface = new gfxWindowsSurface(aSize, SurfaceFormat::A8R8G8B8_UINT32);
|
||||
mTransparentSurface = surface;
|
||||
mMemoryDC = surface->GetDC();
|
||||
}
|
||||
|
||||
void
|
||||
WinCompositorWidget::UpdateTransparency(nsTransparencyMode aMode)
|
||||
{
|
||||
if (mTransparencyMode == aMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTransparencyMode = aMode;
|
||||
mTransparentSurface = nullptr;
|
||||
mMemoryDC = nullptr;
|
||||
|
||||
if (mTransparencyMode == eTransparencyTransparent) {
|
||||
EnsureTransparentSurface();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WinCompositorWidget::ClearTransparentWindow()
|
||||
{
|
||||
if (!mTransparentSurface) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureTransparentSurface();
|
||||
|
||||
IntSize size = mTransparentSurface->GetSize();
|
||||
if (!size.IsEmpty()) {
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::CreateDrawTargetForSurface(mTransparentSurface, size);
|
||||
if (!drawTarget) {
|
||||
return;
|
||||
}
|
||||
drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
|
||||
RedrawTransparentWindow();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WinCompositorWidget::RedrawTransparentWindow()
|
||||
{
|
||||
MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
|
||||
|
||||
LayoutDeviceIntSize size = GetClientSize();
|
||||
|
||||
::GdiFlush();
|
||||
|
||||
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
|
||||
SIZE winSize = { size.width, size.height };
|
||||
POINT srcPos = { 0, 0 };
|
||||
HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true);
|
||||
RECT winRect;
|
||||
::GetWindowRect(hWnd, &winRect);
|
||||
|
||||
// perform the alpha blend
|
||||
return !!::UpdateLayeredWindow(
|
||||
hWnd, nullptr, (POINT*)&winRect, &winSize, mMemoryDC,
|
||||
&srcPos, 0, &bf, ULW_ALPHA);
|
||||
}
|
||||
|
||||
HDC
|
||||
WinCompositorWidget::GetWindowSurface()
|
||||
{
|
||||
return eTransparencyTransparent == mTransparencyMode
|
||||
? mMemoryDC
|
||||
: ::GetDC(mWnd);
|
||||
}
|
||||
|
||||
void
|
||||
WinCompositorWidget::FreeWindowSurface(HDC dc)
|
||||
{
|
||||
if (eTransparencyTransparent != mTransparencyMode)
|
||||
::ReleaseDC(mWnd, dc);
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
112
widget/windows/WinCompositorWidget.h
Normal file
112
widget/windows/WinCompositorWidget.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef widget_windows_CompositorWidgetParent_h
|
||||
#define widget_windows_CompositorWidgetParent_h
|
||||
|
||||
#include "CompositorWidget.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "mozilla/gfx/CriticalSection.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "nsIWidget.h"
|
||||
|
||||
class nsWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class CompositorWidgetDelegate
|
||||
{
|
||||
public:
|
||||
// Callbacks for nsWindow.
|
||||
virtual void EnterPresentLock() = 0;
|
||||
virtual void LeavePresentLock() = 0;
|
||||
virtual void OnDestroyWindow() = 0;
|
||||
|
||||
// Transparency handling.
|
||||
virtual void UpdateTransparency(nsTransparencyMode aMode) = 0;
|
||||
virtual void ClearTransparentWindow() = 0;
|
||||
|
||||
// If in-process and using software rendering, return the backing transparent
|
||||
// DC.
|
||||
virtual HDC GetTransparentDC() const = 0;
|
||||
};
|
||||
|
||||
// This is the Windows-specific implementation of CompositorWidget. For
|
||||
// the most part it only requires an HWND, however it maintains extra state
|
||||
// for transparent windows, as well as for synchronizing WM_SETTEXT messages
|
||||
// with the compositor.
|
||||
class WinCompositorWidget
|
||||
: public CompositorWidget,
|
||||
public CompositorWidgetDelegate
|
||||
{
|
||||
public:
|
||||
WinCompositorWidget(const CompositorWidgetInitData& aInitData);
|
||||
|
||||
bool PreRender(WidgetRenderingContext*) override;
|
||||
void PostRender(WidgetRenderingContext*) override;
|
||||
already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override;
|
||||
void EndRemoteDrawing() override;
|
||||
bool NeedsToDeferEndRemoteDrawing() override;
|
||||
LayoutDeviceIntSize GetClientSize() override;
|
||||
already_AddRefed<gfx::DrawTarget> GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
|
||||
const LayoutDeviceIntRect& aRect,
|
||||
const LayoutDeviceIntRect& aClearRect) override;
|
||||
already_AddRefed<gfx::SourceSurface> EndBackBufferDrawing() override;
|
||||
bool InitCompositor(layers::Compositor* aCompositor) override;
|
||||
uintptr_t GetWidgetKey() override;
|
||||
WinCompositorWidget* AsWindows() override {
|
||||
return this;
|
||||
}
|
||||
CompositorWidgetDelegate* AsDelegate() override {
|
||||
return this;
|
||||
}
|
||||
|
||||
// CompositorWidgetDelegate overrides.
|
||||
void EnterPresentLock() override;
|
||||
void LeavePresentLock() override;
|
||||
void OnDestroyWindow() override;
|
||||
void UpdateTransparency(nsTransparencyMode aMode) override;
|
||||
void ClearTransparentWindow() override;
|
||||
|
||||
bool RedrawTransparentWindow();
|
||||
|
||||
// Ensure that a transparent surface exists, then return it.
|
||||
RefPtr<gfxASurface> EnsureTransparentSurface();
|
||||
|
||||
HDC GetTransparentDC() const override {
|
||||
return mMemoryDC;
|
||||
}
|
||||
HWND GetHwnd() const {
|
||||
return mWnd;
|
||||
}
|
||||
|
||||
private:
|
||||
HDC GetWindowSurface();
|
||||
void FreeWindowSurface(HDC dc);
|
||||
|
||||
void CreateTransparentSurface(const gfx::IntSize& aSize);
|
||||
|
||||
private:
|
||||
uintptr_t mWidgetKey;
|
||||
HWND mWnd;
|
||||
gfx::CriticalSection mPresentLock;
|
||||
|
||||
// Transparency handling.
|
||||
nsTransparencyMode mTransparencyMode;
|
||||
RefPtr<gfxASurface> mTransparentSurface;
|
||||
HDC mMemoryDC;
|
||||
HDC mCompositeDC;
|
||||
|
||||
// Locked back buffer of BasicCompositor
|
||||
uint8_t* mLockedBackBufferData;
|
||||
|
||||
bool mNotDeferEndRemoteDrawing;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // widget_windows_CompositorWidgetParent_h
|
||||
1055
widget/windows/WinIMEHandler.cpp
Normal file
1055
widget/windows/WinIMEHandler.cpp
Normal file
File diff suppressed because it is too large
Load diff
190
widget/windows/WinIMEHandler.h
Normal file
190
widget/windows/WinIMEHandler.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef WinIMEHandler_h_
|
||||
#define WinIMEHandler_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsWindowBase.h"
|
||||
#include "npapi.h"
|
||||
#include <windows.h>
|
||||
#include <inputscope.h>
|
||||
|
||||
#define NS_WM_IMEFIRST WM_IME_SETCONTEXT
|
||||
#define NS_WM_IMELAST WM_IME_KEYUP
|
||||
|
||||
class nsWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
struct MSGResult;
|
||||
|
||||
/**
|
||||
* IMEHandler class is a mediator class. On Windows, there are two IME API
|
||||
* sets: One is IMM which is legacy API set. The other is TSF which is modern
|
||||
* API set. By using this class, non-IME handler classes don't need to worry
|
||||
* that we're in which mode.
|
||||
*/
|
||||
class IMEHandler final
|
||||
{
|
||||
public:
|
||||
static void Initialize();
|
||||
static void Terminate();
|
||||
|
||||
/**
|
||||
* Returns TSF related native data or native IME context.
|
||||
*/
|
||||
static void* GetNativeData(nsWindow* aWindow, uint32_t aDataType);
|
||||
|
||||
/**
|
||||
* ProcessRawKeyMessage() message is called before calling TranslateMessage()
|
||||
* and DispatchMessage(). If this returns true, the message is consumed.
|
||||
* Then, caller must not perform TranslateMessage() nor DispatchMessage().
|
||||
*/
|
||||
static bool ProcessRawKeyMessage(const MSG& aMsg);
|
||||
|
||||
/**
|
||||
* When the message is not needed to handle anymore by the caller, this
|
||||
* returns true. Otherwise, false.
|
||||
*/
|
||||
static bool ProcessMessage(nsWindow* aWindow, UINT aMessage,
|
||||
WPARAM& aWParam, LPARAM& aLParam,
|
||||
MSGResult& aResult);
|
||||
|
||||
/**
|
||||
* When there is a composition, returns true. Otherwise, false.
|
||||
*/
|
||||
static bool IsComposing();
|
||||
|
||||
/**
|
||||
* When there is a composition and it's in the window, returns true.
|
||||
* Otherwise, false.
|
||||
*/
|
||||
static bool IsComposingOn(nsWindow* aWindow);
|
||||
|
||||
/**
|
||||
* Notifies IME of the notification (a request or an event).
|
||||
*/
|
||||
static nsresult NotifyIME(nsWindow* aWindow,
|
||||
const IMENotification& aIMENotification);
|
||||
|
||||
/**
|
||||
* Returns update preferences.
|
||||
*/
|
||||
static nsIMEUpdatePreference GetUpdatePreference();
|
||||
|
||||
/**
|
||||
* Returns native text event dispatcher listener.
|
||||
*/
|
||||
static TextEventDispatcherListener* GetNativeTextEventDispatcherListener();
|
||||
|
||||
/**
|
||||
* Returns IME open state on the window.
|
||||
*/
|
||||
static bool GetOpenState(nsWindow* aWindow);
|
||||
|
||||
/**
|
||||
* Called when the window is destroying.
|
||||
*/
|
||||
static void OnDestroyWindow(nsWindow* aWindow);
|
||||
|
||||
/**
|
||||
* Called when nsIWidget::SetInputContext() is called before the window's
|
||||
* InputContext is modified actually.
|
||||
*/
|
||||
static void SetInputContext(nsWindow* aWindow,
|
||||
InputContext& aInputContext,
|
||||
const InputContextAction& aAction);
|
||||
|
||||
/**
|
||||
* Associate or disassociate IME context to/from the aWindowBase.
|
||||
*/
|
||||
static void AssociateIMEContext(nsWindowBase* aWindowBase, bool aEnable);
|
||||
|
||||
/**
|
||||
* Called when the window is created.
|
||||
*/
|
||||
static void InitInputContext(nsWindow* aWindow, InputContext& aInputContext);
|
||||
|
||||
/*
|
||||
* For windowless plugin helper.
|
||||
*/
|
||||
static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
|
||||
|
||||
/*
|
||||
* For WM_IME_*COMPOSITION messages and e10s with windowless plugin
|
||||
*/
|
||||
static void DefaultProcOfPluginEvent(nsWindow* aWindow,
|
||||
const NPEvent* aPluginEvent);
|
||||
|
||||
#ifdef NS_ENABLE_TSF
|
||||
/**
|
||||
* This is called by TSFStaticSink when active IME is changed.
|
||||
*/
|
||||
static void OnKeyboardLayoutChanged();
|
||||
#endif // #ifdef NS_ENABLE_TSF
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* Returns true when current keyboard layout has IME. Otherwise, false.
|
||||
*/
|
||||
static bool CurrentKeyboardLayoutHasIME();
|
||||
#endif // #ifdef DEBUG
|
||||
|
||||
private:
|
||||
static nsWindow* sFocusedWindow;
|
||||
static InputContextAction::Cause sLastContextActionCause;
|
||||
|
||||
static bool sPluginHasFocus;
|
||||
|
||||
#ifdef NS_ENABLE_TSF
|
||||
static decltype(SetInputScopes)* sSetInputScopes;
|
||||
static void SetInputScopeForIMM32(nsWindow* aWindow,
|
||||
const nsAString& aHTMLInputType,
|
||||
const nsAString& aHTMLInputInputmode);
|
||||
static bool sIsInTSFMode;
|
||||
// If sIMMEnabled is false, any IME messages are not handled in TSF mode.
|
||||
// Additionally, IME context is always disassociated from focused window.
|
||||
static bool sIsIMMEnabled;
|
||||
static bool sAssociateIMCOnlyWhenIMM_IMEActive;
|
||||
|
||||
static bool IsTSFAvailable() { return (sIsInTSFMode && !sPluginHasFocus); }
|
||||
static bool IsIMMActive();
|
||||
|
||||
static void MaybeShowOnScreenKeyboard();
|
||||
static void MaybeDismissOnScreenKeyboard(nsWindow* aWindow);
|
||||
static bool WStringStartsWithCaseInsensitive(const std::wstring& aHaystack,
|
||||
const std::wstring& aNeedle);
|
||||
static bool NeedOnScreenKeyboard();
|
||||
static bool IsKeyboardPresentOnSlate();
|
||||
static bool IsInTabletMode();
|
||||
static bool AutoInvokeOnScreenKeyboardInDesktopMode();
|
||||
static bool NeedsToAssociateIMC();
|
||||
|
||||
/**
|
||||
* Show the Windows on-screen keyboard. Only allowed for
|
||||
* chrome documents and Windows 8 and higher.
|
||||
*/
|
||||
static void ShowOnScreenKeyboard();
|
||||
|
||||
/**
|
||||
* Dismiss the Windows on-screen keyboard. Only allowed for
|
||||
* Windows 8 and higher.
|
||||
*/
|
||||
static void DismissOnScreenKeyboard();
|
||||
|
||||
/**
|
||||
* Get the HWND for the on-screen keyboard, if it's up. Only
|
||||
* allowed for Windows 8 and higher.
|
||||
*/
|
||||
static HWND GetOnScreenKeyboardWindow();
|
||||
#endif // #ifdef NS_ENABLE_TSF
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // #ifndef WinIMEHandler_h_
|
||||
187
widget/windows/WinMessages.h
Normal file
187
widget/windows/WinMessages.h
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_widget_WinMessages_h_
|
||||
#define mozilla_widget_WinMessages_h_
|
||||
|
||||
/*****************************************************************************
|
||||
* MOZ_WM_* messages
|
||||
****************************************************************************/
|
||||
|
||||
// A magic APP message that can be sent to quit, sort of like a
|
||||
// QUERYENDSESSION/ENDSESSION, but without the query.
|
||||
#define MOZ_WM_APP_QUIT (WM_APP+0x0300)
|
||||
// Used as a "tracer" event to probe event loop latency.
|
||||
#define MOZ_WM_TRACE (WM_APP+0x0301)
|
||||
// Our internal message for WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL and
|
||||
// WM_HSCROLL
|
||||
#define MOZ_WM_MOUSEVWHEEL (WM_APP+0x0310)
|
||||
#define MOZ_WM_MOUSEHWHEEL (WM_APP+0x0311)
|
||||
#define MOZ_WM_VSCROLL (WM_APP+0x0312)
|
||||
#define MOZ_WM_HSCROLL (WM_APP+0x0313)
|
||||
#define MOZ_WM_MOUSEWHEEL_FIRST MOZ_WM_MOUSEVWHEEL
|
||||
#define MOZ_WM_MOUSEWHEEL_LAST MOZ_WM_HSCROLL
|
||||
// If a popup window is being activated, we try to reactivate the previous
|
||||
// window with this message.
|
||||
#define MOZ_WM_REACTIVATE (WM_APP+0x0314)
|
||||
// If TSFTextStore needs to notify TSF/TIP of layout change later, this
|
||||
// message is posted.
|
||||
#define MOZ_WM_NOTIY_TSF_OF_LAYOUT_CHANGE (WM_APP+0x0315)
|
||||
// Internal message used in correcting backwards clock skew
|
||||
#define MOZ_WM_SKEWFIX (WM_APP+0x0316)
|
||||
// Internal message used for hiding the on-screen keyboard
|
||||
#define MOZ_WM_DISMISS_ONSCREEN_KEYBOARD (WM_APP+0x0317)
|
||||
|
||||
// Following MOZ_WM_*KEY* messages are used by PluginInstanceChild and
|
||||
// NativeKey internally. (never posted to the queue)
|
||||
#define MOZ_WM_KEYDOWN (WM_APP+0x0318)
|
||||
#define MOZ_WM_KEYUP (WM_APP+0x0319)
|
||||
#define MOZ_WM_SYSKEYDOWN (WM_APP+0x031A)
|
||||
#define MOZ_WM_SYSKEYUP (WM_APP+0x031B)
|
||||
#define MOZ_WM_CHAR (WM_APP+0x031C)
|
||||
#define MOZ_WM_SYSCHAR (WM_APP+0x031D)
|
||||
#define MOZ_WM_DEADCHAR (WM_APP+0x031E)
|
||||
#define MOZ_WM_SYSDEADCHAR (WM_APP+0x031F)
|
||||
|
||||
// Internal message for ensuring the file picker is visible on multi monitor
|
||||
// systems, and when the screen resolution changes.
|
||||
#define MOZ_WM_ENSUREVISIBLE (WM_APP+0x374F)
|
||||
|
||||
// XXX Should rename them to MOZ_WM_* and use safer values!
|
||||
// Messages for fullscreen transition window
|
||||
#define WM_FULLSCREEN_TRANSITION_BEFORE (WM_USER + 0)
|
||||
#define WM_FULLSCREEN_TRANSITION_AFTER (WM_USER + 1)
|
||||
|
||||
/*****************************************************************************
|
||||
* WM_* messages and related constants which may not be defined by
|
||||
* old Windows SDK
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef SM_CXPADDEDBORDER
|
||||
#define SM_CXPADDEDBORDER 92
|
||||
#endif
|
||||
|
||||
// require WINVER >= 0x601
|
||||
#ifndef SM_MAXIMUMTOUCHES
|
||||
#define SM_MAXIMUMTOUCHES 95
|
||||
#endif
|
||||
|
||||
#ifndef WM_THEMECHANGED
|
||||
#define WM_THEMECHANGED 0x031A
|
||||
#endif
|
||||
|
||||
#ifndef WM_GETOBJECT
|
||||
#define WM_GETOBJECT 0x03d
|
||||
#endif
|
||||
|
||||
#ifndef PBT_APMRESUMEAUTOMATIC
|
||||
#define PBT_APMRESUMEAUTOMATIC 0x0012
|
||||
#endif
|
||||
|
||||
#ifndef WM_MOUSEHWHEEL
|
||||
#define WM_MOUSEHWHEEL 0x020E
|
||||
#endif
|
||||
|
||||
#ifndef MOUSEEVENTF_HWHEEL
|
||||
#define MOUSEEVENTF_HWHEEL 0x01000
|
||||
#endif
|
||||
|
||||
#ifndef WM_MOUSELEAVE
|
||||
#define WM_MOUSELEAVE 0x02A3
|
||||
#endif
|
||||
|
||||
#ifndef SPI_GETWHEELSCROLLCHARS
|
||||
#define SPI_GETWHEELSCROLLCHARS 0x006C
|
||||
#endif
|
||||
|
||||
#ifndef SPI_SETWHEELSCROLLCHARS
|
||||
#define SPI_SETWHEELSCROLLCHARS 0x006D
|
||||
#endif
|
||||
|
||||
#ifndef MAPVK_VSC_TO_VK
|
||||
#define MAPVK_VK_TO_VSC 0
|
||||
#define MAPVK_VSC_TO_VK 1
|
||||
#define MAPVK_VK_TO_CHAR 2
|
||||
#define MAPVK_VSC_TO_VK_EX 3
|
||||
#define MAPVK_VK_TO_VSC_EX 4
|
||||
#endif
|
||||
|
||||
#ifndef WM_DWMCOMPOSITIONCHANGED
|
||||
#define WM_DWMCOMPOSITIONCHANGED 0x031E
|
||||
#endif
|
||||
#ifndef WM_DWMNCRENDERINGCHANGED
|
||||
#define WM_DWMNCRENDERINGCHANGED 0x031F
|
||||
#endif
|
||||
#ifndef WM_DWMCOLORIZATIONCOLORCHANGED
|
||||
#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
|
||||
#endif
|
||||
#ifndef WM_DWMWINDOWMAXIMIZEDCHANGE
|
||||
#define WM_DWMWINDOWMAXIMIZEDCHANGE 0x0321
|
||||
#endif
|
||||
|
||||
// Drop shadow window style
|
||||
#define CS_XP_DROPSHADOW 0x00020000
|
||||
|
||||
// App Command messages for IntelliMouse and Natural Keyboard Pro
|
||||
// These messages are not included in Visual C++ 6.0, but are in 7.0+
|
||||
#ifndef WM_APPCOMMAND
|
||||
#define WM_APPCOMMAND 0x0319
|
||||
#endif
|
||||
|
||||
#define FAPPCOMMAND_MASK 0xF000
|
||||
|
||||
#ifndef WM_GETTITLEBARINFOEX
|
||||
#define WM_GETTITLEBARINFOEX 0x033F
|
||||
#endif
|
||||
|
||||
#ifndef CCHILDREN_TITLEBAR
|
||||
#define CCHILDREN_TITLEBAR 5
|
||||
#endif
|
||||
|
||||
#ifndef APPCOMMAND_BROWSER_BACKWARD
|
||||
#define APPCOMMAND_BROWSER_BACKWARD 1
|
||||
#define APPCOMMAND_BROWSER_FORWARD 2
|
||||
#define APPCOMMAND_BROWSER_REFRESH 3
|
||||
#define APPCOMMAND_BROWSER_STOP 4
|
||||
#define APPCOMMAND_BROWSER_SEARCH 5
|
||||
#define APPCOMMAND_BROWSER_FAVORITES 6
|
||||
#define APPCOMMAND_BROWSER_HOME 7
|
||||
|
||||
#define APPCOMMAND_MEDIA_NEXTTRACK 11
|
||||
#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12
|
||||
#define APPCOMMAND_MEDIA_STOP 13
|
||||
#define APPCOMMAND_MEDIA_PLAY_PAUSE 14
|
||||
|
||||
/*
|
||||
* Additional commands currently not in use.
|
||||
*
|
||||
*#define APPCOMMAND_VOLUME_MUTE 8
|
||||
*#define APPCOMMAND_VOLUME_DOWN 9
|
||||
*#define APPCOMMAND_VOLUME_UP 10
|
||||
*#define APPCOMMAND_LAUNCH_MAIL 15
|
||||
*#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16
|
||||
*#define APPCOMMAND_LAUNCH_APP1 17
|
||||
*#define APPCOMMAND_LAUNCH_APP2 18
|
||||
*#define APPCOMMAND_BASS_DOWN 19
|
||||
*#define APPCOMMAND_BASS_BOOST 20
|
||||
*#define APPCOMMAND_BASS_UP 21
|
||||
*#define APPCOMMAND_TREBLE_DOWN 22
|
||||
*#define APPCOMMAND_TREBLE_UP 23
|
||||
*#define FAPPCOMMAND_MOUSE 0x8000
|
||||
*#define FAPPCOMMAND_KEY 0
|
||||
*#define FAPPCOMMAND_OEM 0x1000
|
||||
*/
|
||||
|
||||
#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
|
||||
|
||||
/*
|
||||
*#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK))
|
||||
*#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM
|
||||
*#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam))
|
||||
*#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam)
|
||||
*/
|
||||
#endif // #ifndef APPCOMMAND_BROWSER_BACKWARD
|
||||
|
||||
#endif // #ifndef mozilla_widget_WinMessages_h_
|
||||
62
widget/windows/WinModifierKeyState.h
Normal file
62
widget/windows/WinModifierKeyState.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_widget_WinModifierKeyState_h_
|
||||
#define mozilla_widget_WinModifierKeyState_h_
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include <windows.h>
|
||||
|
||||
class nsCString;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class MOZ_STACK_CLASS ModifierKeyState final
|
||||
{
|
||||
public:
|
||||
ModifierKeyState();
|
||||
ModifierKeyState(bool aIsShiftDown, bool aIsControlDown, bool aIsAltDown);
|
||||
ModifierKeyState(Modifiers aModifiers);
|
||||
|
||||
void Update();
|
||||
|
||||
void Unset(Modifiers aRemovingModifiers);
|
||||
void Set(Modifiers aAddingModifiers);
|
||||
|
||||
void InitInputEvent(WidgetInputEvent& aInputEvent) const;
|
||||
|
||||
bool IsShift() const;
|
||||
bool IsControl() const;
|
||||
bool IsAlt() const;
|
||||
bool IsAltGr() const;
|
||||
bool IsWin() const;
|
||||
|
||||
bool MaybeMatchShortcutKey() const;
|
||||
|
||||
bool IsCapsLocked() const;
|
||||
bool IsNumLocked() const;
|
||||
bool IsScrollLocked() const;
|
||||
|
||||
MOZ_ALWAYS_INLINE Modifiers GetModifiers() const
|
||||
{
|
||||
return mModifiers;
|
||||
}
|
||||
|
||||
private:
|
||||
Modifiers mModifiers;
|
||||
|
||||
MOZ_ALWAYS_INLINE void EnsureAltGr();
|
||||
|
||||
void InitMouseEvent(WidgetInputEvent& aMouseEvent) const;
|
||||
};
|
||||
|
||||
const nsCString ToString(const ModifierKeyState& aModifierKeyState);
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // #ifndef mozilla_widget_WinModifierKeyState_h_
|
||||
1799
widget/windows/WinMouseScrollHandler.cpp
Normal file
1799
widget/windows/WinMouseScrollHandler.cpp
Normal file
File diff suppressed because it is too large
Load diff
625
widget/windows/WinMouseScrollHandler.h
Normal file
625
widget/windows/WinMouseScrollHandler.h
Normal file
|
|
@ -0,0 +1,625 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_widget_WinMouseScrollHandler_h__
|
||||
#define mozilla_widget_WinMouseScrollHandler_h__
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsDebug.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "Units.h"
|
||||
#include <windows.h>
|
||||
#include "nsPoint.h"
|
||||
|
||||
class nsWindowBase;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class ModifierKeyState;
|
||||
|
||||
struct MSGResult;
|
||||
|
||||
class MouseScrollHandler {
|
||||
public:
|
||||
static MouseScrollHandler* GetInstance();
|
||||
|
||||
static void Initialize();
|
||||
static void Shutdown();
|
||||
|
||||
static bool NeedsMessage(UINT aMsg);
|
||||
static bool ProcessMessage(nsWindowBase* aWidget,
|
||||
UINT msg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
|
||||
/**
|
||||
* See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
|
||||
* this method.
|
||||
*/
|
||||
static nsresult SynthesizeNativeMouseScrollEvent(nsWindowBase* aWidget,
|
||||
const LayoutDeviceIntPoint& aPoint,
|
||||
uint32_t aNativeMessage,
|
||||
int32_t aDelta,
|
||||
uint32_t aModifierFlags,
|
||||
uint32_t aAdditionalFlags);
|
||||
|
||||
/**
|
||||
* IsWaitingInternalMessage() returns true if MouseScrollHandler posted
|
||||
* an internal message for a native mouse wheel message and has not
|
||||
* received it. Otherwise, false.
|
||||
*/
|
||||
static bool IsWaitingInternalMessage()
|
||||
{
|
||||
return sInstance && sInstance->mIsWaitingInternalMessage;
|
||||
}
|
||||
|
||||
private:
|
||||
MouseScrollHandler();
|
||||
~MouseScrollHandler();
|
||||
|
||||
bool mIsWaitingInternalMessage;
|
||||
|
||||
static void MaybeLogKeyState();
|
||||
|
||||
static MouseScrollHandler* sInstance;
|
||||
|
||||
/**
|
||||
* InitEvent() initializes the aEvent. If aPoint is null, the result of
|
||||
* GetCurrentMessagePos() will be used.
|
||||
*/
|
||||
static void InitEvent(nsWindowBase* aWidget,
|
||||
WidgetGUIEvent& aEvent,
|
||||
LayoutDeviceIntPoint* aPoint = nullptr);
|
||||
|
||||
/**
|
||||
* GetModifierKeyState() returns current modifier key state.
|
||||
* Note that some devices need some hack for the modifier key state.
|
||||
* This method does it automatically.
|
||||
*
|
||||
* @param aMessage Handling message.
|
||||
*/
|
||||
static ModifierKeyState GetModifierKeyState(UINT aMessage);
|
||||
|
||||
/**
|
||||
* MozGetMessagePos() returns the mouse cursor position when GetMessage()
|
||||
* was called last time. However, if we're sending a native message,
|
||||
* this returns the specified cursor position by
|
||||
* SynthesizeNativeMouseScrollEvent().
|
||||
*/
|
||||
static POINTS GetCurrentMessagePos();
|
||||
|
||||
/**
|
||||
* ProcessNativeMouseWheelMessage() processes WM_MOUSEWHEEL and
|
||||
* WM_MOUSEHWHEEL. Additionally, processes WM_VSCROLL and WM_HSCROLL if they
|
||||
* should be processed as mouse wheel message.
|
||||
* This method posts MOZ_WM_MOUSEVWHEEL, MOZ_WM_MOUSEHWHEEL,
|
||||
* MOZ_WM_VSCROLL or MOZ_WM_HSCROLL if we need to dispatch mouse scroll
|
||||
* events. That avoids deadlock with plugin process.
|
||||
*
|
||||
* @param aWidget A window which receives the message.
|
||||
* @param aMessage WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or
|
||||
* WM_HSCROLL.
|
||||
* @param aWParam The wParam value of the message.
|
||||
* @param aLParam The lParam value of the message.
|
||||
*/
|
||||
void ProcessNativeMouseWheelMessage(nsWindowBase* aWidget,
|
||||
UINT aMessage,
|
||||
WPARAM aWParam,
|
||||
LPARAM aLParam);
|
||||
|
||||
/**
|
||||
* ProcessNativeScrollMessage() processes WM_VSCROLL and WM_HSCROLL.
|
||||
* This method just call ProcessMouseWheelMessage() if the message should be
|
||||
* processed as mouse wheel message. Otherwise, dispatches a content
|
||||
* command event.
|
||||
*
|
||||
* @param aWidget A window which receives the message.
|
||||
* @param aMessage WM_VSCROLL or WM_HSCROLL.
|
||||
* @param aWParam The wParam value of the message.
|
||||
* @param aLParam The lParam value of the message.
|
||||
* @return TRUE if the message is processed. Otherwise, FALSE.
|
||||
*/
|
||||
bool ProcessNativeScrollMessage(nsWindowBase* aWidget,
|
||||
UINT aMessage,
|
||||
WPARAM aWParam,
|
||||
LPARAM aLParam);
|
||||
|
||||
/**
|
||||
* HandleMouseWheelMessage() processes MOZ_WM_MOUSEVWHEEL and
|
||||
* MOZ_WM_MOUSEHWHEEL which are posted when one of our windows received
|
||||
* WM_MOUSEWHEEL or WM_MOUSEHWHEEL for avoiding deadlock with OOPP.
|
||||
*
|
||||
* @param aWidget A window which receives the wheel message.
|
||||
* @param aMessage MOZ_WM_MOUSEWHEEL or MOZ_WM_MOUSEHWHEEL.
|
||||
* @param aWParam The wParam value of the original message.
|
||||
* @param aLParam The lParam value of the original message.
|
||||
*/
|
||||
void HandleMouseWheelMessage(nsWindowBase* aWidget,
|
||||
UINT aMessage,
|
||||
WPARAM aWParam,
|
||||
LPARAM aLParam);
|
||||
|
||||
/**
|
||||
* HandleScrollMessageAsMouseWheelMessage() processes the MOZ_WM_VSCROLL and
|
||||
* MOZ_WM_HSCROLL which are posted when one of mouse windows received
|
||||
* WM_VSCROLL or WM_HSCROLL and user wants them to emulate mouse wheel
|
||||
* message's behavior.
|
||||
*
|
||||
* @param aWidget A window which receives the scroll message.
|
||||
* @param aMessage MOZ_WM_VSCROLL or MOZ_WM_HSCROLL.
|
||||
* @param aWParam The wParam value of the original message.
|
||||
* @param aLParam The lParam value of the original message.
|
||||
*/
|
||||
void HandleScrollMessageAsMouseWheelMessage(nsWindowBase* aWidget,
|
||||
UINT aMessage,
|
||||
WPARAM aWParam,
|
||||
LPARAM aLParam);
|
||||
|
||||
/**
|
||||
* ComputeMessagePos() computes the cursor position when the message was
|
||||
* added to the queue.
|
||||
*
|
||||
* @param aMessage Handling message.
|
||||
* @param aWParam Handling message's wParam.
|
||||
* @param aLParam Handling message's lParam.
|
||||
* @return Mouse cursor position when the message is added to
|
||||
* the queue or current cursor position if the result of
|
||||
* ::GetMessagePos() is broken.
|
||||
*/
|
||||
POINT ComputeMessagePos(UINT aMessage,
|
||||
WPARAM aWParam,
|
||||
LPARAM aLParam);
|
||||
|
||||
class EventInfo {
|
||||
public:
|
||||
/**
|
||||
* @param aWidget An nsWindow which is handling the event.
|
||||
* @param aMessage Must be WM_MOUSEWHEEL or WM_MOUSEHWHEEL.
|
||||
*/
|
||||
EventInfo(nsWindowBase* aWidget, UINT aMessage, WPARAM aWParam, LPARAM aLParam);
|
||||
|
||||
bool CanDispatchWheelEvent() const;
|
||||
|
||||
int32_t GetNativeDelta() const { return mDelta; }
|
||||
HWND GetWindowHandle() const { return mWnd; }
|
||||
const TimeStamp& GetTimeStamp() const { return mTimeStamp; }
|
||||
bool IsVertical() const { return mIsVertical; }
|
||||
bool IsPositive() const { return (mDelta > 0); }
|
||||
bool IsPage() const { return mIsPage; }
|
||||
|
||||
/**
|
||||
* @return Number of lines or pages scrolled per WHEEL_DELTA.
|
||||
*/
|
||||
int32_t GetScrollAmount() const;
|
||||
|
||||
protected:
|
||||
EventInfo() :
|
||||
mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// TRUE if event is for vertical scroll. Otherwise, FALSE.
|
||||
bool mIsVertical;
|
||||
// TRUE if event scrolls per page, otherwise, FALSE.
|
||||
bool mIsPage;
|
||||
// The native delta value.
|
||||
int32_t mDelta;
|
||||
// The window handle which is handling the event.
|
||||
HWND mWnd;
|
||||
// Timestamp of the event.
|
||||
TimeStamp mTimeStamp;
|
||||
};
|
||||
|
||||
class LastEventInfo : public EventInfo {
|
||||
public:
|
||||
LastEventInfo() :
|
||||
EventInfo(), mAccumulatedDelta(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* CanContinueTransaction() checks whether the new event can continue the
|
||||
* last transaction or not. Note that if there is no transaction, this
|
||||
* returns true.
|
||||
*/
|
||||
bool CanContinueTransaction(const EventInfo& aNewEvent);
|
||||
|
||||
/**
|
||||
* ResetTransaction() resets the transaction, i.e., the instance forgets
|
||||
* the last event information.
|
||||
*/
|
||||
void ResetTransaction();
|
||||
|
||||
/**
|
||||
* RecordEvent() saves the information of new event.
|
||||
*/
|
||||
void RecordEvent(const EventInfo& aEvent);
|
||||
|
||||
/**
|
||||
* InitWheelEvent() initializes NS_WHEEL_WHEEL event and
|
||||
* recomputes the remaning detla for the event.
|
||||
* This must be called only once during handling a message and after
|
||||
* RecordEvent() is called.
|
||||
*
|
||||
* @param aWidget A window which will dispatch the event.
|
||||
* @param aWheelEvent An NS_WHEEL_WHEEL event, this will be
|
||||
* initialized.
|
||||
* @param aModKeyState Current modifier key state.
|
||||
* @return TRUE if the event is ready to dispatch.
|
||||
* Otherwise, FALSE.
|
||||
*/
|
||||
bool InitWheelEvent(nsWindowBase* aWidget,
|
||||
WidgetWheelEvent& aWheelEvent,
|
||||
const ModifierKeyState& aModKeyState);
|
||||
|
||||
private:
|
||||
static int32_t RoundDelta(double aDelta);
|
||||
|
||||
int32_t mAccumulatedDelta;
|
||||
};
|
||||
|
||||
LastEventInfo mLastEventInfo;
|
||||
|
||||
class SystemSettings {
|
||||
public:
|
||||
SystemSettings() : mInitialized(false) {}
|
||||
|
||||
void Init();
|
||||
void MarkDirty();
|
||||
void NotifyUserPrefsMayOverrideSystemSettings();
|
||||
|
||||
// On some environments, SystemParametersInfo() may be hooked by touchpad
|
||||
// utility or something. In such case, when user changes active pointing
|
||||
// device to another one, the result of SystemParametersInfo() may be
|
||||
// changed without WM_SETTINGCHANGE message. For avoiding this trouble,
|
||||
// we need to modify cache of system settings at every wheel message
|
||||
// handling if we meet known device whose utility may hook the API.
|
||||
void TrustedScrollSettingsDriver();
|
||||
|
||||
// Returns true if the system scroll may be overridden for faster scroll.
|
||||
// Otherwise, false. For example, if the user maybe uses an expensive
|
||||
// mouse which supports acceleration of scroll speed, faster scroll makes
|
||||
// the user inconvenient.
|
||||
bool IsOverridingSystemScrollSpeedAllowed();
|
||||
|
||||
int32_t GetScrollAmount(bool aForVertical) const
|
||||
{
|
||||
MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
|
||||
return aForVertical ? mScrollLines : mScrollChars;
|
||||
}
|
||||
|
||||
bool IsPageScroll(bool aForVertical) const
|
||||
{
|
||||
MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
|
||||
return aForVertical ? (uint32_t(mScrollLines) == WHEEL_PAGESCROLL) :
|
||||
(uint32_t(mScrollChars) == WHEEL_PAGESCROLL);
|
||||
}
|
||||
|
||||
// The default vertical and horizontal scrolling speed is 3, this is defined
|
||||
// on the document of SystemParametersInfo in MSDN.
|
||||
static int32_t DefaultScrollLines() { return 3; }
|
||||
static int32_t DefaultScrollChars() { return 3; }
|
||||
|
||||
private:
|
||||
bool mInitialized;
|
||||
// The result of SystemParametersInfo() may not be reliable since it may
|
||||
// be hooked. So, if the values are initialized with prefs, we can trust
|
||||
// the value. Following mIsReliableScroll* are set true when mScroll* are
|
||||
// initialized with prefs.
|
||||
bool mIsReliableScrollLines;
|
||||
bool mIsReliableScrollChars;
|
||||
|
||||
int32_t mScrollLines;
|
||||
int32_t mScrollChars;
|
||||
|
||||
// Returns true if cached value is changed.
|
||||
bool InitScrollLines();
|
||||
bool InitScrollChars();
|
||||
|
||||
void RefreshCache();
|
||||
};
|
||||
|
||||
SystemSettings mSystemSettings;
|
||||
|
||||
class UserPrefs {
|
||||
public:
|
||||
UserPrefs();
|
||||
~UserPrefs();
|
||||
|
||||
void MarkDirty();
|
||||
|
||||
bool IsScrollMessageHandledAsWheelMessage()
|
||||
{
|
||||
Init();
|
||||
return mScrollMessageHandledAsWheelMessage;
|
||||
}
|
||||
|
||||
bool IsSystemSettingCacheEnabled()
|
||||
{
|
||||
Init();
|
||||
return mEnableSystemSettingCache;
|
||||
}
|
||||
|
||||
bool IsSystemSettingCacheForciblyEnabled()
|
||||
{
|
||||
Init();
|
||||
return mForceEnableSystemSettingCache;
|
||||
}
|
||||
|
||||
int32_t GetOverriddenVerticalScrollAmout()
|
||||
{
|
||||
Init();
|
||||
return mOverriddenVerticalScrollAmount;
|
||||
}
|
||||
|
||||
int32_t GetOverriddenHorizontalScrollAmout()
|
||||
{
|
||||
Init();
|
||||
return mOverriddenHorizontalScrollAmount;
|
||||
}
|
||||
|
||||
int32_t GetMouseScrollTransactionTimeout()
|
||||
{
|
||||
Init();
|
||||
return mMouseScrollTransactionTimeout;
|
||||
}
|
||||
|
||||
private:
|
||||
void Init();
|
||||
|
||||
static void OnChange(const char* aPrefName, void* aClosure)
|
||||
{
|
||||
static_cast<UserPrefs*>(aClosure)->MarkDirty();
|
||||
}
|
||||
|
||||
bool mInitialized;
|
||||
bool mScrollMessageHandledAsWheelMessage;
|
||||
bool mEnableSystemSettingCache;
|
||||
bool mForceEnableSystemSettingCache;
|
||||
int32_t mOverriddenVerticalScrollAmount;
|
||||
int32_t mOverriddenHorizontalScrollAmount;
|
||||
int32_t mMouseScrollTransactionTimeout;
|
||||
};
|
||||
|
||||
UserPrefs mUserPrefs;
|
||||
|
||||
class SynthesizingEvent {
|
||||
public:
|
||||
SynthesizingEvent() :
|
||||
mWnd(nullptr), mMessage(0), mWParam(0), mLParam(0),
|
||||
mStatus(NOT_SYNTHESIZING)
|
||||
{
|
||||
}
|
||||
|
||||
~SynthesizingEvent() {}
|
||||
|
||||
static bool IsSynthesizing();
|
||||
|
||||
nsresult Synthesize(const POINTS& aCursorPoint, HWND aWnd,
|
||||
UINT aMessage, WPARAM aWParam, LPARAM aLParam,
|
||||
const BYTE (&aKeyStates)[256]);
|
||||
|
||||
void NativeMessageReceived(nsWindowBase* aWidget, UINT aMessage,
|
||||
WPARAM aWParam, LPARAM aLParam);
|
||||
|
||||
void NotifyNativeMessageHandlingFinished();
|
||||
void NotifyInternalMessageHandlingFinished();
|
||||
|
||||
const POINTS& GetCursorPoint() const { return mCursorPoint; }
|
||||
|
||||
private:
|
||||
POINTS mCursorPoint;
|
||||
HWND mWnd;
|
||||
UINT mMessage;
|
||||
WPARAM mWParam;
|
||||
LPARAM mLParam;
|
||||
BYTE mKeyState[256];
|
||||
BYTE mOriginalKeyState[256];
|
||||
|
||||
enum Status {
|
||||
NOT_SYNTHESIZING,
|
||||
SENDING_MESSAGE,
|
||||
NATIVE_MESSAGE_RECEIVED,
|
||||
INTERNAL_MESSAGE_POSTED,
|
||||
};
|
||||
Status mStatus;
|
||||
|
||||
const char* GetStatusName()
|
||||
{
|
||||
switch (mStatus) {
|
||||
case NOT_SYNTHESIZING:
|
||||
return "NOT_SYNTHESIZING";
|
||||
case SENDING_MESSAGE:
|
||||
return "SENDING_MESSAGE";
|
||||
case NATIVE_MESSAGE_RECEIVED:
|
||||
return "NATIVE_MESSAGE_RECEIVED";
|
||||
case INTERNAL_MESSAGE_POSTED:
|
||||
return "INTERNAL_MESSAGE_POSTED";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void Finish();
|
||||
}; // SynthesizingEvent
|
||||
|
||||
SynthesizingEvent* mSynthesizingEvent;
|
||||
|
||||
public:
|
||||
|
||||
class Device {
|
||||
public:
|
||||
// SynTP is a touchpad driver of Synaptics.
|
||||
class SynTP
|
||||
{
|
||||
public:
|
||||
static bool IsDriverInstalled()
|
||||
{
|
||||
return sMajorVersion != 0;
|
||||
}
|
||||
/**
|
||||
* GetDriverMajorVersion() returns the installed driver's major version.
|
||||
* If SynTP driver isn't installed, this returns 0.
|
||||
*/
|
||||
static int32_t GetDriverMajorVersion()
|
||||
{
|
||||
return sMajorVersion;
|
||||
}
|
||||
/**
|
||||
* GetDriverMinorVersion() returns the installed driver's minor version.
|
||||
* If SynTP driver isn't installed, this returns -1.
|
||||
*/
|
||||
static int32_t GetDriverMinorVersion()
|
||||
{
|
||||
return sMinorVersion;
|
||||
}
|
||||
|
||||
static void Init();
|
||||
|
||||
private:
|
||||
static bool sInitialized;
|
||||
static int32_t sMajorVersion;
|
||||
static int32_t sMinorVersion;
|
||||
};
|
||||
|
||||
class Elantech {
|
||||
public:
|
||||
/**
|
||||
* GetDriverMajorVersion() returns the installed driver's major version.
|
||||
* If Elantech's driver was installed, returns 0.
|
||||
*/
|
||||
static int32_t GetDriverMajorVersion();
|
||||
|
||||
/**
|
||||
* IsHelperWindow() checks whether aWnd is a helper window of Elantech's
|
||||
* touchpad. Returns TRUE if so. Otherwise, FALSE.
|
||||
*/
|
||||
static bool IsHelperWindow(HWND aWnd);
|
||||
|
||||
/**
|
||||
* Key message handler for Elantech's hack. Returns TRUE if the message
|
||||
* is consumed by this handler. Otherwise, FALSE.
|
||||
*/
|
||||
static bool HandleKeyMessage(nsWindowBase* aWidget,
|
||||
UINT aMsg,
|
||||
WPARAM aWParam,
|
||||
LPARAM aLParam);
|
||||
|
||||
static void UpdateZoomUntil();
|
||||
static bool IsZooming();
|
||||
|
||||
static void Init();
|
||||
|
||||
static bool IsPinchHackNeeded() { return sUsePinchHack; }
|
||||
|
||||
|
||||
private:
|
||||
// Whether to enable the Elantech swipe gesture hack.
|
||||
static bool sUseSwipeHack;
|
||||
// Whether to enable the Elantech pinch-to-zoom gesture hack.
|
||||
static bool sUsePinchHack;
|
||||
static DWORD sZoomUntil;
|
||||
}; // class Elantech
|
||||
|
||||
// Apoint is a touchpad driver of Alps.
|
||||
class Apoint
|
||||
{
|
||||
public:
|
||||
static bool IsDriverInstalled()
|
||||
{
|
||||
return sMajorVersion != 0;
|
||||
}
|
||||
/**
|
||||
* GetDriverMajorVersion() returns the installed driver's major version.
|
||||
* If Apoint driver isn't installed, this returns 0.
|
||||
*/
|
||||
static int32_t GetDriverMajorVersion()
|
||||
{
|
||||
return sMajorVersion;
|
||||
}
|
||||
/**
|
||||
* GetDriverMinorVersion() returns the installed driver's minor version.
|
||||
* If Apoint driver isn't installed, this returns -1.
|
||||
*/
|
||||
static int32_t GetDriverMinorVersion()
|
||||
{
|
||||
return sMinorVersion;
|
||||
}
|
||||
|
||||
static void Init();
|
||||
|
||||
private:
|
||||
static bool sInitialized;
|
||||
static int32_t sMajorVersion;
|
||||
static int32_t sMinorVersion;
|
||||
};
|
||||
|
||||
class TrackPoint {
|
||||
public:
|
||||
/**
|
||||
* IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
|
||||
* Otherwise, returns FALSE.
|
||||
*/
|
||||
static bool IsDriverInstalled();
|
||||
}; // class TrackPoint
|
||||
|
||||
class UltraNav {
|
||||
public:
|
||||
/**
|
||||
* IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
|
||||
* is installed on the environment.
|
||||
* Returns TRUE if it was installed. Otherwise, FALSE.
|
||||
*/
|
||||
static bool IsObsoleteDriverInstalled();
|
||||
}; // class UltraNav
|
||||
|
||||
class SetPoint {
|
||||
public:
|
||||
/**
|
||||
* SetPoint, Logitech's mouse driver, may report wrong cursor position
|
||||
* for WM_MOUSEHWHEEL message. See comment in the implementation for
|
||||
* the detail.
|
||||
*/
|
||||
static bool IsGetMessagePosResponseValid(UINT aMessage,
|
||||
WPARAM aWParam,
|
||||
LPARAM aLParam);
|
||||
private:
|
||||
static bool sMightBeUsing;
|
||||
};
|
||||
|
||||
static void Init();
|
||||
|
||||
static bool IsFakeScrollableWindowNeeded()
|
||||
{
|
||||
return sFakeScrollableWindowNeeded;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Gets the bool value of aPrefName used to enable or disable an input
|
||||
* workaround (like the Trackpoint hack). The pref can take values 0 (for
|
||||
* disabled), 1 (for enabled) or -1 (to automatically detect whether to
|
||||
* enable the workaround).
|
||||
*
|
||||
* @param aPrefName The name of the pref.
|
||||
* @param aValueIfAutomatic Whether the given input workaround should be
|
||||
* enabled by default.
|
||||
*/
|
||||
static bool GetWorkaroundPref(const char* aPrefName,
|
||||
bool aValueIfAutomatic);
|
||||
|
||||
static bool sFakeScrollableWindowNeeded;
|
||||
}; // class Device
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_widget_WinMouseScrollHandler_h__
|
||||
56
widget/windows/WinNativeEventData.h
Normal file
56
widget/windows/WinNativeEventData.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_widget_WinNativeEventData_h_
|
||||
#define mozilla_widget_WinNativeEventData_h_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/widget/WinModifierKeyState.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
/**
|
||||
* WinNativeKeyEventData is used by nsIWidget::OnWindowedPluginKeyEvent() and
|
||||
* related IPC methods. This class cannot hold any pointers and references
|
||||
* since which are not available in different process.
|
||||
*/
|
||||
|
||||
class WinNativeKeyEventData final
|
||||
{
|
||||
public:
|
||||
UINT mMessage;
|
||||
WPARAM mWParam;
|
||||
LPARAM mLParam;
|
||||
Modifiers mModifiers;
|
||||
|
||||
private:
|
||||
uintptr_t mKeyboardLayout;
|
||||
|
||||
public:
|
||||
WinNativeKeyEventData(UINT aMessage,
|
||||
WPARAM aWParam,
|
||||
LPARAM aLParam,
|
||||
const ModifierKeyState& aModifierKeyState)
|
||||
: mMessage(aMessage)
|
||||
, mWParam(aWParam)
|
||||
, mLParam(aLParam)
|
||||
, mModifiers(aModifierKeyState.GetModifiers())
|
||||
, mKeyboardLayout(reinterpret_cast<uintptr_t>(::GetKeyboardLayout(0)))
|
||||
{
|
||||
}
|
||||
|
||||
HKL GetKeyboardLayout() const
|
||||
{
|
||||
return reinterpret_cast<HKL>(mKeyboardLayout);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // #ifndef mozilla_widget_WinNativeEventData_h_
|
||||
506
widget/windows/WinTaskbar.cpp
Normal file
506
widget/windows/WinTaskbar.cpp
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
/* 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 "WinTaskbar.h"
|
||||
#include "TaskbarPreview.h"
|
||||
#include <nsITaskbarPreviewController.h>
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include <nsError.h>
|
||||
#include <nsCOMPtr.h>
|
||||
#include <nsIWidget.h>
|
||||
#include <nsIBaseWindow.h>
|
||||
#include <nsIObserverService.h>
|
||||
#include <nsServiceManagerUtils.h>
|
||||
#include "nsIXULAppInfo.h"
|
||||
#include "nsIJumpListBuilder.h"
|
||||
#include "nsUXThemeData.h"
|
||||
#include "nsWindow.h"
|
||||
#include "WinUtils.h"
|
||||
#include "TaskbarTabPreview.h"
|
||||
#include "TaskbarWindowPreview.h"
|
||||
#include "JumpListBuilder.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include <io.h>
|
||||
#include <propvarutil.h>
|
||||
#include <propkey.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
const wchar_t kShellLibraryName[] = L"shell32.dll";
|
||||
|
||||
static NS_DEFINE_CID(kJumpListBuilderCID, NS_WIN_JUMPLISTBUILDER_CID);
|
||||
|
||||
namespace {
|
||||
|
||||
HWND
|
||||
GetHWNDFromDocShell(nsIDocShell *aShell) {
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(reinterpret_cast<nsISupports*>(aShell)));
|
||||
|
||||
if (!baseWindow)
|
||||
return nullptr;
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
baseWindow->GetMainWidget(getter_AddRefs(widget));
|
||||
|
||||
return widget ? (HWND)widget->GetNativeData(NS_NATIVE_WINDOW) : nullptr;
|
||||
}
|
||||
|
||||
HWND
|
||||
GetHWNDFromDOMWindow(mozIDOMWindow *dw) {
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
|
||||
if (!dw)
|
||||
return nullptr;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = nsPIDOMWindowInner::From(dw);
|
||||
return GetHWNDFromDocShell(window->GetDocShell());
|
||||
}
|
||||
|
||||
nsresult
|
||||
SetWindowAppUserModelProp(mozIDOMWindow *aParent,
|
||||
const nsString & aIdentifier) {
|
||||
NS_ENSURE_ARG_POINTER(aParent);
|
||||
|
||||
if (aIdentifier.IsEmpty())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDOMWindow(aParent), GA_ROOT);
|
||||
|
||||
if (!toplevelHWND)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
typedef HRESULT (WINAPI * SHGetPropertyStoreForWindowPtr)
|
||||
(HWND hwnd, REFIID riid, void** ppv);
|
||||
SHGetPropertyStoreForWindowPtr funcGetProStore = nullptr;
|
||||
|
||||
HMODULE hDLL = ::LoadLibraryW(kShellLibraryName);
|
||||
funcGetProStore = (SHGetPropertyStoreForWindowPtr)
|
||||
GetProcAddress(hDLL, "SHGetPropertyStoreForWindow");
|
||||
|
||||
if (!funcGetProStore) {
|
||||
FreeLibrary(hDLL);
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
IPropertyStore* pPropStore;
|
||||
if (FAILED(funcGetProStore(toplevelHWND,
|
||||
IID_PPV_ARGS(&pPropStore)))) {
|
||||
FreeLibrary(hDLL);
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
PROPVARIANT pv;
|
||||
if (FAILED(InitPropVariantFromString(aIdentifier.get(), &pv))) {
|
||||
pPropStore->Release();
|
||||
FreeLibrary(hDLL);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (FAILED(pPropStore->SetValue(PKEY_AppUserModel_ID, pv)) ||
|
||||
FAILED(pPropStore->Commit())) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
PropVariantClear(&pv);
|
||||
pPropStore->Release();
|
||||
FreeLibrary(hDLL);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// default nsITaskbarPreviewController
|
||||
|
||||
class DefaultController final : public nsITaskbarPreviewController
|
||||
{
|
||||
~DefaultController() {}
|
||||
HWND mWnd;
|
||||
public:
|
||||
DefaultController(HWND hWnd)
|
||||
: mWnd(hWnd)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITASKBARPREVIEWCONTROLLER
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::GetWidth(uint32_t *aWidth)
|
||||
{
|
||||
RECT r;
|
||||
::GetClientRect(mWnd, &r);
|
||||
*aWidth = r.right;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::GetHeight(uint32_t *aHeight)
|
||||
{
|
||||
RECT r;
|
||||
::GetClientRect(mWnd, &r);
|
||||
*aHeight = r.bottom;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::GetThumbnailAspectRatio(float *aThumbnailAspectRatio) {
|
||||
uint32_t width, height;
|
||||
GetWidth(&width);
|
||||
GetHeight(&height);
|
||||
if (!height)
|
||||
height = 1;
|
||||
|
||||
*aThumbnailAspectRatio = width/float(height);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
NS_IMETHODIMP
|
||||
DefaultController::DrawPreview(nsISupports *ctx, bool *rDrawFrame) {
|
||||
*rDrawFrame = true;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
NS_IMETHODIMP
|
||||
DefaultController::DrawThumbnail(nsISupports *ctx, uint32_t width, uint32_t height, bool *rDrawFrame) {
|
||||
*rDrawFrame = false;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::RequestThumbnail(nsITaskbarPreviewCallback *aCallback, uint32_t width, uint32_t height) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::RequestPreview(nsITaskbarPreviewCallback *aCallback) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::OnClose(void) {
|
||||
NS_NOTREACHED("OnClose should not be called for TaskbarWindowPreviews");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::OnActivate(bool *rAcceptActivation) {
|
||||
*rAcceptActivation = true;
|
||||
NS_NOTREACHED("OnActivate should not be called for TaskbarWindowPreviews");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DefaultController::OnClick(nsITaskbarPreviewButton *button) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(DefaultController, nsITaskbarPreviewController)
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// nsIWinTaskbar
|
||||
|
||||
NS_IMPL_ISUPPORTS(WinTaskbar, nsIWinTaskbar)
|
||||
|
||||
bool
|
||||
WinTaskbar::Initialize() {
|
||||
if (mTaskbar)
|
||||
return true;
|
||||
|
||||
::CoInitialize(nullptr);
|
||||
HRESULT hr = ::CoCreateInstance(CLSID_TaskbarList,
|
||||
nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_ITaskbarList4,
|
||||
(void**)&mTaskbar);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
hr = mTaskbar->HrInit();
|
||||
if (FAILED(hr)) {
|
||||
// This may fail with shell extensions like blackbox installed.
|
||||
NS_WARNING("Unable to initialize taskbar");
|
||||
NS_RELEASE(mTaskbar);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WinTaskbar::WinTaskbar()
|
||||
: mTaskbar(nullptr) {
|
||||
}
|
||||
|
||||
WinTaskbar::~WinTaskbar() {
|
||||
if (mTaskbar) { // match successful Initialize() call
|
||||
NS_RELEASE(mTaskbar);
|
||||
::CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
WinTaskbar::GetAppUserModelID(nsAString & aDefaultGroupId) {
|
||||
// If marked as such in prefs, use a hash of the profile path for the id
|
||||
// instead of the install path hash setup by the installer.
|
||||
bool useProfile =
|
||||
Preferences::GetBool("taskbar.grouping.useprofile", false);
|
||||
if (useProfile) {
|
||||
nsCOMPtr<nsIFile> profileDir;
|
||||
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||
getter_AddRefs(profileDir));
|
||||
bool exists = false;
|
||||
if (profileDir && NS_SUCCEEDED(profileDir->Exists(&exists)) && exists) {
|
||||
nsAutoCString path;
|
||||
if (NS_SUCCEEDED(profileDir->GetNativePath(path))) {
|
||||
nsAutoString id;
|
||||
id.AppendInt(HashString(path));
|
||||
if (!id.IsEmpty()) {
|
||||
aDefaultGroupId.Assign(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The default value is set by the installer and is stored in the registry
|
||||
// under (HKLM||HKCU)/Software/Mozilla/Firefox/TaskBarIDs. If for any reason
|
||||
// hash generation operation fails, the installer will not store a value in
|
||||
// the registry or set ids on shortcuts. A lack of an id can also occur for
|
||||
// zipped builds. We skip setting the global id in this case as well.
|
||||
nsCOMPtr<nsIXULAppInfo> appInfo =
|
||||
do_GetService("@mozilla.org/xre/app-info;1");
|
||||
if (!appInfo)
|
||||
return false;
|
||||
|
||||
nsCString appName;
|
||||
if (NS_FAILED(appInfo->GetName(appName))) {
|
||||
// We just won't register then, let Windows handle it.
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString regKey;
|
||||
regKey.AssignLiteral("Software\\Mozilla\\");
|
||||
AppendASCIItoUTF16(appName, regKey);
|
||||
regKey.AppendLiteral("\\TaskBarIDs");
|
||||
|
||||
WCHAR path[MAX_PATH];
|
||||
if (GetModuleFileNameW(nullptr, path, MAX_PATH)) {
|
||||
wchar_t* slash = wcsrchr(path, '\\');
|
||||
if (!slash)
|
||||
return false;
|
||||
*slash = '\0'; // no trailing slash
|
||||
|
||||
// The hash is short, but users may customize this, so use a respectable
|
||||
// string buffer.
|
||||
wchar_t buf[256];
|
||||
if (WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE,
|
||||
regKey.get(),
|
||||
path,
|
||||
buf,
|
||||
sizeof buf)) {
|
||||
aDefaultGroupId.Assign(buf);
|
||||
} else if (WinUtils::GetRegistryKey(HKEY_CURRENT_USER,
|
||||
regKey.get(),
|
||||
path,
|
||||
buf,
|
||||
sizeof buf)) {
|
||||
aDefaultGroupId.Assign(buf);
|
||||
}
|
||||
}
|
||||
|
||||
return !aDefaultGroupId.IsEmpty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::GetDefaultGroupId(nsAString & aDefaultGroupId) {
|
||||
if (!GetAppUserModelID(aDefaultGroupId))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// (static) Called from AppShell
|
||||
bool
|
||||
WinTaskbar::RegisterAppUserModelID() {
|
||||
if (!IsWin7OrLater())
|
||||
return false;
|
||||
|
||||
SetCurrentProcessExplicitAppUserModelIDPtr funcAppUserModelID = nullptr;
|
||||
bool retVal = false;
|
||||
|
||||
nsAutoString uid;
|
||||
if (!GetAppUserModelID(uid))
|
||||
return false;
|
||||
|
||||
HMODULE hDLL = ::LoadLibraryW(kShellLibraryName);
|
||||
|
||||
funcAppUserModelID = (SetCurrentProcessExplicitAppUserModelIDPtr)
|
||||
GetProcAddress(hDLL, "SetCurrentProcessExplicitAppUserModelID");
|
||||
|
||||
if (!funcAppUserModelID) {
|
||||
::FreeLibrary(hDLL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(funcAppUserModelID(uid.get())))
|
||||
retVal = true;
|
||||
|
||||
if (hDLL)
|
||||
::FreeLibrary(hDLL);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::GetAvailable(bool *aAvailable) {
|
||||
// ITaskbarList4::HrInit() may fail with shell extensions like blackbox
|
||||
// installed. Initialize early to return available=false in those cases.
|
||||
*aAvailable = IsWin7OrLater() && Initialize();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::CreateTaskbarTabPreview(nsIDocShell *shell, nsITaskbarPreviewController *controller, nsITaskbarTabPreview **_retval) {
|
||||
if (!Initialize())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(shell);
|
||||
NS_ENSURE_ARG_POINTER(controller);
|
||||
|
||||
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDocShell(shell), GA_ROOT);
|
||||
|
||||
if (!toplevelHWND)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
RefPtr<TaskbarTabPreview> preview(new TaskbarTabPreview(mTaskbar, controller, toplevelHWND, shell));
|
||||
if (!preview)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
preview.forget(_retval);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::GetTaskbarWindowPreview(nsIDocShell *shell, nsITaskbarWindowPreview **_retval) {
|
||||
if (!Initialize())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(shell);
|
||||
|
||||
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDocShell(shell), GA_ROOT);
|
||||
|
||||
if (!toplevelHWND)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsWindow *window = WinUtils::GetNSWindowPtr(toplevelHWND);
|
||||
|
||||
if (!window)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsITaskbarWindowPreview> preview = window->GetTaskbarPreview();
|
||||
if (!preview) {
|
||||
RefPtr<DefaultController> defaultController = new DefaultController(toplevelHWND);
|
||||
preview = new TaskbarWindowPreview(mTaskbar, defaultController, toplevelHWND, shell);
|
||||
if (!preview)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
window->SetTaskbarPreview(preview);
|
||||
}
|
||||
|
||||
preview.forget(_retval);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::GetTaskbarProgress(nsIDocShell *shell, nsITaskbarProgress **_retval) {
|
||||
nsCOMPtr<nsITaskbarWindowPreview> preview;
|
||||
nsresult rv = GetTaskbarWindowPreview(shell, getter_AddRefs(preview));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return CallQueryInterface(preview, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::GetOverlayIconController(nsIDocShell *shell,
|
||||
nsITaskbarOverlayIconController **_retval) {
|
||||
nsCOMPtr<nsITaskbarWindowPreview> preview;
|
||||
nsresult rv = GetTaskbarWindowPreview(shell, getter_AddRefs(preview));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return CallQueryInterface(preview, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::CreateJumpListBuilder(nsIJumpListBuilder * *aJumpListBuilder) {
|
||||
nsresult rv;
|
||||
|
||||
if (JumpListBuilder::sBuildingList)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
nsCOMPtr<nsIJumpListBuilder> builder =
|
||||
do_CreateInstance(kJumpListBuilderCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
NS_IF_ADDREF(*aJumpListBuilder = builder);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::SetGroupIdForWindow(mozIDOMWindow *aParent,
|
||||
const nsAString & aIdentifier) {
|
||||
return SetWindowAppUserModelProp(aParent, nsString(aIdentifier));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::PrepareFullScreen(mozIDOMWindow *aWindow, bool aFullScreen) {
|
||||
NS_ENSURE_ARG_POINTER(aWindow);
|
||||
|
||||
HWND toplevelHWND = ::GetAncestor(GetHWNDFromDOMWindow(aWindow), GA_ROOT);
|
||||
if (!toplevelHWND)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
return PrepareFullScreenHWND(toplevelHWND, aFullScreen);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTaskbar::PrepareFullScreenHWND(void *aHWND, bool aFullScreen) {
|
||||
if (!Initialize())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aHWND);
|
||||
|
||||
if (!::IsWindow((HWND)aHWND))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
HRESULT hr = mTaskbar->MarkFullscreenWindow((HWND)aHWND, aFullScreen);
|
||||
if (FAILED(hr)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
46
widget/windows/WinTaskbar.h
Normal file
46
widget/windows/WinTaskbar.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef __WinTaskbar_h__
|
||||
#define __WinTaskbar_h__
|
||||
|
||||
#include <windows.h>
|
||||
#include <shobjidl.h>
|
||||
#undef LogSeverity // SetupAPI.h #defines this as DWORD
|
||||
#include "nsIWinTaskbar.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class WinTaskbar final : public nsIWinTaskbar
|
||||
{
|
||||
~WinTaskbar();
|
||||
|
||||
public:
|
||||
WinTaskbar();
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIWINTASKBAR
|
||||
|
||||
// Registers the global app user model id for the instance.
|
||||
// See comments in WinTaskbar.cpp for more information.
|
||||
static bool RegisterAppUserModelID();
|
||||
static bool GetAppUserModelID(nsAString & aDefaultGroupId);
|
||||
|
||||
private:
|
||||
bool Initialize();
|
||||
|
||||
typedef HRESULT (WINAPI * SetCurrentProcessExplicitAppUserModelIDPtr)(PCWSTR AppID);
|
||||
ITaskbarList4 *mTaskbar;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __WinTaskbar_h__ */
|
||||
|
||||
78
widget/windows/WinTextEventDispatcherListener.cpp
Normal file
78
widget/windows/WinTextEventDispatcherListener.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- Mode: C++; tab-width: 4; 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 "KeyboardLayout.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
#include "mozilla/widget/IMEData.h"
|
||||
#include "nsWindow.h"
|
||||
#include "WinIMEHandler.h"
|
||||
#include "WinTextEventDispatcherListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
StaticRefPtr<WinTextEventDispatcherListener>
|
||||
WinTextEventDispatcherListener::sInstance;
|
||||
|
||||
// static
|
||||
WinTextEventDispatcherListener*
|
||||
WinTextEventDispatcherListener::GetInstance()
|
||||
{
|
||||
if (!sInstance) {
|
||||
sInstance = new WinTextEventDispatcherListener();
|
||||
}
|
||||
return sInstance.get();
|
||||
}
|
||||
|
||||
void
|
||||
WinTextEventDispatcherListener::Shutdown()
|
||||
{
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(WinTextEventDispatcherListener,
|
||||
TextEventDispatcherListener,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
WinTextEventDispatcherListener::WinTextEventDispatcherListener()
|
||||
{
|
||||
}
|
||||
|
||||
WinTextEventDispatcherListener::~WinTextEventDispatcherListener()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WinTextEventDispatcherListener::NotifyIME(
|
||||
TextEventDispatcher* aTextEventDispatcher,
|
||||
const IMENotification& aNotification)
|
||||
{
|
||||
nsWindow* window = static_cast<nsWindow*>(aTextEventDispatcher->GetWidget());
|
||||
if (NS_WARN_IF(!window)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return IMEHandler::NotifyIME(window, aNotification);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
WinTextEventDispatcherListener::OnRemovedFrom(
|
||||
TextEventDispatcher* aTextEventDispatcher)
|
||||
{
|
||||
// XXX When input transaction is being stolen by add-on, what should we do?
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
WinTextEventDispatcherListener::WillDispatchKeyboardEvent(
|
||||
TextEventDispatcher* aTextEventDispatcher,
|
||||
WidgetKeyboardEvent& aKeyboardEvent,
|
||||
uint32_t aIndexOfKeypress,
|
||||
void* aData)
|
||||
{
|
||||
static_cast<NativeKey*>(aData)->
|
||||
WillDispatchKeyboardEvent(aKeyboardEvent, aIndexOfKeypress);
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
50
widget/windows/WinTextEventDispatcherListener.h
Normal file
50
widget/windows/WinTextEventDispatcherListener.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: C++; tab-width: 4; 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/. */
|
||||
|
||||
#ifndef WinTextEventDispatcherListener_h_
|
||||
#define WinTextEventDispatcherListener_h_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/TextEventDispatcherListener.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
/**
|
||||
* On Windows, it's enough TextEventDispatcherListener to be a singleton
|
||||
* because we have only one input context per process (IMM can create
|
||||
* multiple IM context but we don't support such behavior).
|
||||
*/
|
||||
|
||||
class WinTextEventDispatcherListener final : public TextEventDispatcherListener
|
||||
{
|
||||
public:
|
||||
static WinTextEventDispatcherListener* GetInstance();
|
||||
static void Shutdown();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,
|
||||
const IMENotification& aNotification) override;
|
||||
NS_IMETHOD_(void) OnRemovedFrom(
|
||||
TextEventDispatcher* aTextEventDispatcher) override;
|
||||
NS_IMETHOD_(void) WillDispatchKeyboardEvent(
|
||||
TextEventDispatcher* aTextEventDispatcher,
|
||||
WidgetKeyboardEvent& aKeyboardEvent,
|
||||
uint32_t aIndexOfKeypress,
|
||||
void* aData) override;
|
||||
|
||||
private:
|
||||
WinTextEventDispatcherListener();
|
||||
virtual ~WinTextEventDispatcherListener();
|
||||
|
||||
static StaticRefPtr<WinTextEventDispatcherListener> sInstance;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // #ifndef WinTextEventDispatcherListener_h_
|
||||
2110
widget/windows/WinUtils.cpp
Normal file
2110
widget/windows/WinUtils.cpp
Normal file
File diff suppressed because it is too large
Load diff
648
widget/windows/WinUtils.h
Normal file
648
widget/windows/WinUtils.h
Normal file
|
|
@ -0,0 +1,648 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_widget_WinUtils_h__
|
||||
#define mozilla_widget_WinUtils_h__
|
||||
|
||||
#include "nscore.h"
|
||||
#include <windows.h>
|
||||
#include <shobjidl.h>
|
||||
#include <uxtheme.h>
|
||||
#include <dwmapi.h>
|
||||
|
||||
// Undo the windows.h damage
|
||||
#undef GetMessage
|
||||
#undef CreateEvent
|
||||
#undef GetClassName
|
||||
#undef GetBinaryType
|
||||
#undef RemoveDirectory
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsRegion.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#ifdef MOZ_PLACES
|
||||
#include "nsIFaviconService.h"
|
||||
#endif
|
||||
#include "nsIDownloader.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIThread.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
/**
|
||||
* NS_INLINE_DECL_IUNKNOWN_REFCOUNTING should be used for defining and
|
||||
* implementing AddRef() and Release() of IUnknown interface.
|
||||
* This depends on xpcom/glue/nsISupportsImpl.h.
|
||||
*/
|
||||
|
||||
#define NS_INLINE_DECL_IUNKNOWN_REFCOUNTING(_class) \
|
||||
public: \
|
||||
STDMETHODIMP_(ULONG) AddRef() \
|
||||
{ \
|
||||
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
|
||||
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
|
||||
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||
++mRefCnt; \
|
||||
NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \
|
||||
return static_cast<ULONG>(mRefCnt.get()); \
|
||||
} \
|
||||
STDMETHODIMP_(ULONG) Release() \
|
||||
{ \
|
||||
MOZ_ASSERT(int32_t(mRefCnt) > 0, \
|
||||
"Release called on object that has already been released!"); \
|
||||
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||
--mRefCnt; \
|
||||
NS_LOG_RELEASE(this, mRefCnt, #_class); \
|
||||
if (mRefCnt == 0) { \
|
||||
NS_ASSERT_OWNINGTHREAD(_class); \
|
||||
mRefCnt = 1; /* stabilize */ \
|
||||
delete this; \
|
||||
return 0; \
|
||||
} \
|
||||
return static_cast<ULONG>(mRefCnt.get()); \
|
||||
} \
|
||||
protected: \
|
||||
nsAutoRefCnt mRefCnt; \
|
||||
NS_DECL_OWNINGTHREAD \
|
||||
public:
|
||||
|
||||
class nsWindow;
|
||||
class nsWindowBase;
|
||||
struct KeyPair;
|
||||
|
||||
#if !defined(DPI_AWARENESS_CONTEXT_DECLARED) && !defined(DPI_AWARENESS_CONTEXT_UNAWARE)
|
||||
|
||||
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
||||
|
||||
typedef enum DPI_AWARENESS {
|
||||
DPI_AWARENESS_INVALID = -1,
|
||||
DPI_AWARENESS_UNAWARE = 0,
|
||||
DPI_AWARENESS_SYSTEM_AWARE = 1,
|
||||
DPI_AWARENESS_PER_MONITOR_AWARE = 2
|
||||
} DPI_AWARENESS;
|
||||
|
||||
#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
|
||||
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2)
|
||||
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
|
||||
|
||||
#define DPI_AWARENESS_CONTEXT_DECLARED
|
||||
#endif // (DPI_AWARENESS_CONTEXT_DECLARED)
|
||||
|
||||
typedef DPI_AWARENESS_CONTEXT(WINAPI * SetThreadDpiAwarenessContextProc)(DPI_AWARENESS_CONTEXT);
|
||||
typedef BOOL(WINAPI * EnableNonClientDpiScalingProc)(HWND);
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
// Windows message debugging data
|
||||
typedef struct {
|
||||
const char * mStr;
|
||||
UINT mId;
|
||||
} EventMsgInfo;
|
||||
extern EventMsgInfo gAllEvents[];
|
||||
|
||||
// More complete QS definitions for MsgWaitForMultipleObjects() and
|
||||
// GetQueueStatus() that include newer win8 specific defines.
|
||||
|
||||
#ifndef QS_RAWINPUT
|
||||
#define QS_RAWINPUT 0x0400
|
||||
#endif
|
||||
|
||||
#ifndef QS_TOUCH
|
||||
#define QS_TOUCH 0x0800
|
||||
#define QS_POINTER 0x1000
|
||||
#endif
|
||||
|
||||
#define MOZ_QS_ALLEVENT (QS_KEY | QS_MOUSEMOVE | QS_MOUSEBUTTON | \
|
||||
QS_POSTMESSAGE | QS_TIMER | QS_PAINT | \
|
||||
QS_SENDMESSAGE | QS_HOTKEY | \
|
||||
QS_ALLPOSTMESSAGE | QS_RAWINPUT | \
|
||||
QS_TOUCH | QS_POINTER)
|
||||
|
||||
// Logging macros
|
||||
#define LogFunction() mozilla::widget::WinUtils::Log(__FUNCTION__)
|
||||
#define LogThread() mozilla::widget::WinUtils::Log("%s: IsMainThread:%d ThreadId:%X", __FUNCTION__, NS_IsMainThread(), GetCurrentThreadId())
|
||||
#define LogThis() mozilla::widget::WinUtils::Log("[%X] %s", this, __FUNCTION__)
|
||||
#define LogException(e) mozilla::widget::WinUtils::Log("%s Exception:%s", __FUNCTION__, e->ToString()->Data())
|
||||
#define LogHRESULT(hr) mozilla::widget::WinUtils::Log("%s hr=%X", __FUNCTION__, hr)
|
||||
|
||||
#ifdef MOZ_PLACES
|
||||
class myDownloadObserver final : public nsIDownloadObserver
|
||||
{
|
||||
~myDownloadObserver() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOWNLOADOBSERVER
|
||||
};
|
||||
#endif
|
||||
|
||||
class WinUtils
|
||||
{
|
||||
// Function pointers for APIs that may not be available depending on
|
||||
// the Win10 update version -- will be set up in Initialize().
|
||||
static SetThreadDpiAwarenessContextProc sSetThreadDpiAwarenessContext;
|
||||
static EnableNonClientDpiScalingProc sEnableNonClientDpiScaling;
|
||||
|
||||
public:
|
||||
class AutoSystemDpiAware
|
||||
{
|
||||
public:
|
||||
AutoSystemDpiAware()
|
||||
{
|
||||
if (sSetThreadDpiAwarenessContext) {
|
||||
mPrevContext = sSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
|
||||
}
|
||||
}
|
||||
|
||||
~AutoSystemDpiAware()
|
||||
{
|
||||
if (sSetThreadDpiAwarenessContext) {
|
||||
sSetThreadDpiAwarenessContext(mPrevContext);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DPI_AWARENESS_CONTEXT mPrevContext;
|
||||
};
|
||||
|
||||
// Wrapper for DefWindowProc that will enable non-client dpi scaling on the
|
||||
// window during creation.
|
||||
static LRESULT WINAPI
|
||||
NonClientDpiScalingDefWindowProcW(HWND hWnd, UINT msg,
|
||||
WPARAM wParam, LPARAM lParam);
|
||||
|
||||
/**
|
||||
* Get the system's default logical-to-physical DPI scaling factor,
|
||||
* which is based on the primary display. Note however that unlike
|
||||
* LogToPhysFactor(GetPrimaryMonitor()), this will not change during
|
||||
* a session even if the displays are reconfigured. This scale factor
|
||||
* is used by Windows theme metrics etc, which do not fully support
|
||||
* dynamic resolution changes but are only updated on logout.
|
||||
*/
|
||||
static double SystemScaleFactor();
|
||||
|
||||
static bool IsPerMonitorDPIAware();
|
||||
/**
|
||||
* Functions to convert between logical pixels as used by most Windows APIs
|
||||
* and physical (device) pixels.
|
||||
*/
|
||||
static double LogToPhysFactor(HMONITOR aMonitor);
|
||||
static double LogToPhysFactor(HWND aWnd) {
|
||||
// if there's an ancestor window, we want to share its DPI setting
|
||||
HWND ancestor = ::GetAncestor(aWnd, GA_ROOTOWNER);
|
||||
return LogToPhysFactor(::MonitorFromWindow(ancestor ? ancestor : aWnd,
|
||||
MONITOR_DEFAULTTOPRIMARY));
|
||||
}
|
||||
static double LogToPhysFactor(HDC aDC) {
|
||||
return LogToPhysFactor(::WindowFromDC(aDC));
|
||||
}
|
||||
static int32_t LogToPhys(HMONITOR aMonitor, double aValue);
|
||||
static HMONITOR GetPrimaryMonitor();
|
||||
static HMONITOR MonitorFromRect(const gfx::Rect& rect);
|
||||
|
||||
/**
|
||||
* Logging helpers that dump output to prlog module 'Widget', console, and
|
||||
* OutputDebugString. Note these output in both debug and release builds.
|
||||
*/
|
||||
static void Log(const char *fmt, ...);
|
||||
static void LogW(const wchar_t *fmt, ...);
|
||||
|
||||
/**
|
||||
* PeekMessage() and GetMessage() are wrapper methods for PeekMessageW(),
|
||||
* GetMessageW(), ITfMessageMgr::PeekMessageW() and
|
||||
* ITfMessageMgr::GetMessageW().
|
||||
* Don't call the native APIs directly. You MUST use these methods instead.
|
||||
*/
|
||||
static bool PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
|
||||
UINT aLastMessage, UINT aOption);
|
||||
static bool GetMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
|
||||
UINT aLastMessage);
|
||||
|
||||
/**
|
||||
* Wait until a message is ready to be processed.
|
||||
* Prefer using this method to directly calling ::WaitMessage since
|
||||
* ::WaitMessage will wait if there is an unread message in the queue.
|
||||
* That can cause freezes until another message enters the queue if the
|
||||
* message is marked read by a call to PeekMessage which the caller is
|
||||
* not aware of (e.g., from a different thread).
|
||||
* Note that this method may cause sync dispatch of sent (as opposed to
|
||||
* posted) messages.
|
||||
* @param aTimeoutMs Timeout for waiting in ms, defaults to INFINITE
|
||||
*/
|
||||
static void WaitForMessage(DWORD aTimeoutMs = INFINITE);
|
||||
|
||||
/**
|
||||
* Gets the value of a string-typed registry value.
|
||||
*
|
||||
* @param aRoot The registry root to search in.
|
||||
* @param aKeyName The name of the registry key to open.
|
||||
* @param aValueName The name of the registry value in the specified key whose
|
||||
* value is to be retrieved. Can be null, to retrieve the key's unnamed/
|
||||
* default value.
|
||||
* @param aBuffer The buffer into which to store the string value. Can be
|
||||
* null, in which case the return value indicates just whether the value
|
||||
* exists.
|
||||
* @param aBufferLength The size of aBuffer, in bytes.
|
||||
* @return Whether the value exists and is a string.
|
||||
*/
|
||||
static bool GetRegistryKey(HKEY aRoot,
|
||||
char16ptr_t aKeyName,
|
||||
char16ptr_t aValueName,
|
||||
wchar_t* aBuffer,
|
||||
DWORD aBufferLength);
|
||||
|
||||
/**
|
||||
* Checks whether the registry key exists in either 32bit or 64bit branch on
|
||||
* the environment.
|
||||
*
|
||||
* @param aRoot The registry root of aName.
|
||||
* @param aKeyName The name of the registry key to check.
|
||||
* @return TRUE if it exists and is readable. Otherwise, FALSE.
|
||||
*/
|
||||
static bool HasRegistryKey(HKEY aRoot,
|
||||
char16ptr_t aKeyName);
|
||||
|
||||
/**
|
||||
* GetTopLevelHWND() returns a window handle of the top level window which
|
||||
* aWnd belongs to. Note that the result may not be our window, i.e., it
|
||||
* may not be managed by nsWindow.
|
||||
*
|
||||
* See follwing table for the detail of the result window type.
|
||||
*
|
||||
* +-------------------------+-----------------------------------------------+
|
||||
* | | aStopIfNotPopup |
|
||||
* +-------------------------+-----------------------+-----------------------+
|
||||
* | | TRUE | FALSE |
|
||||
+ +-----------------+-------+-----------------------+-----------------------+
|
||||
* | | | * an independent top level window |
|
||||
* | | TRUE | * a pupup window (WS_POPUP) |
|
||||
* | | | * an owned top level window (like dialog) |
|
||||
* | aStopIfNotChild +-------+-----------------------+-----------------------+
|
||||
* | | | * independent window | * only an independent |
|
||||
* | | FALSE | * non-popup-owned- | top level window |
|
||||
* | | | window like dialog | |
|
||||
* +-----------------+-------+-----------------------+-----------------------+
|
||||
*/
|
||||
static HWND GetTopLevelHWND(HWND aWnd,
|
||||
bool aStopIfNotChild = false,
|
||||
bool aStopIfNotPopup = true);
|
||||
|
||||
/**
|
||||
* SetNSWindowBasePtr() associates an nsWindowBase to aWnd. If aWidget is
|
||||
* nullptr, it dissociate any nsBaseWidget pointer from aWnd.
|
||||
* GetNSWindowBasePtr() returns an nsWindowBase pointer which was associated by
|
||||
* SetNSWindowBasePtr().
|
||||
* GetNSWindowPtr() is a legacy api for win32 nsWindow and should be avoided
|
||||
* outside of nsWindow src.
|
||||
*/
|
||||
static bool SetNSWindowBasePtr(HWND aWnd, nsWindowBase* aWidget);
|
||||
static nsWindowBase* GetNSWindowBasePtr(HWND aWnd);
|
||||
static nsWindow* GetNSWindowPtr(HWND aWnd);
|
||||
|
||||
/**
|
||||
* GetMonitorCount() returns count of monitors on the environment.
|
||||
*/
|
||||
static int32_t GetMonitorCount();
|
||||
|
||||
/**
|
||||
* IsOurProcessWindow() returns TRUE if aWnd belongs our process.
|
||||
* Otherwise, FALSE.
|
||||
*/
|
||||
static bool IsOurProcessWindow(HWND aWnd);
|
||||
|
||||
/**
|
||||
* FindOurProcessWindow() returns the nearest ancestor window which
|
||||
* belongs to our process. If it fails to find our process's window by the
|
||||
* top level window, returns nullptr. And note that this is using
|
||||
* ::GetParent() for climbing the window hierarchy, therefore, it gives
|
||||
* up at an owned top level window except popup window (e.g., dialog).
|
||||
*/
|
||||
static HWND FindOurProcessWindow(HWND aWnd);
|
||||
|
||||
/**
|
||||
* FindOurWindowAtPoint() returns the topmost child window which belongs to
|
||||
* our process's top level window.
|
||||
*
|
||||
* NOTE: the topmost child window may NOT be our process's window like a
|
||||
* plugin's window.
|
||||
*/
|
||||
static HWND FindOurWindowAtPoint(const POINT& aPointInScreen);
|
||||
|
||||
/**
|
||||
* InitMSG() returns an MSG struct which was initialized by the params.
|
||||
* Don't trust the other members in the result.
|
||||
*/
|
||||
static MSG InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam, HWND aWnd);
|
||||
|
||||
/**
|
||||
* GetScanCode() returns a scan code for the LPARAM of WM_KEYDOWN, WM_KEYUP,
|
||||
* WM_CHAR and WM_UNICHAR.
|
||||
*
|
||||
*/
|
||||
static WORD GetScanCode(LPARAM aLParam)
|
||||
{
|
||||
return (aLParam >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* IsExtendedScanCode() returns TRUE if the LPARAM indicates the key message
|
||||
* is an extended key event.
|
||||
*/
|
||||
static bool IsExtendedScanCode(LPARAM aLParam)
|
||||
{
|
||||
return (aLParam & 0x1000000) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetInternalMessage() converts a native message to an internal message.
|
||||
* If there is no internal message for the given native message, returns
|
||||
* the native message itself.
|
||||
*/
|
||||
static UINT GetInternalMessage(UINT aNativeMessage);
|
||||
|
||||
/**
|
||||
* GetNativeMessage() converts an internal message to a native message.
|
||||
* If aInternalMessage is a native message, returns the native message itself.
|
||||
*/
|
||||
static UINT GetNativeMessage(UINT aInternalMessage);
|
||||
|
||||
/**
|
||||
* GetMouseInputSource() returns a pointing device information. The value is
|
||||
* one of nsIDOMMouseEvent::MOZ_SOURCE_*. This method MUST be called during
|
||||
* mouse message handling.
|
||||
*/
|
||||
static uint16_t GetMouseInputSource();
|
||||
|
||||
/**
|
||||
* Windows also fires mouse window messages for pens and touches, so we should
|
||||
* retrieve their pointer ID on receiving mouse events as well. Please refer to
|
||||
* https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320(v=vs.85).aspx
|
||||
*/
|
||||
static uint16_t GetMousePointerID();
|
||||
|
||||
static bool GetIsMouseFromTouch(EventMessage aEventType);
|
||||
|
||||
/**
|
||||
* SHCreateItemFromParsingName() calls native SHCreateItemFromParsingName()
|
||||
* API which is available on Vista and up.
|
||||
*/
|
||||
static HRESULT SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc,
|
||||
REFIID riid, void **ppv);
|
||||
|
||||
/**
|
||||
* SHGetKnownFolderPath() calls native SHGetKnownFolderPath()
|
||||
* API which is available on Vista and up.
|
||||
*/
|
||||
static HRESULT SHGetKnownFolderPath(REFKNOWNFOLDERID rfid,
|
||||
DWORD dwFlags,
|
||||
HANDLE hToken,
|
||||
PWSTR *ppszPath);
|
||||
/**
|
||||
* GetShellItemPath return the file or directory path of a shell item.
|
||||
* Internally calls IShellItem's GetDisplayName.
|
||||
*
|
||||
* aItem the shell item containing the path.
|
||||
* aResultString the resulting string path.
|
||||
* returns true if a path was retreived.
|
||||
*/
|
||||
static bool GetShellItemPath(IShellItem* aItem,
|
||||
nsString& aResultString);
|
||||
|
||||
/**
|
||||
* ConvertHRGNToRegion converts a Windows HRGN to an nsIntRegion.
|
||||
*
|
||||
* aRgn the HRGN to convert.
|
||||
* returns the nsIntRegion.
|
||||
*/
|
||||
static nsIntRegion ConvertHRGNToRegion(HRGN aRgn);
|
||||
|
||||
/**
|
||||
* ToIntRect converts a Windows RECT to a nsIntRect.
|
||||
*
|
||||
* aRect the RECT to convert.
|
||||
* returns the nsIntRect.
|
||||
*/
|
||||
static nsIntRect ToIntRect(const RECT& aRect);
|
||||
|
||||
/**
|
||||
* Helper used in invalidating flash plugin windows owned
|
||||
* by low rights flash containers.
|
||||
*/
|
||||
static void InvalidatePluginAsWorkaround(nsIWidget* aWidget,
|
||||
const LayoutDeviceIntRect& aRect);
|
||||
|
||||
/**
|
||||
* Returns true if the context or IME state is enabled. Otherwise, false.
|
||||
*/
|
||||
static bool IsIMEEnabled(const InputContext& aInputContext);
|
||||
static bool IsIMEEnabled(IMEState::Enabled aIMEState);
|
||||
|
||||
/**
|
||||
* Returns modifier key array for aModifiers. This is for
|
||||
* nsIWidget::SynthethizeNative*Event().
|
||||
*/
|
||||
static void SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray,
|
||||
uint32_t aModifiers);
|
||||
|
||||
/**
|
||||
* Does device have touch support
|
||||
*/
|
||||
static uint32_t IsTouchDeviceSupportPresent();
|
||||
|
||||
/**
|
||||
* The maximum number of simultaneous touch contacts supported by the device.
|
||||
* In the case of devices with multiple digitizers (e.g. multiple touch screens),
|
||||
* the value will be the maximum of the set of maximum supported contacts by
|
||||
* each individual digitizer.
|
||||
*/
|
||||
static uint32_t GetMaxTouchPoints();
|
||||
|
||||
/**
|
||||
* Fully resolves a path to its final path name. So if path contains
|
||||
* junction points or symlinks to other folders, we'll resolve the path
|
||||
* fully to the actual path that the links target.
|
||||
*
|
||||
* @param aPath path to be resolved.
|
||||
* @return true if successful, including if nothing needs to be changed.
|
||||
* false if something failed or aPath does not exist, aPath will
|
||||
* remain unchanged.
|
||||
*/
|
||||
static bool ResolveJunctionPointsAndSymLinks(std::wstring& aPath);
|
||||
|
||||
/**
|
||||
* dwmapi.dll function typedefs and declarations
|
||||
*/
|
||||
typedef HRESULT (WINAPI*DwmExtendFrameIntoClientAreaProc)(HWND hWnd, const MARGINS *pMarInset);
|
||||
typedef HRESULT (WINAPI*DwmIsCompositionEnabledProc)(BOOL *pfEnabled);
|
||||
typedef HRESULT (WINAPI*DwmSetIconicThumbnailProc)(HWND hWnd, HBITMAP hBitmap, DWORD dwSITFlags);
|
||||
typedef HRESULT (WINAPI*DwmSetIconicLivePreviewBitmapProc)(HWND hWnd, HBITMAP hBitmap, POINT *pptClient, DWORD dwSITFlags);
|
||||
typedef HRESULT (WINAPI*DwmGetWindowAttributeProc)(HWND hWnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
|
||||
typedef HRESULT (WINAPI*DwmSetWindowAttributeProc)(HWND hWnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
|
||||
typedef HRESULT (WINAPI*DwmInvalidateIconicBitmapsProc)(HWND hWnd);
|
||||
typedef HRESULT (WINAPI*DwmDefWindowProcProc)(HWND hWnd, UINT msg, LPARAM lParam, WPARAM wParam, LRESULT *aRetValue);
|
||||
typedef HRESULT (WINAPI*DwmGetCompositionTimingInfoProc)(HWND hWnd, DWM_TIMING_INFO *info);
|
||||
typedef HRESULT (WINAPI*DwmFlushProc)(void);
|
||||
|
||||
static DwmExtendFrameIntoClientAreaProc dwmExtendFrameIntoClientAreaPtr;
|
||||
static DwmIsCompositionEnabledProc dwmIsCompositionEnabledPtr;
|
||||
static DwmSetIconicThumbnailProc dwmSetIconicThumbnailPtr;
|
||||
static DwmSetIconicLivePreviewBitmapProc dwmSetIconicLivePreviewBitmapPtr;
|
||||
static DwmGetWindowAttributeProc dwmGetWindowAttributePtr;
|
||||
static DwmSetWindowAttributeProc dwmSetWindowAttributePtr;
|
||||
static DwmInvalidateIconicBitmapsProc dwmInvalidateIconicBitmapsPtr;
|
||||
static DwmDefWindowProcProc dwmDwmDefWindowProcPtr;
|
||||
static DwmGetCompositionTimingInfoProc dwmGetCompositionTimingInfoPtr;
|
||||
static DwmFlushProc dwmFlushProcPtr;
|
||||
|
||||
static void Initialize();
|
||||
|
||||
static bool ShouldHideScrollbars();
|
||||
|
||||
/**
|
||||
* This function normalizes the input path, converts short filenames to long
|
||||
* filenames, and substitutes environment variables for system paths.
|
||||
* The resulting output string length is guaranteed to be <= MAX_PATH.
|
||||
*/
|
||||
static bool SanitizePath(const wchar_t* aInputPath, nsAString& aOutput);
|
||||
|
||||
/**
|
||||
* Retrieve a semicolon-delimited list of DLL files derived from AppInit_DLLs
|
||||
*/
|
||||
static bool GetAppInitDLLs(nsAString& aOutput);
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
static void SetAPCPending();
|
||||
#endif
|
||||
|
||||
private:
|
||||
typedef HRESULT (WINAPI * SHCreateItemFromParsingNamePtr)(PCWSTR pszPath,
|
||||
IBindCtx *pbc,
|
||||
REFIID riid,
|
||||
void **ppv);
|
||||
static SHCreateItemFromParsingNamePtr sCreateItemFromParsingName;
|
||||
typedef HRESULT (WINAPI * SHGetKnownFolderPathPtr)(REFKNOWNFOLDERID rfid,
|
||||
DWORD dwFlags,
|
||||
HANDLE hToken,
|
||||
PWSTR *ppszPath);
|
||||
static SHGetKnownFolderPathPtr sGetKnownFolderPath;
|
||||
|
||||
static void GetWhitelistedPaths(
|
||||
nsTArray<mozilla::Pair<nsString,nsDependentString>>& aOutput);
|
||||
};
|
||||
|
||||
#ifdef MOZ_PLACES
|
||||
class AsyncFaviconDataReady final : public nsIFaviconDataCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFAVICONDATACALLBACK
|
||||
|
||||
AsyncFaviconDataReady(nsIURI *aNewURI,
|
||||
nsCOMPtr<nsIThread> &aIOThread,
|
||||
const bool aURLShortcut);
|
||||
nsresult OnFaviconDataNotAvailable(void);
|
||||
private:
|
||||
~AsyncFaviconDataReady() {}
|
||||
|
||||
nsCOMPtr<nsIURI> mNewURI;
|
||||
nsCOMPtr<nsIThread> mIOThread;
|
||||
const bool mURLShortcut;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Asynchronously tries add the list to the build
|
||||
*/
|
||||
class AsyncEncodeAndWriteIcon : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
const bool mURLShortcut;
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
// Warning: AsyncEncodeAndWriteIcon assumes ownership of the aData buffer passed in
|
||||
AsyncEncodeAndWriteIcon(const nsAString &aIconPath,
|
||||
UniquePtr<uint8_t[]> aData,
|
||||
uint32_t aStride, uint32_t aWidth, uint32_t aHeight,
|
||||
const bool aURLShortcut);
|
||||
|
||||
private:
|
||||
virtual ~AsyncEncodeAndWriteIcon();
|
||||
|
||||
nsAutoString mIconPath;
|
||||
UniquePtr<uint8_t[]> mBuffer;
|
||||
uint32_t mStride;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
};
|
||||
|
||||
|
||||
class AsyncDeleteIconFromDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
AsyncDeleteIconFromDisk(const nsAString &aIconPath);
|
||||
|
||||
private:
|
||||
virtual ~AsyncDeleteIconFromDisk();
|
||||
|
||||
nsAutoString mIconPath;
|
||||
};
|
||||
|
||||
class AsyncDeleteAllFaviconsFromDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
AsyncDeleteAllFaviconsFromDisk(bool aIgnoreRecent = false);
|
||||
|
||||
private:
|
||||
virtual ~AsyncDeleteAllFaviconsFromDisk();
|
||||
|
||||
int32_t mIcoNoDeleteSeconds;
|
||||
bool mIgnoreRecent;
|
||||
};
|
||||
|
||||
class FaviconHelper
|
||||
{
|
||||
public:
|
||||
static const char kJumpListCacheDir[];
|
||||
static const char kShortcutCacheDir[];
|
||||
static nsresult ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsString &aICOFilePath,
|
||||
nsCOMPtr<nsIThread> &aIOThread,
|
||||
bool aURLShortcut);
|
||||
|
||||
static nsresult HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash,
|
||||
nsIURI *aUri,
|
||||
nsACString& aUriHash);
|
||||
|
||||
static nsresult GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> &aICOFile,
|
||||
bool aURLShortcut);
|
||||
|
||||
static nsresult
|
||||
CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> aICOFile,
|
||||
nsCOMPtr<nsIThread> &aIOThread,
|
||||
bool aURLShortcut);
|
||||
|
||||
static int32_t GetICOCacheSecondsTimeout();
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_widget_WinUtils_h__
|
||||
129
widget/windows/WindowHook.cpp
Normal file
129
widget/windows/WindowHook.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/* -*- 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 "WindowHook.h"
|
||||
#include "nsWindow.h"
|
||||
#include "nsWindowDefs.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
nsresult
|
||||
WindowHook::AddHook(UINT nMsg, Callback callback, void *context) {
|
||||
MessageData *data = LookupOrCreate(nMsg);
|
||||
|
||||
if (!data)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Ensure we don't overwrite another hook
|
||||
NS_ENSURE_TRUE(nullptr == data->hook.cb, NS_ERROR_UNEXPECTED);
|
||||
|
||||
data->hook = CallbackData(callback, context);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WindowHook::RemoveHook(UINT nMsg, Callback callback, void *context) {
|
||||
CallbackData cbdata(callback, context);
|
||||
MessageData *data = Lookup(nMsg);
|
||||
if (!data)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
if (data->hook != cbdata)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
data->hook = CallbackData();
|
||||
|
||||
DeleteIfEmpty(data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WindowHook::AddMonitor(UINT nMsg, Callback callback, void *context) {
|
||||
MessageData *data = LookupOrCreate(nMsg);
|
||||
return (data && data->monitors.AppendElement(CallbackData(callback, context)))
|
||||
? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WindowHook::RemoveMonitor(UINT nMsg, Callback callback, void *context) {
|
||||
CallbackData cbdata(callback, context);
|
||||
MessageData *data = Lookup(nMsg);
|
||||
if (!data)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
CallbackDataArray::index_type idx = data->monitors.IndexOf(cbdata);
|
||||
if (idx == CallbackDataArray::NoIndex)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
data->monitors.RemoveElementAt(idx);
|
||||
DeleteIfEmpty(data);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
WindowHook::MessageData *
|
||||
WindowHook::Lookup(UINT nMsg) {
|
||||
MessageDataArray::index_type idx;
|
||||
for (idx = 0; idx < mMessageData.Length(); idx++) {
|
||||
MessageData &data = mMessageData[idx];
|
||||
if (data.nMsg == nMsg)
|
||||
return &data;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WindowHook::MessageData *
|
||||
WindowHook::LookupOrCreate(UINT nMsg) {
|
||||
MessageData *data = Lookup(nMsg);
|
||||
if (!data) {
|
||||
data = mMessageData.AppendElement();
|
||||
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
data->nMsg = nMsg;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
WindowHook::DeleteIfEmpty(MessageData *data) {
|
||||
// Never remove a MessageData that has still a hook or monitor entries.
|
||||
if (data->hook || !data->monitors.IsEmpty())
|
||||
return;
|
||||
|
||||
MessageDataArray::index_type idx;
|
||||
idx = data - mMessageData.Elements();
|
||||
NS_ASSERTION(idx < mMessageData.Length(), "Attempted to delete MessageData that doesn't belong to this array!");
|
||||
mMessageData.RemoveElementAt(idx);
|
||||
}
|
||||
|
||||
bool
|
||||
WindowHook::Notify(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult)
|
||||
{
|
||||
MessageData *data = Lookup(nMsg);
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
uint32_t length = data->monitors.Length();
|
||||
for (uint32_t midx = 0; midx < length; midx++) {
|
||||
data->monitors[midx].Invoke(hWnd, nMsg, wParam, lParam, &aResult.mResult);
|
||||
}
|
||||
|
||||
aResult.mConsumed =
|
||||
data->hook.Invoke(hWnd, nMsg, wParam, lParam, &aResult.mResult);
|
||||
return aResult.mConsumed;
|
||||
}
|
||||
|
||||
bool
|
||||
WindowHook::CallbackData::Invoke(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam,
|
||||
LRESULT *aResult) {
|
||||
if (!cb)
|
||||
return false;
|
||||
return cb(context, hWnd, msg, wParam, lParam, aResult);
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
81
widget/windows/WindowHook.h
Normal file
81
widget/windows/WindowHook.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __mozilla_WindowHook_h__
|
||||
#define __mozilla_WindowHook_h__
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <nsHashKeys.h>
|
||||
#include <nsClassHashtable.h>
|
||||
#include <nsTArray.h>
|
||||
|
||||
#include "nsAppShell.h"
|
||||
|
||||
class nsWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
struct MSGResult;
|
||||
|
||||
class WindowHook {
|
||||
public:
|
||||
|
||||
// It is expected that most callbacks will return false
|
||||
typedef bool (*Callback)(void *aContext, HWND hWnd, UINT nMsg,
|
||||
WPARAM wParam, LPARAM lParam, LRESULT *aResult);
|
||||
|
||||
nsresult AddHook(UINT nMsg, Callback callback, void *context);
|
||||
nsresult RemoveHook(UINT nMsg, Callback callback, void *context);
|
||||
nsresult AddMonitor(UINT nMsg, Callback callback, void *context);
|
||||
nsresult RemoveMonitor(UINT nMsg, Callback callback, void *context);
|
||||
|
||||
private:
|
||||
struct CallbackData {
|
||||
Callback cb;
|
||||
void *context;
|
||||
|
||||
CallbackData() : cb(nullptr), context(nullptr) {}
|
||||
CallbackData(Callback cb, void *ctx) : cb(cb), context(ctx) {}
|
||||
bool Invoke(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam,
|
||||
LRESULT *aResult);
|
||||
bool operator== (const CallbackData &rhs) const {
|
||||
return cb == rhs.cb && context == rhs.context;
|
||||
}
|
||||
bool operator!= (const CallbackData &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
operator bool () const {
|
||||
return !!cb;
|
||||
}
|
||||
};
|
||||
|
||||
typedef nsTArray<CallbackData> CallbackDataArray;
|
||||
struct MessageData {
|
||||
UINT nMsg;
|
||||
CallbackData hook;
|
||||
CallbackDataArray monitors;
|
||||
};
|
||||
|
||||
bool Notify(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam,
|
||||
MSGResult& aResult);
|
||||
|
||||
MessageData *Lookup(UINT nMsg);
|
||||
MessageData *LookupOrCreate(UINT nMsg);
|
||||
void DeleteIfEmpty(MessageData *data);
|
||||
|
||||
typedef nsTArray<MessageData> MessageDataArray;
|
||||
MessageDataArray mMessageData;
|
||||
|
||||
// For Notify
|
||||
friend class ::nsWindow;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __mozilla_WindowHook_h__
|
||||
182
widget/windows/WindowsUIUtils.cpp
Normal file
182
widget/windows/WindowsUIUtils.cpp
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/* -*- 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 <windows.h>
|
||||
#include <winsdkver.h>
|
||||
#include "mozwrlbase.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "WindowsUIUtils.h"
|
||||
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIAppShellService.h"
|
||||
#include "nsAppShellCID.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIWidget.h"
|
||||
|
||||
/* mingw currently doesn't support windows.ui.viewmanagement.h, so we disable it until it's fixed. */
|
||||
#ifndef __MINGW32__
|
||||
|
||||
#include <windows.ui.viewmanagement.h>
|
||||
|
||||
#pragma comment(lib, "runtimeobject.lib")
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace ABI::Windows::UI;
|
||||
using namespace ABI::Windows::UI::ViewManagement;
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Microsoft::WRL::Wrappers;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
|
||||
/* All of this is win10 stuff and we're compiling against win81 headers
|
||||
* for now, so we may need to do some legwork: */
|
||||
#if WINVER_MAXVER < 0x0A00
|
||||
namespace ABI {
|
||||
namespace Windows {
|
||||
namespace UI {
|
||||
namespace ViewManagement {
|
||||
enum UserInteractionMode {
|
||||
UserInteractionMode_Mouse = 0,
|
||||
UserInteractionMode_Touch = 1
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
|
||||
#define RuntimeClass_Windows_UI_ViewManagement_UIViewSettings L"Windows.UI.ViewManagement.UIViewSettings"
|
||||
#endif
|
||||
|
||||
#if WINVER_MAXVER < 0x0A00
|
||||
namespace ABI {
|
||||
namespace Windows {
|
||||
namespace UI {
|
||||
namespace ViewManagement {
|
||||
interface IUIViewSettings;
|
||||
MIDL_INTERFACE("C63657F6-8850-470D-88F8-455E16EA2C26")
|
||||
IUIViewSettings : public IInspectable
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE get_UserInteractionMode(UserInteractionMode *value) = 0;
|
||||
};
|
||||
|
||||
extern const __declspec(selectany) IID & IID_IUIViewSettings = __uuidof(IUIViewSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef IUIViewSettingsInterop
|
||||
|
||||
typedef interface IUIViewSettingsInterop IUIViewSettingsInterop;
|
||||
|
||||
MIDL_INTERFACE("3694dbf9-8f68-44be-8ff5-195c98ede8a6")
|
||||
IUIViewSettingsInterop : public IInspectable
|
||||
{
|
||||
public:
|
||||
virtual HRESULT STDMETHODCALLTYPE GetForWindow(HWND hwnd, REFIID riid, void **ppv) = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
WindowsUIUtils::WindowsUIUtils() :
|
||||
mInTabletMode(eTabletModeUnknown)
|
||||
{
|
||||
}
|
||||
|
||||
WindowsUIUtils::~WindowsUIUtils()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the nsISupports methods...
|
||||
*/
|
||||
NS_IMPL_ISUPPORTS(WindowsUIUtils,
|
||||
nsIWindowsUIUtils)
|
||||
|
||||
NS_IMETHODIMP
|
||||
WindowsUIUtils::GetInTabletMode(bool* aResult)
|
||||
{
|
||||
if (mInTabletMode == eTabletModeUnknown) {
|
||||
UpdateTabletModeState();
|
||||
}
|
||||
*aResult = mInTabletMode == eTabletModeOn;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WindowsUIUtils::UpdateTabletModeState()
|
||||
{
|
||||
#ifndef __MINGW32__
|
||||
if (!IsWin10OrLater()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
|
||||
nsCOMPtr<nsIXULWindow> hiddenWindow;
|
||||
|
||||
nsresult rv = appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
rv = hiddenWindow->GetDocShell(getter_AddRefs(docShell));
|
||||
if (NS_FAILED(rv) || !docShell) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
|
||||
|
||||
if (!baseWindow)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
baseWindow->GetMainWidget(getter_AddRefs(widget));
|
||||
|
||||
if (!widget)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
HWND winPtr = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
ComPtr<IUIViewSettingsInterop> uiViewSettingsInterop;
|
||||
|
||||
HRESULT hr = GetActivationFactory(
|
||||
HStringReference(RuntimeClass_Windows_UI_ViewManagement_UIViewSettings).Get(),
|
||||
&uiViewSettingsInterop);
|
||||
if (SUCCEEDED(hr)) {
|
||||
ComPtr<IUIViewSettings> uiViewSettings;
|
||||
hr = uiViewSettingsInterop->GetForWindow(winPtr, IID_PPV_ARGS(&uiViewSettings));
|
||||
if (SUCCEEDED(hr)) {
|
||||
UserInteractionMode mode;
|
||||
hr = uiViewSettings->get_UserInteractionMode(&mode);
|
||||
if (SUCCEEDED(hr)) {
|
||||
TabletModeState oldTabletModeState = mInTabletMode;
|
||||
mInTabletMode = (mode == UserInteractionMode_Touch) ? eTabletModeOn : eTabletModeOff;
|
||||
if (mInTabletMode != oldTabletModeState) {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
NS_NAMED_LITERAL_STRING(tabletMode, "tablet-mode");
|
||||
NS_NAMED_LITERAL_STRING(normalMode, "normal-mode");
|
||||
observerService->NotifyObservers(nullptr, "tablet-mode-change",
|
||||
((mInTabletMode == eTabletModeOn) ? tabletMode.get() : normalMode.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
29
widget/windows/WindowsUIUtils.h
Normal file
29
widget/windows/WindowsUIUtils.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_widget_WindowsUIUtils_h__
|
||||
#define mozilla_widget_WindowsUIUtils_h__
|
||||
|
||||
#include "nsIWindowsUIUtils.h"
|
||||
|
||||
enum TabletModeState {
|
||||
eTabletModeUnknown = 0,
|
||||
eTabletModeOff,
|
||||
eTabletModeOn
|
||||
};
|
||||
|
||||
class WindowsUIUtils final : public nsIWindowsUIUtils {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIWINDOWSUIUTILS
|
||||
|
||||
WindowsUIUtils();
|
||||
protected:
|
||||
~WindowsUIUtils();
|
||||
|
||||
TabletModeState mInTabletMode;
|
||||
};
|
||||
|
||||
#endif // mozilla_widget_WindowsUIUtils_h__
|
||||
123
widget/windows/moz.build
Normal file
123
widget/windows/moz.build
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
TEST_DIRS += ['tests']
|
||||
|
||||
EXPORTS += [
|
||||
'nsdefs.h',
|
||||
'WindowHook.h',
|
||||
'WinUtils.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.widget += [
|
||||
'AudioSession.h',
|
||||
'CompositorWidgetChild.h',
|
||||
'CompositorWidgetParent.h',
|
||||
'InProcessWinCompositorWidget.h',
|
||||
'WinCompositorWidget.h',
|
||||
'WinMessages.h',
|
||||
'WinModifierKeyState.h',
|
||||
'WinNativeEventData.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AudioSession.cpp',
|
||||
'CompositorWidgetChild.cpp',
|
||||
'CompositorWidgetParent.cpp',
|
||||
'GfxInfo.cpp',
|
||||
'IEnumFE.cpp',
|
||||
'IMMHandler.cpp',
|
||||
'InkCollector.cpp',
|
||||
'InProcessWinCompositorWidget.cpp',
|
||||
'JumpListItem.cpp',
|
||||
'KeyboardLayout.cpp',
|
||||
'nsAppShell.cpp',
|
||||
'nsClipboard.cpp',
|
||||
'nsColorPicker.cpp',
|
||||
'nsDataObj.cpp',
|
||||
'nsDataObjCollection.cpp',
|
||||
'nsDragService.cpp',
|
||||
'nsIdleServiceWin.cpp',
|
||||
'nsImageClipboard.cpp',
|
||||
'nsLookAndFeel.cpp',
|
||||
'nsNativeDragSource.cpp',
|
||||
'nsNativeDragTarget.cpp',
|
||||
'nsNativeThemeWin.cpp',
|
||||
'nsScreenManagerWin.cpp',
|
||||
'nsScreenWin.cpp',
|
||||
'nsSound.cpp',
|
||||
'nsToolkit.cpp',
|
||||
'nsUXThemeData.cpp',
|
||||
'nsWindow.cpp',
|
||||
'nsWindowBase.cpp',
|
||||
'nsWindowDbg.cpp',
|
||||
'nsWindowGfx.cpp',
|
||||
'nsWinGesture.cpp',
|
||||
'TaskbarPreview.cpp',
|
||||
'TaskbarPreviewButton.cpp',
|
||||
'TaskbarTabPreview.cpp',
|
||||
'TaskbarWindowPreview.cpp',
|
||||
'WidgetTraceEvent.cpp',
|
||||
'WindowHook.cpp',
|
||||
'WinIMEHandler.cpp',
|
||||
'WinTaskbar.cpp',
|
||||
'WinTextEventDispatcherListener.cpp',
|
||||
'WinUtils.cpp',
|
||||
]
|
||||
|
||||
# The following files cannot be built in unified mode because of name clashes.
|
||||
SOURCES += [
|
||||
'JumpListBuilder.cpp',
|
||||
'nsBidiKeyboard.cpp',
|
||||
'nsFilePicker.cpp',
|
||||
'nsWidgetFactory.cpp',
|
||||
'WinCompositorWidget.cpp',
|
||||
'WindowsUIUtils.cpp',
|
||||
'WinMouseScrollHandler.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_CRASHREPORTER']:
|
||||
UNIFIED_SOURCES += [
|
||||
'LSPAnnotator.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['NS_PRINTING']:
|
||||
UNIFIED_SOURCES += [
|
||||
'nsDeviceContextSpecWin.cpp',
|
||||
'nsPrintOptionsWin.cpp',
|
||||
'nsPrintSettingsWin.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['NS_ENABLE_TSF']:
|
||||
SOURCES += [
|
||||
'TSFTextStore.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/layout/generic',
|
||||
'/layout/xul',
|
||||
'/toolkit/xre',
|
||||
'/widget',
|
||||
'/xpcom/base',
|
||||
]
|
||||
|
||||
DEFINES['MOZ_UNICODE'] = True
|
||||
|
||||
for var in ('MOZ_ENABLE_D3D10_LAYER'):
|
||||
if CONFIG[var]:
|
||||
DEFINES[var] = True
|
||||
|
||||
RESFILE = 'widget.res'
|
||||
|
||||
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
|
||||
|
||||
OS_LIBS += [
|
||||
'rpcrt4',
|
||||
]
|
||||
77
widget/windows/mozwrlbase.h
Normal file
77
widget/windows/mozwrlbase.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/* -*- Mode: C++; tab-width: 4; 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/. */
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Includes <wrl.h> and it's children. Defines imports needed by
|
||||
* corewrappers.h in the case where windows.h has already been
|
||||
* included w/WINVER < 0x600. Also ups WINVER/_WIN32_WINNT prior
|
||||
* to including wrl.h. Mozilla's build currently has WINVER set to
|
||||
* 0x502 for XP support.
|
||||
*/
|
||||
|
||||
#if _WIN32_WINNT < 0x600
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
ReleaseSRWLockExclusive(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
ReleaseSRWLockShared(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
InitializeCriticalSectionEx(
|
||||
_Out_ LPCRITICAL_SECTION lpCriticalSection,
|
||||
_In_ DWORD dwSpinCount,
|
||||
_In_ DWORD Flags
|
||||
);
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
InitializeSRWLock(
|
||||
_Out_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
AcquireSRWLockExclusive(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
WINAPI
|
||||
TryAcquireSRWLockExclusive(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
WINAPI
|
||||
TryAcquireSRWLockShared(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
VOID
|
||||
WINAPI
|
||||
AcquireSRWLockShared(
|
||||
_Inout_ PSRWLOCK SRWLock
|
||||
);
|
||||
|
||||
#undef WINVER
|
||||
#undef _WIN32_WINNT
|
||||
#define WINVER 0x600
|
||||
#define _WIN32_WINNT 0x600
|
||||
|
||||
#endif // _WIN32_WINNT < 0x600
|
||||
|
||||
#include <wrl.h>
|
||||
436
widget/windows/nsAppShell.cpp
Normal file
436
widget/windows/nsAppShell.cpp
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
|
||||
/* 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 "mozilla/ipc/MessageChannel.h"
|
||||
#include "mozilla/ipc/WindowsMessageLoop.h"
|
||||
#include "nsAppShell.h"
|
||||
#include "nsToolkit.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "WinUtils.h"
|
||||
#include "WinTaskbar.h"
|
||||
#include "WinMouseScrollHandler.h"
|
||||
#include "nsWindowDefs.h"
|
||||
#include "nsString.h"
|
||||
#include "WinIMEHandler.h"
|
||||
#include "mozilla/widget/AudioSession.h"
|
||||
#include "mozilla/HangMonitor.h"
|
||||
#include "nsIDOMWakeLockListener.h"
|
||||
#include "nsIPowerManagerService.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
// These are two messages that the code in winspool.drv on Windows 7 explicitly
|
||||
// waits for while it is pumping other Windows messages, during display of the
|
||||
// Printer Properties dialog.
|
||||
#define MOZ_WM_PRINTER_PROPERTIES_COMPLETION 0x5b7a
|
||||
#define MOZ_WM_PRINTER_PROPERTIES_FAILURE 0x5b7f
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
#define WAKE_LOCK_LOG(...) MOZ_LOG(GetWinWakeLockLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
PRLogModuleInfo* GetWinWakeLockLog() {
|
||||
static PRLogModuleInfo* log = nullptr;
|
||||
if (!log) {
|
||||
log = PR_NewLogModule("WinWakeLock");
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
// A wake lock listener that disables screen saver when requested by
|
||||
// Gecko. For example when we're playing video in a foreground tab we
|
||||
// don't want the screen saver to turn on.
|
||||
class WinWakeLockListener final : public nsIDOMMozWakeLockListener
|
||||
, public nsITimerCallback {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS;
|
||||
|
||||
NS_IMETHOD Notify(nsITimer *timer) override {
|
||||
WAKE_LOCK_LOG("WinWakeLock: periodic timer fired");
|
||||
ResetScreenSaverTimeout();
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
~WinWakeLockListener() {}
|
||||
|
||||
NS_IMETHOD Callback(const nsAString& aTopic, const nsAString& aState) {
|
||||
if (!aTopic.EqualsASCII("screen")) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Note the wake lock code ensures that we're not sent duplicate
|
||||
// "locked-foreground" notifications when multipe wake locks are held.
|
||||
if (aState.EqualsASCII("locked-foreground")) {
|
||||
WAKE_LOCK_LOG("WinWakeLock: Blocking screen saver");
|
||||
// We block the screen saver by periodically resetting the screen
|
||||
// saver timeout.
|
||||
StartTimer();
|
||||
// Prevent the display turning off. On Win7 and later this also
|
||||
// blocks the screen saver, but we need the timer started above
|
||||
// to block on Win XP and Vista.
|
||||
SetThreadExecutionState(ES_DISPLAY_REQUIRED|ES_CONTINUOUS);
|
||||
} else {
|
||||
WAKE_LOCK_LOG("WinWakeLock: Unblocking screen saver");
|
||||
// Re-enable screen saver.
|
||||
StopTimer();
|
||||
// Unblock display turning off.
|
||||
SetThreadExecutionState(ES_CONTINUOUS);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void StartTimer() {
|
||||
ResetScreenSaverTimeout();
|
||||
MOZ_ASSERT(!mTimer);
|
||||
if (mTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to create screen saver timeout reset timer");
|
||||
return;
|
||||
}
|
||||
// The minimum screensaver timeout that can be specified with Windows' UI
|
||||
// is 60 seconds. We set a timer to re-jig the screen saver 10 seconds
|
||||
// before we expect the timer to run out, but always at least in 1 second
|
||||
// intervals. We reset the timer at a max of 50 seconds, so that if the
|
||||
// user changes the timeout using the UI, we won't be caught out.
|
||||
int32_t timeout = std::max(std::min(50, (int32_t)mScreenSaverTimeout - 10), 1);
|
||||
uint32_t timeoutMs = (uint32_t)timeout * 1000;
|
||||
WAKE_LOCK_LOG("WinWakeLock: Setting periodic timer for %d ms", timeoutMs);
|
||||
rv = timer->InitWithCallback(this,
|
||||
timeoutMs,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to initialize screen saver timeout reset timer");
|
||||
return;
|
||||
}
|
||||
|
||||
mTimer = timer.forget();
|
||||
}
|
||||
|
||||
void StopTimer() {
|
||||
WAKE_LOCK_LOG("WinWakeLock: StopTimer()");
|
||||
if (!mTimer) {
|
||||
return;
|
||||
}
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
|
||||
// Resets the operating system's timeout for when to disable the screen.
|
||||
// Called periodically to keep the screensaver off.
|
||||
void ResetScreenSaverTimeout() {
|
||||
if (SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &mScreenSaverTimeout, 0)) {
|
||||
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, mScreenSaverTimeout, NULL, 0);
|
||||
}
|
||||
WAKE_LOCK_LOG("WinWakeLock: ResetScreenSaverTimeout() mScreenSaverTimeout=%d", mScreenSaverTimeout);
|
||||
}
|
||||
|
||||
UINT mScreenSaverTimeout = 60;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WinWakeLockListener, nsIDOMMozWakeLockListener, nsITimerCallback)
|
||||
StaticRefPtr<WinWakeLockListener> sWakeLockListener;
|
||||
|
||||
static void
|
||||
AddScreenWakeLockListener()
|
||||
{
|
||||
nsCOMPtr<nsIPowerManagerService> sPowerManagerService = do_GetService(POWERMANAGERSERVICE_CONTRACTID);
|
||||
if (sPowerManagerService) {
|
||||
sWakeLockListener = new WinWakeLockListener();
|
||||
sPowerManagerService->AddWakeLockListener(sWakeLockListener);
|
||||
} else {
|
||||
NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
RemoveScreenWakeLockListener()
|
||||
{
|
||||
nsCOMPtr<nsIPowerManagerService> sPowerManagerService = do_GetService(POWERMANAGERSERVICE_CONTRACTID);
|
||||
if (sPowerManagerService) {
|
||||
sPowerManagerService->RemoveWakeLockListener(sWakeLockListener);
|
||||
sPowerManagerService = nullptr;
|
||||
sWakeLockListener = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
// Native event callback message.
|
||||
UINT sAppShellGeckoMsgId = RegisterWindowMessageW(L"nsAppShell:EventID");
|
||||
} }
|
||||
|
||||
const wchar_t* kTaskbarButtonEventId = L"TaskbarButtonCreated";
|
||||
UINT sTaskbarButtonCreatedMsg;
|
||||
|
||||
/* static */
|
||||
UINT nsAppShell::GetTaskbarButtonCreatedMessage() {
|
||||
return sTaskbarButtonCreatedMsg;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace crashreporter {
|
||||
void LSPAnnotate();
|
||||
} // namespace crashreporter
|
||||
} // namespace mozilla
|
||||
|
||||
using mozilla::crashreporter::LSPAnnotate;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/*static*/ LRESULT CALLBACK
|
||||
nsAppShell::EventWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (uMsg == sAppShellGeckoMsgId) {
|
||||
nsAppShell *as = reinterpret_cast<nsAppShell *>(lParam);
|
||||
as->NativeEventCallback();
|
||||
NS_RELEASE(as);
|
||||
return TRUE;
|
||||
}
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
nsAppShell::~nsAppShell()
|
||||
{
|
||||
if (mEventWnd) {
|
||||
// DestroyWindow doesn't do anything when called from a non UI thread.
|
||||
// Since mEventWnd was created on the UI thread, it must be destroyed on
|
||||
// the UI thread.
|
||||
SendMessage(mEventWnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAppShell::Init()
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
LSPAnnotate();
|
||||
#endif
|
||||
|
||||
mLastNativeEventScheduled = TimeStamp::NowLoRes();
|
||||
|
||||
mozilla::ipc::windows::InitUIThread();
|
||||
|
||||
sTaskbarButtonCreatedMsg = ::RegisterWindowMessageW(kTaskbarButtonEventId);
|
||||
NS_ASSERTION(sTaskbarButtonCreatedMsg, "Could not register taskbar button creation message");
|
||||
|
||||
WNDCLASSW wc;
|
||||
HINSTANCE module = GetModuleHandle(nullptr);
|
||||
|
||||
const wchar_t *const kWindowClass = L"nsAppShell:EventWindowClass";
|
||||
if (!GetClassInfoW(module, kWindowClass, &wc)) {
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = EventWindowProc;
|
||||
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);
|
||||
}
|
||||
|
||||
mEventWnd = CreateWindowW(kWindowClass, L"nsAppShell:EventWindow",
|
||||
0, 0, 0, 10, 10, nullptr, nullptr, module, nullptr);
|
||||
NS_ENSURE_STATE(mEventWnd);
|
||||
|
||||
return nsBaseAppShell::Init();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::Run(void)
|
||||
{
|
||||
// Content processes initialize audio later through PContent using audio
|
||||
// tray id information pulled from the browser process AudioSession. This
|
||||
// way the two share a single volume control.
|
||||
// Note StopAudioSession() is called from nsAppRunner.cpp after xpcom is torn
|
||||
// down to insure the browser shuts down after child processes.
|
||||
if (XRE_IsParentProcess()) {
|
||||
mozilla::widget::StartAudioSession();
|
||||
}
|
||||
|
||||
// Add an observer that disables the screen saver when requested by Gecko.
|
||||
// For example when we're playing video in the foreground tab.
|
||||
AddScreenWakeLockListener();
|
||||
|
||||
nsresult rv = nsBaseAppShell::Run();
|
||||
|
||||
RemoveScreenWakeLockListener();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::Exit(void)
|
||||
{
|
||||
return nsBaseAppShell::Exit();
|
||||
}
|
||||
|
||||
void
|
||||
nsAppShell::DoProcessMoreGeckoEvents()
|
||||
{
|
||||
// Called by nsBaseAppShell's NativeEventCallback() after it has finished
|
||||
// processing pending gecko events and there are still gecko events pending
|
||||
// for the thread. (This can happen if NS_ProcessPendingEvents reached it's
|
||||
// starvation timeout limit.) The default behavior in nsBaseAppShell is to
|
||||
// call ScheduleNativeEventCallback to post a follow up native event callback
|
||||
// message. This triggers an additional call to NativeEventCallback for more
|
||||
// gecko event processing.
|
||||
|
||||
// There's a deadlock risk here with certain internal Windows modal loops. In
|
||||
// our dispatch code, we prioritize messages so that input is handled first.
|
||||
// However Windows modal dispatch loops often prioritize posted messages. If
|
||||
// we find ourselves in a tight gecko timer loop where NS_ProcessPendingEvents
|
||||
// takes longer than the timer duration, NS_HasPendingEvents(thread) will
|
||||
// always be true. ScheduleNativeEventCallback will be called on every
|
||||
// NativeEventCallback callback, and in a Windows modal dispatch loop, the
|
||||
// callback message will be processed first -> input gets starved, dead lock.
|
||||
|
||||
// To avoid, don't post native callback messages from NativeEventCallback
|
||||
// when we're in a modal loop. This gets us back into the Windows modal
|
||||
// dispatch loop dispatching input messages. Once we drop out of the modal
|
||||
// loop, we use mNativeCallbackPending to fire off a final NativeEventCallback
|
||||
// if we need it, which insures NS_ProcessPendingEvents gets called and all
|
||||
// gecko events get processed.
|
||||
if (mEventloopNestingLevel < 2) {
|
||||
OnDispatchedEvent(nullptr);
|
||||
mNativeCallbackPending = false;
|
||||
} else {
|
||||
mNativeCallbackPending = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAppShell::ScheduleNativeEventCallback()
|
||||
{
|
||||
// Post a message to the hidden message window
|
||||
NS_ADDREF_THIS(); // will be released when the event is processed
|
||||
{
|
||||
MutexAutoLock lock(mLastNativeEventScheduledMutex);
|
||||
// Time stamp this event so we can detect cases where the event gets
|
||||
// dropping in sub classes / modal loops we do not control.
|
||||
mLastNativeEventScheduled = TimeStamp::NowLoRes();
|
||||
}
|
||||
::PostMessage(mEventWnd, sAppShellGeckoMsgId, 0, reinterpret_cast<LPARAM>(this));
|
||||
}
|
||||
|
||||
bool
|
||||
nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
||||
{
|
||||
// Notify ipc we are spinning a (possibly nested) gecko event loop.
|
||||
mozilla::ipc::MessageChannel::NotifyGeckoEventDispatch();
|
||||
|
||||
bool gotMessage = false;
|
||||
|
||||
do {
|
||||
MSG msg;
|
||||
bool uiMessage = false;
|
||||
|
||||
// For avoiding deadlock between our process and plugin process by
|
||||
// mouse wheel messages, we're handling actually when we receive one of
|
||||
// following internal messages which is posted by native mouse wheel
|
||||
// message handler. Any other events, especially native modifier key
|
||||
// events, should not be handled between native message and posted
|
||||
// internal message because it may make different modifier key state or
|
||||
// mouse cursor position between them.
|
||||
if (mozilla::widget::MouseScrollHandler::IsWaitingInternalMessage()) {
|
||||
gotMessage = WinUtils::PeekMessage(&msg, nullptr, MOZ_WM_MOUSEWHEEL_FIRST,
|
||||
MOZ_WM_MOUSEWHEEL_LAST, PM_REMOVE);
|
||||
NS_ASSERTION(gotMessage,
|
||||
"waiting internal wheel message, but it has not come");
|
||||
uiMessage = gotMessage;
|
||||
}
|
||||
|
||||
if (!gotMessage) {
|
||||
gotMessage = WinUtils::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
|
||||
uiMessage =
|
||||
(msg.message >= WM_KEYFIRST && msg.message <= WM_IME_KEYLAST) ||
|
||||
(msg.message >= NS_WM_IMEFIRST && msg.message <= NS_WM_IMELAST) ||
|
||||
(msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST);
|
||||
}
|
||||
|
||||
if (gotMessage) {
|
||||
if (msg.message == WM_QUIT) {
|
||||
::PostQuitMessage(msg.wParam);
|
||||
Exit();
|
||||
} else {
|
||||
// If we had UI activity we would be processing it now so we know we
|
||||
// have either kUIActivity or kActivityNoUIAVail.
|
||||
mozilla::HangMonitor::NotifyActivity(
|
||||
uiMessage ? mozilla::HangMonitor::kUIActivity :
|
||||
mozilla::HangMonitor::kActivityNoUIAVail);
|
||||
|
||||
if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST &&
|
||||
IMEHandler::ProcessRawKeyMessage(msg)) {
|
||||
continue; // the message is consumed.
|
||||
}
|
||||
|
||||
// Store Printer Properties messages for reposting, because they are not
|
||||
// processed by a window procedure, but are explicitly waited for in the
|
||||
// winspool.drv code that will be further up the stack.
|
||||
if (msg.message == MOZ_WM_PRINTER_PROPERTIES_COMPLETION ||
|
||||
msg.message == MOZ_WM_PRINTER_PROPERTIES_FAILURE) {
|
||||
mMsgsToRepost.push_back(msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
::TranslateMessage(&msg);
|
||||
::DispatchMessageW(&msg);
|
||||
}
|
||||
} else if (mayWait) {
|
||||
// Block and wait for any posted application message
|
||||
mozilla::HangMonitor::Suspend();
|
||||
{
|
||||
GeckoProfilerSleepRAII profiler_sleep;
|
||||
WinUtils::WaitForMessage();
|
||||
}
|
||||
}
|
||||
} while (!gotMessage && mayWait);
|
||||
|
||||
// See DoProcessNextNativeEvent, mEventloopNestingLevel will be
|
||||
// one when a modal loop unwinds.
|
||||
if (mNativeCallbackPending && mEventloopNestingLevel == 1)
|
||||
DoProcessMoreGeckoEvents();
|
||||
|
||||
// Check for starved native callbacks. If we haven't processed one
|
||||
// of these events in NATIVE_EVENT_STARVATION_LIMIT, fire one off.
|
||||
static const mozilla::TimeDuration nativeEventStarvationLimit =
|
||||
mozilla::TimeDuration::FromSeconds(NATIVE_EVENT_STARVATION_LIMIT);
|
||||
|
||||
TimeDuration timeSinceLastNativeEventScheduled;
|
||||
{
|
||||
MutexAutoLock lock(mLastNativeEventScheduledMutex);
|
||||
timeSinceLastNativeEventScheduled =
|
||||
TimeStamp::NowLoRes() - mLastNativeEventScheduled;
|
||||
}
|
||||
if (timeSinceLastNativeEventScheduled > nativeEventStarvationLimit) {
|
||||
ScheduleNativeEventCallback();
|
||||
}
|
||||
|
||||
return gotMessage;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAppShell::AfterProcessNextEvent(nsIThreadInternal* /* unused */,
|
||||
bool /* unused */)
|
||||
{
|
||||
if (!mMsgsToRepost.empty()) {
|
||||
for (MSG msg : mMsgsToRepost) {
|
||||
::PostMessageW(msg.hwnd, msg.message, msg.wParam, msg.lParam);
|
||||
}
|
||||
mMsgsToRepost.clear();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
59
widget/windows/nsAppShell.h
Normal file
59
widget/windows/nsAppShell.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsAppShell_h__
|
||||
#define nsAppShell_h__
|
||||
|
||||
#include "nsBaseAppShell.h"
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
// The maximum time we allow before forcing a native event callback.
|
||||
// In seconds.
|
||||
#define NATIVE_EVENT_STARVATION_LIMIT 1
|
||||
|
||||
/**
|
||||
* Native Win32 Application shell wrapper
|
||||
*/
|
||||
class nsAppShell : public nsBaseAppShell
|
||||
{
|
||||
public:
|
||||
nsAppShell() :
|
||||
mEventWnd(nullptr),
|
||||
mNativeCallbackPending(false),
|
||||
mLastNativeEventScheduledMutex("nsAppShell::mLastNativeEventScheduledMutex")
|
||||
{}
|
||||
typedef mozilla::TimeStamp TimeStamp;
|
||||
typedef mozilla::Mutex Mutex;
|
||||
|
||||
nsresult Init();
|
||||
void DoProcessMoreGeckoEvents();
|
||||
|
||||
static UINT GetTaskbarButtonCreatedMessage();
|
||||
|
||||
NS_IMETHOD AfterProcessNextEvent(nsIThreadInternal* thread,
|
||||
bool eventWasProcessed) final;
|
||||
|
||||
protected:
|
||||
NS_IMETHOD Run();
|
||||
NS_IMETHOD Exit();
|
||||
virtual void ScheduleNativeEventCallback();
|
||||
virtual bool ProcessNextNativeEvent(bool mayWait);
|
||||
virtual ~nsAppShell();
|
||||
|
||||
static LRESULT CALLBACK EventWindowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
protected:
|
||||
HWND mEventWnd;
|
||||
bool mNativeCallbackPending;
|
||||
|
||||
Mutex mLastNativeEventScheduledMutex;
|
||||
TimeStamp mLastNativeEventScheduled;
|
||||
std::vector<MSG> mMsgsToRepost;
|
||||
};
|
||||
|
||||
#endif // nsAppShell_h__
|
||||
187
widget/windows/nsBidiKeyboard.cpp
Normal file
187
widget/windows/nsBidiKeyboard.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/* -*- 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 <stdio.h>
|
||||
#include "nsBidiKeyboard.h"
|
||||
#include "WidgetUtils.h"
|
||||
#include "prmem.h"
|
||||
#include <tchar.h>
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsBidiKeyboard, nsIBidiKeyboard)
|
||||
|
||||
nsBidiKeyboard::nsBidiKeyboard() : nsIBidiKeyboard()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
nsBidiKeyboard::~nsBidiKeyboard()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBidiKeyboard::Reset()
|
||||
{
|
||||
mInitialized = false;
|
||||
mHaveBidiKeyboards = false;
|
||||
mLTRKeyboard[0] = '\0';
|
||||
mRTLKeyboard[0] = '\0';
|
||||
mCurrentLocaleName[0] = '\0';
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBidiKeyboard::IsLangRTL(bool *aIsRTL)
|
||||
{
|
||||
*aIsRTL = false;
|
||||
|
||||
nsresult result = SetupBidiKeyboards();
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
|
||||
HKL currentLocale;
|
||||
|
||||
currentLocale = ::GetKeyboardLayout(0);
|
||||
*aIsRTL = IsRTLLanguage(currentLocale);
|
||||
|
||||
if (!::GetKeyboardLayoutNameW(mCurrentLocaleName))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_ASSERTION(*mCurrentLocaleName,
|
||||
"GetKeyboardLayoutName return string length == 0");
|
||||
NS_ASSERTION((wcslen(mCurrentLocaleName) < KL_NAMELENGTH),
|
||||
"GetKeyboardLayoutName return string length >= KL_NAMELENGTH");
|
||||
|
||||
// The language set by the user overrides the default language for that direction
|
||||
if (*aIsRTL) {
|
||||
wcsncpy(mRTLKeyboard, mCurrentLocaleName, KL_NAMELENGTH);
|
||||
mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
|
||||
} else {
|
||||
wcsncpy(mLTRKeyboard, mCurrentLocaleName, KL_NAMELENGTH);
|
||||
mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
|
||||
}
|
||||
|
||||
NS_ASSERTION((wcslen(mRTLKeyboard) < KL_NAMELENGTH),
|
||||
"mLTRKeyboard has string length >= KL_NAMELENGTH");
|
||||
NS_ASSERTION((wcslen(mLTRKeyboard) < KL_NAMELENGTH),
|
||||
"mRTLKeyboard has string length >= KL_NAMELENGTH");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBidiKeyboard::GetHaveBidiKeyboards(bool* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
nsresult result = SetupBidiKeyboards();
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
|
||||
*aResult = mHaveBidiKeyboards;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// Get the list of keyboard layouts available in the system
|
||||
// Set mLTRKeyboard to the first LTR keyboard in the list and mRTLKeyboard to the first RTL keyboard in the list
|
||||
// These defaults will be used unless the user explicitly sets something else.
|
||||
nsresult nsBidiKeyboard::SetupBidiKeyboards()
|
||||
{
|
||||
if (mInitialized)
|
||||
return mHaveBidiKeyboards ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
||||
int keyboards;
|
||||
HKL far* buf;
|
||||
HKL locale;
|
||||
wchar_t localeName[KL_NAMELENGTH];
|
||||
bool isLTRKeyboardSet = false;
|
||||
bool isRTLKeyboardSet = false;
|
||||
|
||||
// GetKeyboardLayoutList with 0 as first parameter returns the number of keyboard layouts available
|
||||
keyboards = ::GetKeyboardLayoutList(0, nullptr);
|
||||
if (!keyboards)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// allocate a buffer to hold the list
|
||||
buf = (HKL far*) PR_Malloc(keyboards * sizeof(HKL));
|
||||
if (!buf)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Call again to fill the buffer
|
||||
if (::GetKeyboardLayoutList(keyboards, buf) != keyboards) {
|
||||
PR_Free(buf);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Go through the list and pick a default LTR and RTL keyboard layout
|
||||
while (keyboards--) {
|
||||
locale = buf[keyboards];
|
||||
if (IsRTLLanguage(locale)) {
|
||||
_snwprintf(mRTLKeyboard, KL_NAMELENGTH, L"%.*x", KL_NAMELENGTH - 1,
|
||||
LANGIDFROMLCID((DWORD_PTR)locale));
|
||||
isRTLKeyboardSet = true;
|
||||
}
|
||||
else {
|
||||
_snwprintf(mLTRKeyboard, KL_NAMELENGTH, L"%.*x", KL_NAMELENGTH - 1,
|
||||
LANGIDFROMLCID((DWORD_PTR)locale));
|
||||
isLTRKeyboardSet = true;
|
||||
}
|
||||
}
|
||||
PR_Free(buf);
|
||||
mInitialized = true;
|
||||
|
||||
// If there is not at least one keyboard of each directionality, Bidi
|
||||
// keyboard functionality will be disabled.
|
||||
mHaveBidiKeyboards = (isRTLKeyboardSet && isLTRKeyboardSet);
|
||||
if (!mHaveBidiKeyboards)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Get the current keyboard layout and use it for either mRTLKeyboard or
|
||||
// mLTRKeyboard as appropriate. If the user has many keyboard layouts
|
||||
// installed this prevents us from arbitrarily resetting the current
|
||||
// layout (bug 80274)
|
||||
locale = ::GetKeyboardLayout(0);
|
||||
if (!::GetKeyboardLayoutNameW(localeName))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_ASSERTION(*localeName,
|
||||
"GetKeyboardLayoutName return string length == 0");
|
||||
NS_ASSERTION((wcslen(localeName) < KL_NAMELENGTH),
|
||||
"GetKeyboardLayout return string length >= KL_NAMELENGTH");
|
||||
|
||||
if (IsRTLLanguage(locale)) {
|
||||
wcsncpy(mRTLKeyboard, localeName, KL_NAMELENGTH);
|
||||
mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
|
||||
}
|
||||
else {
|
||||
wcsncpy(mLTRKeyboard, localeName, KL_NAMELENGTH);
|
||||
mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
|
||||
}
|
||||
|
||||
NS_ASSERTION(*mRTLKeyboard,
|
||||
"mLTRKeyboard has string length == 0");
|
||||
NS_ASSERTION(*mLTRKeyboard,
|
||||
"mLTRKeyboard has string length == 0");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Test whether the language represented by this locale identifier is a
|
||||
// right-to-left language, using bit 123 of the Unicode subset bitfield in
|
||||
// the LOCALESIGNATURE
|
||||
// See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_63ub.asp
|
||||
bool nsBidiKeyboard::IsRTLLanguage(HKL aLocale)
|
||||
{
|
||||
LOCALESIGNATURE localesig;
|
||||
return (::GetLocaleInfoW(PRIMARYLANGID((DWORD_PTR)aLocale),
|
||||
LOCALE_FONTSIGNATURE,
|
||||
(LPWSTR)&localesig,
|
||||
(sizeof(localesig)/sizeof(WCHAR))) &&
|
||||
(localesig.lsUsb[3] & 0x08000000));
|
||||
}
|
||||
|
||||
//static
|
||||
void
|
||||
nsBidiKeyboard::OnLayoutChange()
|
||||
{
|
||||
mozilla::widget::WidgetUtils::SendBidiKeyboardInfoToContent();
|
||||
}
|
||||
37
widget/windows/nsBidiKeyboard.h
Normal file
37
widget/windows/nsBidiKeyboard.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __nsBidiKeyboard
|
||||
#define __nsBidiKeyboard
|
||||
#include "nsIBidiKeyboard.h"
|
||||
#include <windows.h>
|
||||
|
||||
class nsBidiKeyboard : public nsIBidiKeyboard
|
||||
{
|
||||
virtual ~nsBidiKeyboard();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIBIDIKEYBOARD
|
||||
|
||||
nsBidiKeyboard();
|
||||
|
||||
static void OnLayoutChange();
|
||||
|
||||
protected:
|
||||
|
||||
nsresult SetupBidiKeyboards();
|
||||
bool IsRTLLanguage(HKL aLocale);
|
||||
|
||||
bool mInitialized;
|
||||
bool mHaveBidiKeyboards;
|
||||
wchar_t mLTRKeyboard[KL_NAMELENGTH];
|
||||
wchar_t mRTLKeyboard[KL_NAMELENGTH];
|
||||
wchar_t mCurrentLocaleName[KL_NAMELENGTH];
|
||||
};
|
||||
|
||||
|
||||
#endif // __nsBidiKeyboard
|
||||
1036
widget/windows/nsClipboard.cpp
Normal file
1036
widget/windows/nsClipboard.cpp
Normal file
File diff suppressed because it is too large
Load diff
92
widget/windows/nsClipboard.h
Normal file
92
widget/windows/nsClipboard.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsClipboard_h__
|
||||
#define nsClipboard_h__
|
||||
|
||||
#include "nsBaseClipboard.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIURI.h"
|
||||
#include <windows.h>
|
||||
|
||||
class nsITransferable;
|
||||
class nsIWidget;
|
||||
class nsIFile;
|
||||
struct IDataObject;
|
||||
|
||||
/**
|
||||
* Native Win32 Clipboard wrapper
|
||||
*/
|
||||
|
||||
class nsClipboard : public nsBaseClipboard,
|
||||
public nsIObserver
|
||||
{
|
||||
virtual ~nsClipboard();
|
||||
|
||||
public:
|
||||
nsClipboard();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIObserver
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
// nsIClipboard
|
||||
NS_IMETHOD HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength,
|
||||
int32_t aWhichClipboard, bool *_retval) override;
|
||||
NS_IMETHOD EmptyClipboard(int32_t aWhichClipboard) override;
|
||||
|
||||
// Internal Native Routines
|
||||
static nsresult CreateNativeDataObject(nsITransferable * aTransferable,
|
||||
IDataObject ** aDataObj,
|
||||
nsIURI * uri);
|
||||
static nsresult SetupNativeDataObject(nsITransferable * aTransferable,
|
||||
IDataObject * aDataObj);
|
||||
static nsresult GetDataFromDataObject(IDataObject * aDataObject,
|
||||
UINT anIndex,
|
||||
nsIWidget * aWindow,
|
||||
nsITransferable * aTransferable);
|
||||
static nsresult GetNativeDataOffClipboard(nsIWidget * aWindow, UINT aIndex, UINT aFormat, void ** aData, uint32_t * aLen);
|
||||
static nsresult GetNativeDataOffClipboard(IDataObject * aDataObject, UINT aIndex, UINT aFormat, const char * aMIMEImageFormat, void ** aData, uint32_t * aLen);
|
||||
static nsresult GetGlobalData(HGLOBAL aHGBL, void ** aData, uint32_t * aLen);
|
||||
|
||||
// This function returns the internal Windows clipboard format identifier
|
||||
// for a given Mime string. The default is to map kHTMLMime ("text/html")
|
||||
// to the clipboard format CF_HTML ("HTLM Format"), but it can also be
|
||||
// registered as clipboard format "text/html" to support previous versions
|
||||
// of Gecko.
|
||||
static UINT GetFormat(const char* aMimeStr, bool aMapHTMLMime = true);
|
||||
|
||||
static UINT CF_HTML;
|
||||
static UINT CF_CUSTOMTYPES;
|
||||
|
||||
protected:
|
||||
NS_IMETHOD SetNativeClipboardData ( int32_t aWhichClipboard ) override;
|
||||
NS_IMETHOD GetNativeClipboardData ( nsITransferable * aTransferable, int32_t aWhichClipboard ) override;
|
||||
|
||||
static bool IsInternetShortcut ( const nsAString& inFileName ) ;
|
||||
static bool FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
|
||||
static bool FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
|
||||
static bool FindUnicodeFromPlainText ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ;
|
||||
static bool FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData,
|
||||
uint32_t* outStartOfData, uint32_t* outDataLen );
|
||||
static void ResolveShortcut ( nsIFile* inFileName, nsACString& outURL ) ;
|
||||
|
||||
nsIWidget * mWindow;
|
||||
|
||||
};
|
||||
|
||||
#define SET_FORMATETC(fe, cf, td, asp, li, med) \
|
||||
{\
|
||||
(fe).cfFormat=cf;\
|
||||
(fe).ptd=td;\
|
||||
(fe).dwAspect=asp;\
|
||||
(fe).lindex=li;\
|
||||
(fe).tymed=med;\
|
||||
}
|
||||
|
||||
|
||||
#endif // nsClipboard_h__
|
||||
|
||||
212
widget/windows/nsColorPicker.cpp
Normal file
212
widget/windows/nsColorPicker.cpp
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/* -*- 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 "nsColorPicker.h"
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsString.h"
|
||||
#include "WidgetUtils.h"
|
||||
|
||||
using namespace mozilla::widget;
|
||||
|
||||
namespace
|
||||
{
|
||||
// Manages NS_NATIVE_TMP_WINDOW child windows. NS_NATIVE_TMP_WINDOWs are
|
||||
// temporary child windows of mParentWidget created to address RTL issues
|
||||
// in picker dialogs. We are responsible for destroying these.
|
||||
class AutoDestroyTmpWindow
|
||||
{
|
||||
public:
|
||||
explicit AutoDestroyTmpWindow(HWND aTmpWnd) :
|
||||
mWnd(aTmpWnd) {
|
||||
}
|
||||
|
||||
~AutoDestroyTmpWindow() {
|
||||
if (mWnd)
|
||||
DestroyWindow(mWnd);
|
||||
}
|
||||
|
||||
inline HWND get() const { return mWnd; }
|
||||
private:
|
||||
HWND mWnd;
|
||||
};
|
||||
|
||||
static DWORD ColorStringToRGB(const nsAString& aColor)
|
||||
{
|
||||
DWORD result = 0;
|
||||
|
||||
for (uint32_t i = 1; i < aColor.Length(); ++i) {
|
||||
result *= 16;
|
||||
|
||||
char16_t c = aColor[i];
|
||||
if (c >= '0' && c <= '9') {
|
||||
result += c - '0';
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
result += 10 + (c - 'a');
|
||||
} else {
|
||||
result += 10 + (c - 'A');
|
||||
}
|
||||
}
|
||||
|
||||
DWORD r = result & 0x00FF0000;
|
||||
DWORD g = result & 0x0000FF00;
|
||||
DWORD b = result & 0x000000FF;
|
||||
|
||||
r = r >> 16;
|
||||
b = b << 16;
|
||||
|
||||
result = r | g | b;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static nsString ToHexString(BYTE n)
|
||||
{
|
||||
nsString result;
|
||||
if (n <= 0x0F) {
|
||||
result.Append('0');
|
||||
}
|
||||
result.AppendInt(n, 16);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
BGRIntToRGBString(DWORD color, nsAString& aResult)
|
||||
{
|
||||
BYTE r = GetRValue(color);
|
||||
BYTE g = GetGValue(color);
|
||||
BYTE b = GetBValue(color);
|
||||
|
||||
aResult.Assign('#');
|
||||
aResult.Append(ToHexString(r));
|
||||
aResult.Append(ToHexString(g));
|
||||
aResult.Append(ToHexString(b));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
static AsyncColorChooser* gColorChooser;
|
||||
|
||||
AsyncColorChooser::AsyncColorChooser(COLORREF aInitialColor,
|
||||
nsIWidget* aParentWidget,
|
||||
nsIColorPickerShownCallback* aCallback)
|
||||
: mInitialColor(aInitialColor)
|
||||
, mColor(aInitialColor)
|
||||
, mParentWidget(aParentWidget)
|
||||
, mCallback(aCallback)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncColorChooser::Run()
|
||||
{
|
||||
static COLORREF sCustomColors[16] = {0} ;
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"Color pickers can only be opened from main thread currently");
|
||||
|
||||
// Allow only one color picker to be opened at a time, to workaround bug 944737
|
||||
if (!gColorChooser) {
|
||||
mozilla::AutoRestore<AsyncColorChooser*> restoreColorChooser(gColorChooser);
|
||||
gColorChooser = this;
|
||||
|
||||
AutoDestroyTmpWindow adtw((HWND) (mParentWidget.get() ?
|
||||
mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : nullptr));
|
||||
|
||||
CHOOSECOLOR options;
|
||||
options.lStructSize = sizeof(options);
|
||||
options.hwndOwner = adtw.get();
|
||||
options.Flags = CC_RGBINIT | CC_FULLOPEN | CC_ENABLEHOOK;
|
||||
options.rgbResult = mInitialColor;
|
||||
options.lpCustColors = sCustomColors;
|
||||
options.lpfnHook = HookProc;
|
||||
|
||||
mColor = ChooseColor(&options) ? options.rgbResult : mInitialColor;
|
||||
} else {
|
||||
NS_WARNING("Currently, it's not possible to open more than one color "
|
||||
"picker at a time");
|
||||
mColor = mInitialColor;
|
||||
}
|
||||
|
||||
if (mCallback) {
|
||||
nsAutoString colorStr;
|
||||
BGRIntToRGBString(mColor, colorStr);
|
||||
mCallback->Done(colorStr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
AsyncColorChooser::Update(COLORREF aColor)
|
||||
{
|
||||
if (mColor != aColor) {
|
||||
mColor = aColor;
|
||||
|
||||
nsAutoString colorStr;
|
||||
BGRIntToRGBString(mColor, colorStr);
|
||||
mCallback->Update(colorStr);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ UINT_PTR CALLBACK
|
||||
AsyncColorChooser::HookProc(HWND aDialog, UINT aMsg,
|
||||
WPARAM aWParam, LPARAM aLParam)
|
||||
{
|
||||
if (!gColorChooser) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (aMsg == WM_CTLCOLORSTATIC) {
|
||||
// The color picker does not expose a proper way to retrieve the current
|
||||
// color, so we need to obtain it from the static control displaying the
|
||||
// current color instead.
|
||||
const int kCurrentColorBoxID = 709;
|
||||
if ((HWND)aLParam == GetDlgItem(aDialog, kCurrentColorBoxID)) {
|
||||
gColorChooser->Update(GetPixel((HDC)aWParam, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// nsIColorPicker
|
||||
|
||||
nsColorPicker::nsColorPicker()
|
||||
{
|
||||
}
|
||||
|
||||
nsColorPicker::~nsColorPicker()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsColorPicker::Init(mozIDOMWindowProxy* parent,
|
||||
const nsAString& title,
|
||||
const nsAString& aInitialColor)
|
||||
{
|
||||
NS_PRECONDITION(parent,
|
||||
"Null parent passed to colorpicker, no color picker for you!");
|
||||
mParentWidget = WidgetUtils::DOMWindowToWidget(nsPIDOMWindowOuter::From(parent));
|
||||
mInitialColor = ColorStringToRGB(aInitialColor);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsColorPicker::Open(nsIColorPickerShownCallback* aCallback)
|
||||
{
|
||||
NS_ENSURE_ARG(aCallback);
|
||||
nsCOMPtr<nsIRunnable> event = new AsyncColorChooser(mInitialColor,
|
||||
mParentWidget,
|
||||
aCallback);
|
||||
return NS_DispatchToMainThread(event);
|
||||
}
|
||||
59
widget/windows/nsColorPicker.h
Normal file
59
widget/windows/nsColorPicker.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsColorPicker_h__
|
||||
#define nsColorPicker_h__
|
||||
|
||||
#include <windows.h>
|
||||
#include <commdlg.h>
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIColorPicker.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class nsIWidget;
|
||||
|
||||
class AsyncColorChooser :
|
||||
public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
AsyncColorChooser(COLORREF aInitialColor,
|
||||
nsIWidget* aParentWidget,
|
||||
nsIColorPickerShownCallback* aCallback);
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
private:
|
||||
void Update(COLORREF aColor);
|
||||
|
||||
static UINT_PTR CALLBACK HookProc(HWND aDialog, UINT aMsg,
|
||||
WPARAM aWParam, LPARAM aLParam);
|
||||
|
||||
COLORREF mInitialColor;
|
||||
COLORREF mColor;
|
||||
nsCOMPtr<nsIWidget> mParentWidget;
|
||||
nsCOMPtr<nsIColorPickerShownCallback> mCallback;
|
||||
};
|
||||
|
||||
class nsColorPicker :
|
||||
public nsIColorPicker
|
||||
{
|
||||
virtual ~nsColorPicker();
|
||||
|
||||
public:
|
||||
nsColorPicker();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Init(mozIDOMWindowProxy* parent, const nsAString& title,
|
||||
const nsAString& aInitialColor);
|
||||
NS_IMETHOD Open(nsIColorPickerShownCallback* aCallback);
|
||||
|
||||
private:
|
||||
COLORREF mInitialColor;
|
||||
nsCOMPtr<nsIWidget> mParentWidget;
|
||||
};
|
||||
|
||||
#endif // nsColorPicker_h__
|
||||
2166
widget/windows/nsDataObj.cpp
Normal file
2166
widget/windows/nsDataObj.cpp
Normal file
File diff suppressed because it is too large
Load diff
296
widget/windows/nsDataObj.h
Normal file
296
widget/windows/nsDataObj.h
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef _NSDATAOBJ_H_
|
||||
#define _NSDATAOBJ_H_
|
||||
|
||||
#include <oleidl.h>
|
||||
#include <shldisp.h>
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
class nsIThread;
|
||||
class nsIPrincipal;
|
||||
|
||||
// The SDK shipping with VC11 has renamed IAsyncOperation to
|
||||
// IDataObjectAsyncCapability. We try to detect this, and rename this in our
|
||||
// code too to make sure that we pick the correct name when building.
|
||||
#ifdef __IDataObjectAsyncCapability_INTERFACE_DEFINED__
|
||||
#define IAsyncOperation IDataObjectAsyncCapability
|
||||
#define IID_IAsyncOperation IID_IDataObjectAsyncCapability
|
||||
#else
|
||||
// XXX for older version of PSDK where IAsyncOperation and related stuff is not available
|
||||
// but thisdefine should be removed when parocles config is updated
|
||||
#ifndef __IAsyncOperation_INTERFACE_DEFINED__
|
||||
// IAsyncOperation interface definition
|
||||
EXTERN_C const IID IID_IAsyncOperation;
|
||||
|
||||
MIDL_INTERFACE("3D8B0590-F691-11d2-8EA9-006097DF5BD4")
|
||||
IAsyncOperation : public IUnknown
|
||||
{
|
||||
virtual HRESULT STDMETHODCALLTYPE SetAsyncMode(BOOL fDoOpAsync) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE GetAsyncMode(BOOL *pfIsOpAsync) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE StartOperation(IBindCtx *pbcReserved) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE InOperation(BOOL *pfInAsyncOp) = 0;
|
||||
virtual HRESULT STDMETHODCALLTYPE EndOperation(HRESULT hResult,
|
||||
IBindCtx *pbcReserved,
|
||||
DWORD dwEffects) = 0;
|
||||
};
|
||||
// this is not defined in the old headers for some reason
|
||||
#ifndef FD_PROGRESSUI
|
||||
#define FD_PROGRESSUI 0x4000
|
||||
#endif
|
||||
|
||||
#endif // __IAsyncOperation_INTERFACE_DEFINED__
|
||||
#endif // __IDataObjectAsyncCapability_INTERFACE_DEFINED__
|
||||
|
||||
/*
|
||||
* CFSTR_SHELLURL is deprecated and doesn't have a Unicode version.
|
||||
* Therefore we are using CFSTR_INETURL instead of CFSTR_SHELLURL.
|
||||
* See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_programming/transferring/clipboard.asp
|
||||
*/
|
||||
#ifndef CFSTR_INETURLA
|
||||
#define CFSTR_INETURLA L"UniformResourceLocator"
|
||||
#endif
|
||||
#ifndef CFSTR_INETURLW
|
||||
#define CFSTR_INETURLW L"UniformResourceLocatorW"
|
||||
#endif
|
||||
|
||||
// For support of MinGW w32api v2.4.
|
||||
// When the next version of w32api is released with shlobj.h rev 1.35
|
||||
// http://sources.redhat.com/cgi-bin/cvsweb.cgi/src/winsup/w32api/include/shlobj.h?cvsroot=src
|
||||
// then that can be made the base required version and this code should be removed.
|
||||
#ifndef CFSTR_FILEDESCRIPTORA
|
||||
# define CFSTR_FILEDESCRIPTORA L"FileGroupDescriptor"
|
||||
#endif
|
||||
#ifndef CFSTR_FILEDESCRIPTORW
|
||||
# define CFSTR_FILEDESCRIPTORW L"FileGroupDescriptorW"
|
||||
#endif
|
||||
|
||||
class CEnumFormatEtc;
|
||||
class nsITransferable;
|
||||
|
||||
/*
|
||||
* This ole registered class is used to facilitate drag-drop of objects which
|
||||
* can be adapted by an object derived from CfDragDrop. The CfDragDrop is
|
||||
* associated with instances via SetDragDrop().
|
||||
*/
|
||||
class nsDataObj : public IDataObject,
|
||||
public IAsyncOperation
|
||||
{
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIThread> mIOThread;
|
||||
|
||||
public: // construction, destruction
|
||||
nsDataObj(nsIURI *uri = nullptr);
|
||||
virtual ~nsDataObj();
|
||||
|
||||
public: // IUnknown methods - see iunknown.h for documentation
|
||||
STDMETHODIMP_(ULONG) AddRef ();
|
||||
STDMETHODIMP QueryInterface(REFIID, void**);
|
||||
STDMETHODIMP_(ULONG) Release ();
|
||||
|
||||
// support for clipboard
|
||||
virtual void AddDataFlavor(const char* aDataFlavor, LPFORMATETC aFE);
|
||||
void SetTransferable(nsITransferable * aTransferable);
|
||||
|
||||
// Return the registered OLE class ID of this object's CfDataObj.
|
||||
CLSID GetClassID() const;
|
||||
|
||||
public: // IDataObject methods - these are general comments. see CfDragDrop
|
||||
// for overriding behavior
|
||||
|
||||
// Store data in pSTM according to the format specified by pFE, if the
|
||||
// format is supported (supported formats are specified in CfDragDrop::
|
||||
// GetFormats) and return NOERROR; otherwise return DATA_E_FORMATETC. It
|
||||
// is the callers responsibility to free pSTM if NOERROR is returned.
|
||||
STDMETHODIMP GetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
|
||||
|
||||
// Similar to GetData except that the caller allocates the structure
|
||||
// referenced by pSTM.
|
||||
STDMETHODIMP GetDataHere (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
|
||||
|
||||
// Returns S_TRUE if this object supports the format specified by pSTM,
|
||||
// S_FALSE otherwise.
|
||||
STDMETHODIMP QueryGetData (LPFORMATETC pFE);
|
||||
|
||||
// Set pCanonFE to the canonical format of pFE if one exists and return
|
||||
// NOERROR, otherwise return DATA_S_SAMEFORMATETC. A canonical format
|
||||
// implies an identical rendering.
|
||||
STDMETHODIMP GetCanonicalFormatEtc (LPFORMATETC pFE, LPFORMATETC pCanonFE);
|
||||
|
||||
// Set this objects data according to the format specified by pFE and
|
||||
// the storage medium specified by pSTM and return NOERROR, if the format
|
||||
// is supported. If release is TRUE this object must release the storage
|
||||
// associated with pSTM.
|
||||
STDMETHODIMP SetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL release);
|
||||
|
||||
// Set ppEnum to an IEnumFORMATETC object which will iterate all of the
|
||||
// data formats that this object supports. direction is either DATADIR_GET
|
||||
// or DATADIR_SET.
|
||||
STDMETHODIMP EnumFormatEtc (DWORD direction, LPENUMFORMATETC* ppEnum);
|
||||
|
||||
// Set up an advisory connection to this object based on the format specified
|
||||
// by pFE, flags, and the pAdvise. Set pConn to the established advise
|
||||
// connection.
|
||||
STDMETHODIMP DAdvise (LPFORMATETC pFE, DWORD flags, LPADVISESINK pAdvise,
|
||||
DWORD* pConn);
|
||||
|
||||
// Turn off advising of a previous call to DAdvise which set pConn.
|
||||
STDMETHODIMP DUnadvise (DWORD pConn);
|
||||
|
||||
// Set ppEnum to an IEnumSTATDATA object which will iterate over the
|
||||
// existing objects which have established advisory connections to this
|
||||
// object.
|
||||
STDMETHODIMP EnumDAdvise (LPENUMSTATDATA *ppEnum);
|
||||
|
||||
// IAsyncOperation methods
|
||||
STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects);
|
||||
STDMETHOD(GetAsyncMode)(BOOL *pfIsOpAsync);
|
||||
STDMETHOD(InOperation)(BOOL *pfInAsyncOp);
|
||||
STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync);
|
||||
STDMETHOD(StartOperation)(IBindCtx *pbcReserved);
|
||||
|
||||
public: // other methods
|
||||
|
||||
// Gets the filename from the kFilePromiseURLMime flavour
|
||||
HRESULT GetDownloadDetails(nsIURI **aSourceURI,
|
||||
nsAString &aFilename);
|
||||
|
||||
protected:
|
||||
// help determine the kind of drag
|
||||
bool IsFlavourPresent(const char *inFlavour);
|
||||
|
||||
virtual HRESULT AddSetFormat(FORMATETC& FE);
|
||||
virtual HRESULT AddGetFormat(FORMATETC& FE);
|
||||
|
||||
virtual HRESULT GetFile ( FORMATETC& aFE, STGMEDIUM& aSTG );
|
||||
virtual HRESULT GetText ( const nsACString& aDF, FORMATETC& aFE, STGMEDIUM & aSTG );
|
||||
virtual HRESULT GetDib ( const nsACString& inFlavor, FORMATETC &, STGMEDIUM & aSTG );
|
||||
virtual HRESULT GetMetafilePict(FORMATETC& FE, STGMEDIUM& STM);
|
||||
|
||||
virtual HRESULT DropImage( FORMATETC& aFE, STGMEDIUM& aSTG );
|
||||
virtual HRESULT DropFile( FORMATETC& aFE, STGMEDIUM& aSTG );
|
||||
virtual HRESULT DropTempFile( FORMATETC& aFE, STGMEDIUM& aSTG );
|
||||
|
||||
virtual HRESULT GetUniformResourceLocator ( FORMATETC& aFE, STGMEDIUM& aSTG, bool aIsUnicode ) ;
|
||||
virtual HRESULT ExtractUniformResourceLocatorA ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
|
||||
virtual HRESULT ExtractUniformResourceLocatorW ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
|
||||
virtual HRESULT GetFileDescriptor ( FORMATETC& aFE, STGMEDIUM& aSTG, bool aIsUnicode ) ;
|
||||
virtual HRESULT GetFileContents ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
|
||||
virtual HRESULT GetPreferredDropEffect ( FORMATETC& aFE, STGMEDIUM& aSTG );
|
||||
|
||||
virtual HRESULT SetBitmap(FORMATETC& FE, STGMEDIUM& STM);
|
||||
virtual HRESULT SetDib (FORMATETC& FE, STGMEDIUM& STM);
|
||||
virtual HRESULT SetText (FORMATETC& FE, STGMEDIUM& STM);
|
||||
virtual HRESULT SetMetafilePict(FORMATETC& FE, STGMEDIUM& STM);
|
||||
|
||||
// Provide the structures needed for an internet shortcut by the shell
|
||||
virtual HRESULT GetFileDescriptorInternetShortcutA ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
|
||||
virtual HRESULT GetFileDescriptorInternetShortcutW ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
|
||||
virtual HRESULT GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
|
||||
|
||||
// IStream implementation
|
||||
virtual HRESULT GetFileDescriptor_IStreamA ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
|
||||
virtual HRESULT GetFileDescriptor_IStreamW ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
|
||||
virtual HRESULT GetFileContents_IStream ( FORMATETC& aFE, STGMEDIUM& aSTG ) ;
|
||||
|
||||
nsresult ExtractShortcutURL ( nsString & outURL ) ;
|
||||
nsresult ExtractShortcutTitle ( nsString & outTitle ) ;
|
||||
|
||||
// munge our HTML data to win32's CF_HTML spec. Will null terminate
|
||||
nsresult BuildPlatformHTML ( const char* inOurHTML, char** outPlatformHTML ) ;
|
||||
|
||||
// Used for the SourceURL part of CF_HTML
|
||||
nsCString mSourceURL;
|
||||
|
||||
BOOL FormatsMatch(const FORMATETC& source, const FORMATETC& target) const;
|
||||
|
||||
ULONG m_cRef; // the reference count
|
||||
|
||||
nsTArray<nsCString> mDataFlavors;
|
||||
|
||||
nsITransferable * mTransferable; // nsDataObj owns and ref counts nsITransferable,
|
||||
// the nsITransferable does know anything about the nsDataObj
|
||||
|
||||
CEnumFormatEtc * m_enumFE; // Ownership Rules:
|
||||
// nsDataObj owns and ref counts CEnumFormatEtc,
|
||||
|
||||
nsCOMPtr<nsIFile> mCachedTempFile;
|
||||
|
||||
BOOL mIsAsyncMode;
|
||||
BOOL mIsInOperation;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CStream class implementation
|
||||
// this class is used in Drag and drop with download sample
|
||||
// called from IDataObject::GetData
|
||||
class CStream : public IStream, public nsIStreamListener
|
||||
{
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
FallibleTArray<uint8_t> mChannelData;
|
||||
bool mChannelRead;
|
||||
nsresult mChannelResult;
|
||||
uint32_t mStreamRead;
|
||||
|
||||
protected:
|
||||
virtual ~CStream();
|
||||
nsresult WaitForCompletion();
|
||||
|
||||
public:
|
||||
CStream();
|
||||
nsresult Init(nsIURI *pSourceURI,
|
||||
uint32_t aContentPolicyType,
|
||||
nsIPrincipal* aRequestingPrincipal);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
// IUnknown
|
||||
STDMETHOD(QueryInterface)(REFIID refiid, void** ppvResult);
|
||||
|
||||
// IStream
|
||||
STDMETHOD(Clone)(IStream** ppStream);
|
||||
STDMETHOD(Commit)(DWORD dwFrags);
|
||||
STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten);
|
||||
STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
|
||||
STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
|
||||
STDMETHOD(Revert)(void);
|
||||
STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos);
|
||||
STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize);
|
||||
STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags);
|
||||
STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
|
||||
STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
|
||||
};
|
||||
|
||||
HRESULT CreateStream(IStream **outStream);
|
||||
|
||||
private:
|
||||
|
||||
// Drag and drop helper data for implementing drag and drop image support
|
||||
typedef struct {
|
||||
FORMATETC fe;
|
||||
STGMEDIUM stgm;
|
||||
} DATAENTRY, *LPDATAENTRY;
|
||||
|
||||
nsTArray <LPDATAENTRY> mDataEntryList;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
bool LookupArbitraryFormat(FORMATETC *aFormat, LPDATAENTRY *aDataEntry, BOOL aAddorUpdate);
|
||||
bool CopyMediumData(STGMEDIUM *aMediumDst, STGMEDIUM *aMediumSrc, LPFORMATETC aFormat, BOOL aSetData);
|
||||
static void RemoveTempFile(nsITimer* aTimer, void* aClosure);
|
||||
};
|
||||
|
||||
|
||||
#endif // _NSDATAOBJ_H_
|
||||
405
widget/windows/nsDataObjCollection.cpp
Normal file
405
widget/windows/nsDataObjCollection.cpp
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
/* -*- 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 <shlobj.h>
|
||||
|
||||
#include "nsDataObjCollection.h"
|
||||
#include "nsClipboard.h"
|
||||
#include "IEnumFE.h"
|
||||
|
||||
#include <ole2.h>
|
||||
|
||||
// {25589C3E-1FAC-47b9-BF43-CAEA89B79533}
|
||||
const IID IID_IDataObjCollection =
|
||||
{0x25589c3e, 0x1fac, 0x47b9, {0xbf, 0x43, 0xca, 0xea, 0x89, 0xb7, 0x95, 0x33}};
|
||||
|
||||
/*
|
||||
* Class nsDataObjCollection
|
||||
*/
|
||||
|
||||
nsDataObjCollection::nsDataObjCollection()
|
||||
: m_cRef(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsDataObjCollection::~nsDataObjCollection()
|
||||
{
|
||||
mDataObjects.Clear();
|
||||
}
|
||||
|
||||
|
||||
// IUnknown interface methods - see iunknown.h for documentation
|
||||
STDMETHODIMP nsDataObjCollection::QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
*ppv=nullptr;
|
||||
|
||||
if ( (IID_IUnknown == riid) || (IID_IDataObject == riid) ) {
|
||||
*ppv = static_cast<IDataObject*>(this);
|
||||
AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
if ( IID_IDataObjCollection == riid ) {
|
||||
*ppv = static_cast<nsIDataObjCollection*>(this);
|
||||
AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
//offer to operate asynchronously (required by nsDragService)
|
||||
if (IID_IAsyncOperation == riid) {
|
||||
*ppv = static_cast<IAsyncOperation*>(this);
|
||||
AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) nsDataObjCollection::AddRef()
|
||||
{
|
||||
return ++m_cRef;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) nsDataObjCollection::Release()
|
||||
{
|
||||
if (0 != --m_cRef)
|
||||
return m_cRef;
|
||||
|
||||
delete this;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// IDataObject methods
|
||||
STDMETHODIMP nsDataObjCollection::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||||
{
|
||||
static CLIPFORMAT fileDescriptorFlavorA =
|
||||
::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
|
||||
static CLIPFORMAT fileDescriptorFlavorW =
|
||||
::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
|
||||
static CLIPFORMAT fileFlavor = ::RegisterClipboardFormat(CFSTR_FILECONTENTS);
|
||||
|
||||
switch (pFE->cfFormat) {
|
||||
case CF_TEXT:
|
||||
case CF_UNICODETEXT:
|
||||
return GetText(pFE, pSTM);
|
||||
case CF_HDROP:
|
||||
return GetFile(pFE, pSTM);
|
||||
default:
|
||||
if (pFE->cfFormat == fileDescriptorFlavorA ||
|
||||
pFE->cfFormat == fileDescriptorFlavorW) {
|
||||
return GetFileDescriptors(pFE, pSTM);
|
||||
}
|
||||
if (pFE->cfFormat == fileFlavor) {
|
||||
return GetFileContents(pFE, pSTM);
|
||||
}
|
||||
}
|
||||
return GetFirstSupporting(pFE, pSTM);
|
||||
}
|
||||
|
||||
STDMETHODIMP nsDataObjCollection::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Other objects querying to see if we support a particular format
|
||||
STDMETHODIMP nsDataObjCollection::QueryGetData(LPFORMATETC pFE)
|
||||
{
|
||||
UINT format = nsClipboard::GetFormat(MULTI_MIME);
|
||||
|
||||
if (format == pFE->cfFormat) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
|
||||
IDataObject * dataObj = mDataObjects.ElementAt(i);
|
||||
if (S_OK == dataObj->QueryGetData(pFE)) {
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return DV_E_FORMATETC;
|
||||
}
|
||||
|
||||
STDMETHODIMP nsDataObjCollection::SetData(LPFORMATETC pFE,
|
||||
LPSTGMEDIUM pSTM,
|
||||
BOOL fRelease)
|
||||
{
|
||||
// Set arbitrary data formats on the first object in the collection and let
|
||||
// it handle the heavy lifting
|
||||
if (mDataObjects.Length() == 0)
|
||||
return E_FAIL;
|
||||
return mDataObjects.ElementAt(0)->SetData(pFE, pSTM, fRelease);
|
||||
}
|
||||
|
||||
// Registers a DataFlavor/FE pair
|
||||
void nsDataObjCollection::AddDataFlavor(const char * aDataFlavor,
|
||||
LPFORMATETC aFE)
|
||||
{
|
||||
// Add the FormatEtc to our list if it's not already there. We don't care
|
||||
// about the internal aDataFlavor because nsDataObj handles that.
|
||||
IEnumFORMATETC * ifEtc;
|
||||
FORMATETC fEtc;
|
||||
ULONG num;
|
||||
if (S_OK != this->EnumFormatEtc(DATADIR_GET, &ifEtc))
|
||||
return;
|
||||
while (S_OK == ifEtc->Next(1, &fEtc, &num)) {
|
||||
NS_ASSERTION(1 == num,
|
||||
"Bit off more than we can chew in nsDataObjCollection::AddDataFlavor");
|
||||
if (FormatsMatch(fEtc, *aFE)) {
|
||||
ifEtc->Release();
|
||||
return;
|
||||
}
|
||||
} // If we didn't find a matching format, add this one
|
||||
ifEtc->Release();
|
||||
m_enumFE->AddFormatEtc(aFE);
|
||||
}
|
||||
|
||||
// We accept ownership of the nsDataObj which we free on destruction
|
||||
void nsDataObjCollection::AddDataObject(IDataObject * aDataObj)
|
||||
{
|
||||
nsDataObj* dataObj = reinterpret_cast<nsDataObj*>(aDataObj);
|
||||
mDataObjects.AppendElement(dataObj);
|
||||
}
|
||||
|
||||
// Methods for getting data
|
||||
HRESULT nsDataObjCollection::GetFile(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||||
{
|
||||
STGMEDIUM workingmedium;
|
||||
FORMATETC fe = *pFE;
|
||||
HGLOBAL hGlobalMemory;
|
||||
HRESULT hr;
|
||||
// Make enough space for the header and the trailing null
|
||||
uint32_t buffersize = sizeof(DROPFILES) + sizeof(char16_t);
|
||||
uint32_t alloclen = 0;
|
||||
char16_t* realbuffer;
|
||||
nsAutoString filename;
|
||||
|
||||
hGlobalMemory = GlobalAlloc(GHND, buffersize);
|
||||
|
||||
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
|
||||
nsDataObj* dataObj = mDataObjects.ElementAt(i);
|
||||
hr = dataObj->GetData(&fe, &workingmedium);
|
||||
if (hr != S_OK) {
|
||||
switch (hr) {
|
||||
case DV_E_FORMATETC:
|
||||
continue;
|
||||
default:
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
// Now we need to pull out the filename
|
||||
char16_t* buffer = (char16_t*)GlobalLock(workingmedium.hGlobal);
|
||||
if (buffer == nullptr)
|
||||
return E_FAIL;
|
||||
buffer += sizeof(DROPFILES)/sizeof(char16_t);
|
||||
filename = buffer;
|
||||
GlobalUnlock(workingmedium.hGlobal);
|
||||
ReleaseStgMedium(&workingmedium);
|
||||
// Now put the filename into our buffer
|
||||
alloclen = (filename.Length() + 1) * sizeof(char16_t);
|
||||
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND);
|
||||
if (hGlobalMemory == nullptr)
|
||||
return E_FAIL;
|
||||
realbuffer = (char16_t*)((char*)GlobalLock(hGlobalMemory) + buffersize);
|
||||
if (!realbuffer)
|
||||
return E_FAIL;
|
||||
realbuffer--; // Overwrite the preceding null
|
||||
memcpy(realbuffer, filename.get(), alloclen);
|
||||
GlobalUnlock(hGlobalMemory);
|
||||
buffersize += alloclen;
|
||||
}
|
||||
// We get the last null (on the double null terminator) for free since we used
|
||||
// the zero memory flag when we allocated. All we need to do is fill the
|
||||
// DROPFILES structure
|
||||
DROPFILES* df = (DROPFILES*)GlobalLock(hGlobalMemory);
|
||||
if (!df)
|
||||
return E_FAIL;
|
||||
df->pFiles = sizeof(DROPFILES); //Offset to start of file name string
|
||||
df->fNC = 0;
|
||||
df->pt.x = 0;
|
||||
df->pt.y = 0;
|
||||
df->fWide = TRUE; // utf-16 chars
|
||||
GlobalUnlock(hGlobalMemory);
|
||||
// Finally fill out the STGMEDIUM struct
|
||||
pSTM->tymed = TYMED_HGLOBAL;
|
||||
pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
|
||||
pSTM->hGlobal = hGlobalMemory;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT nsDataObjCollection::GetText(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||||
{
|
||||
STGMEDIUM workingmedium;
|
||||
FORMATETC fe = *pFE;
|
||||
HGLOBAL hGlobalMemory;
|
||||
HRESULT hr;
|
||||
uint32_t buffersize = 1;
|
||||
uint32_t alloclen = 0;
|
||||
|
||||
hGlobalMemory = GlobalAlloc(GHND, buffersize);
|
||||
|
||||
if (pFE->cfFormat == CF_TEXT) {
|
||||
nsAutoCString text;
|
||||
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
|
||||
nsDataObj* dataObj = mDataObjects.ElementAt(i);
|
||||
hr = dataObj->GetData(&fe, &workingmedium);
|
||||
if (hr != S_OK) {
|
||||
switch (hr) {
|
||||
case DV_E_FORMATETC:
|
||||
continue;
|
||||
default:
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
// Now we need to pull out the text
|
||||
char* buffer = (char*)GlobalLock(workingmedium.hGlobal);
|
||||
if (buffer == nullptr)
|
||||
return E_FAIL;
|
||||
text = buffer;
|
||||
GlobalUnlock(workingmedium.hGlobal);
|
||||
ReleaseStgMedium(&workingmedium);
|
||||
// Now put the text into our buffer
|
||||
alloclen = text.Length();
|
||||
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen,
|
||||
GHND);
|
||||
if (hGlobalMemory == nullptr)
|
||||
return E_FAIL;
|
||||
buffer = ((char*)GlobalLock(hGlobalMemory) + buffersize);
|
||||
if (!buffer)
|
||||
return E_FAIL;
|
||||
buffer--; // Overwrite the preceding null
|
||||
memcpy(buffer, text.get(), alloclen);
|
||||
GlobalUnlock(hGlobalMemory);
|
||||
buffersize += alloclen;
|
||||
}
|
||||
pSTM->tymed = TYMED_HGLOBAL;
|
||||
pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
|
||||
pSTM->hGlobal = hGlobalMemory;
|
||||
return S_OK;
|
||||
}
|
||||
if (pFE->cfFormat == CF_UNICODETEXT) {
|
||||
buffersize = sizeof(char16_t);
|
||||
nsAutoString text;
|
||||
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
|
||||
nsDataObj* dataObj = mDataObjects.ElementAt(i);
|
||||
hr = dataObj->GetData(&fe, &workingmedium);
|
||||
if (hr != S_OK) {
|
||||
switch (hr) {
|
||||
case DV_E_FORMATETC:
|
||||
continue;
|
||||
default:
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
// Now we need to pull out the text
|
||||
char16_t* buffer = (char16_t*)GlobalLock(workingmedium.hGlobal);
|
||||
if (buffer == nullptr)
|
||||
return E_FAIL;
|
||||
text = buffer;
|
||||
GlobalUnlock(workingmedium.hGlobal);
|
||||
ReleaseStgMedium(&workingmedium);
|
||||
// Now put the text into our buffer
|
||||
alloclen = text.Length() * sizeof(char16_t);
|
||||
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen,
|
||||
GHND);
|
||||
if (hGlobalMemory == nullptr)
|
||||
return E_FAIL;
|
||||
buffer = (char16_t*)((char*)GlobalLock(hGlobalMemory) + buffersize);
|
||||
if (!buffer)
|
||||
return E_FAIL;
|
||||
buffer--; // Overwrite the preceding null
|
||||
memcpy(buffer, text.get(), alloclen);
|
||||
GlobalUnlock(hGlobalMemory);
|
||||
buffersize += alloclen;
|
||||
}
|
||||
pSTM->tymed = TYMED_HGLOBAL;
|
||||
pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
|
||||
pSTM->hGlobal = hGlobalMemory;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT nsDataObjCollection::GetFileDescriptors(LPFORMATETC pFE,
|
||||
LPSTGMEDIUM pSTM)
|
||||
{
|
||||
STGMEDIUM workingmedium;
|
||||
FORMATETC fe = *pFE;
|
||||
HGLOBAL hGlobalMemory;
|
||||
HRESULT hr;
|
||||
uint32_t buffersize = sizeof(UINT);
|
||||
uint32_t alloclen = sizeof(FILEDESCRIPTOR);
|
||||
|
||||
hGlobalMemory = GlobalAlloc(GHND, buffersize);
|
||||
|
||||
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
|
||||
nsDataObj* dataObj = mDataObjects.ElementAt(i);
|
||||
hr = dataObj->GetData(&fe, &workingmedium);
|
||||
if (hr != S_OK) {
|
||||
switch (hr) {
|
||||
case DV_E_FORMATETC:
|
||||
continue;
|
||||
default:
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
// Now we need to pull out the filedescriptor
|
||||
FILEDESCRIPTOR* buffer =
|
||||
(FILEDESCRIPTOR*)((char*)GlobalLock(workingmedium.hGlobal) + sizeof(UINT));
|
||||
if (buffer == nullptr)
|
||||
return E_FAIL;
|
||||
hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND);
|
||||
if (hGlobalMemory == nullptr)
|
||||
return E_FAIL;
|
||||
FILEGROUPDESCRIPTOR* realbuffer =
|
||||
(FILEGROUPDESCRIPTOR*)GlobalLock(hGlobalMemory);
|
||||
if (!realbuffer)
|
||||
return E_FAIL;
|
||||
FILEDESCRIPTOR* copyloc = (FILEDESCRIPTOR*)((char*)realbuffer + buffersize);
|
||||
memcpy(copyloc, buffer, alloclen);
|
||||
realbuffer->cItems++;
|
||||
GlobalUnlock(hGlobalMemory);
|
||||
GlobalUnlock(workingmedium.hGlobal);
|
||||
ReleaseStgMedium(&workingmedium);
|
||||
buffersize += alloclen;
|
||||
}
|
||||
pSTM->tymed = TYMED_HGLOBAL;
|
||||
pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
|
||||
pSTM->hGlobal = hGlobalMemory;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT nsDataObjCollection::GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
|
||||
{
|
||||
ULONG num = 0;
|
||||
ULONG numwanted = (pFE->lindex == -1) ? 0 : pFE->lindex;
|
||||
FORMATETC fEtc = *pFE;
|
||||
fEtc.lindex = -1; // We're lying to the data object so it thinks it's alone
|
||||
|
||||
// The key for this data type is to figure out which data object the index
|
||||
// corresponds to and then just pass it along
|
||||
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
|
||||
nsDataObj* dataObj = mDataObjects.ElementAt(i);
|
||||
if (dataObj->QueryGetData(&fEtc) != S_OK)
|
||||
continue;
|
||||
if (num == numwanted)
|
||||
return dataObj->GetData(pFE, pSTM);
|
||||
num++;
|
||||
}
|
||||
return DV_E_LINDEX;
|
||||
}
|
||||
|
||||
HRESULT nsDataObjCollection::GetFirstSupporting(LPFORMATETC pFE,
|
||||
LPSTGMEDIUM pSTM)
|
||||
{
|
||||
// There is no way to pass more than one of this, so just find the first data
|
||||
// object that supports it and pass it along
|
||||
for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
|
||||
if (mDataObjects.ElementAt(i)->QueryGetData(pFE) == S_OK)
|
||||
return mDataObjects.ElementAt(i)->GetData(pFE, pSTM);
|
||||
}
|
||||
return DV_E_FORMATETC;
|
||||
}
|
||||
95
widget/windows/nsDataObjCollection.h
Normal file
95
widget/windows/nsDataObjCollection.h
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef _NSDATAOBJCOLLECTION_H_
|
||||
#define _NSDATAOBJCOLLECTION_H_
|
||||
|
||||
#include <oleidl.h>
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsDataObj.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#define MULTI_MIME "Mozilla/IDataObjectCollectionFormat"
|
||||
|
||||
EXTERN_C const IID IID_IDataObjCollection;
|
||||
|
||||
// An interface to make sure we have the right kind of object for D&D
|
||||
// this way we can filter out collection objects that aren't ours
|
||||
class nsIDataObjCollection : public IUnknown {
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* This ole registered class is used to facilitate drag-drop of objects which
|
||||
* can be adapted by an object derived from CfDragDrop. The CfDragDrop is
|
||||
* associated with instances via SetDragDrop().
|
||||
*/
|
||||
|
||||
class nsDataObjCollection final : public nsIDataObjCollection, public nsDataObj
|
||||
{
|
||||
public:
|
||||
nsDataObjCollection();
|
||||
~nsDataObjCollection();
|
||||
|
||||
public: // IUnknown methods - see iunknown.h for documentation
|
||||
STDMETHODIMP_(ULONG) AddRef ();
|
||||
STDMETHODIMP QueryInterface(REFIID, void**);
|
||||
STDMETHODIMP_(ULONG) Release ();
|
||||
|
||||
public: // DataGet and DataSet helper methods
|
||||
virtual HRESULT GetFile(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
|
||||
virtual HRESULT GetText(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
|
||||
virtual HRESULT GetFileDescriptors(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
|
||||
virtual HRESULT GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
|
||||
virtual HRESULT GetFirstSupporting(LPFORMATETC pFE, LPSTGMEDIUM pSTM);
|
||||
|
||||
using nsDataObj::GetFile;
|
||||
using nsDataObj::GetFileContents;
|
||||
using nsDataObj::GetText;
|
||||
|
||||
// support for clipboard
|
||||
void AddDataFlavor(const char * aDataFlavor, LPFORMATETC aFE);
|
||||
|
||||
// from nsPIDataObjCollection
|
||||
void AddDataObject(IDataObject * aDataObj);
|
||||
int32_t GetNumDataObjects() { return mDataObjects.Length(); }
|
||||
nsDataObj* GetDataObjectAt(uint32_t aItem)
|
||||
{ return mDataObjects.SafeElementAt(aItem, RefPtr<nsDataObj>()); }
|
||||
|
||||
// Return the registered OLE class ID of this object's CfDataObj.
|
||||
CLSID GetClassID() const;
|
||||
|
||||
public:
|
||||
// Store data in pSTM according to the format specified by pFE, if the
|
||||
// format is supported (supported formats are specified in CfDragDrop::
|
||||
// GetFormats) and return NOERROR; otherwise return DATA_E_FORMATETC. It
|
||||
// is the callers responsibility to free pSTM if NOERROR is returned.
|
||||
STDMETHODIMP GetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
|
||||
|
||||
// Similar to GetData except that the caller allocates the structure
|
||||
// referenced by pSTM.
|
||||
STDMETHODIMP GetDataHere (LPFORMATETC pFE, LPSTGMEDIUM pSTM);
|
||||
|
||||
// Returns S_TRUE if this object supports the format specified by pSTM,
|
||||
// S_FALSE otherwise.
|
||||
STDMETHODIMP QueryGetData (LPFORMATETC pFE);
|
||||
|
||||
// Set this objects data according to the format specified by pFE and
|
||||
// the storage medium specified by pSTM and return NOERROR, if the format
|
||||
// is supported. If release is TRUE this object must release the storage
|
||||
// associated with pSTM.
|
||||
STDMETHODIMP SetData (LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL release);
|
||||
|
||||
protected:
|
||||
ULONG m_cRef; // the reference count
|
||||
|
||||
nsTArray<RefPtr<nsDataObj> > mDataObjects;
|
||||
};
|
||||
|
||||
#endif //
|
||||
669
widget/windows/nsDeviceContextSpecWin.cpp
Normal file
669
widget/windows/nsDeviceContextSpecWin.cpp
Normal file
|
|
@ -0,0 +1,669 @@
|
|||
/* -*- 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 "nsDeviceContextSpecWin.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/gfx/PrintTargetPDF.h"
|
||||
#include "mozilla/gfx/PrintTargetWindows.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#include "prmem.h"
|
||||
|
||||
#include <winspool.h>
|
||||
|
||||
#include "nsIWidget.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsIPrintSettingsWin.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsStringEnumerator.h"
|
||||
|
||||
#include "gfxWindowsSurface.h"
|
||||
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
static mozilla::LazyLogModule kWidgetPrintingLogMod("printing-widget");
|
||||
#define PR_PL(_p1) MOZ_LOG(kWidgetPrintingLogMod, mozilla::LogLevel::Debug, _p1)
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
static const wchar_t kDriverName[] = L"WINSPOOL";
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// The printer data is shared between the PrinterEnumerator and the nsDeviceContextSpecWin
|
||||
// The PrinterEnumerator creates the printer info
|
||||
// but the nsDeviceContextSpecWin cleans it up
|
||||
// If it gets created (via the Page Setup Dialog) but the user never prints anything
|
||||
// then it will never be delete, so this class takes care of that.
|
||||
class GlobalPrinters {
|
||||
public:
|
||||
static GlobalPrinters* GetInstance() { return &mGlobalPrinters; }
|
||||
~GlobalPrinters() { FreeGlobalPrinters(); }
|
||||
|
||||
void FreeGlobalPrinters();
|
||||
|
||||
bool PrintersAreAllocated() { return mPrinters != nullptr; }
|
||||
LPWSTR GetItemFromList(int32_t aInx) { return mPrinters?mPrinters->ElementAt(aInx):nullptr; }
|
||||
nsresult EnumeratePrinterList();
|
||||
void GetDefaultPrinterName(nsString& aDefaultPrinterName);
|
||||
uint32_t GetNumPrinters() { return mPrinters?mPrinters->Length():0; }
|
||||
|
||||
protected:
|
||||
GlobalPrinters() {}
|
||||
nsresult EnumerateNativePrinters();
|
||||
void ReallocatePrinters();
|
||||
|
||||
static GlobalPrinters mGlobalPrinters;
|
||||
static nsTArray<LPWSTR>* mPrinters;
|
||||
};
|
||||
//---------------
|
||||
// static members
|
||||
GlobalPrinters GlobalPrinters::mGlobalPrinters;
|
||||
nsTArray<LPWSTR>* GlobalPrinters::mPrinters = nullptr;
|
||||
|
||||
struct AutoFreeGlobalPrinters
|
||||
{
|
||||
~AutoFreeGlobalPrinters() {
|
||||
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
nsDeviceContextSpecWin::nsDeviceContextSpecWin()
|
||||
{
|
||||
mDriverName = nullptr;
|
||||
mDeviceName = nullptr;
|
||||
mDevMode = nullptr;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDeviceContextSpecWin, nsIDeviceContextSpec)
|
||||
|
||||
nsDeviceContextSpecWin::~nsDeviceContextSpecWin()
|
||||
{
|
||||
SetDeviceName(nullptr);
|
||||
SetDriverName(nullptr);
|
||||
SetDevMode(nullptr);
|
||||
|
||||
nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(mPrintSettings));
|
||||
if (psWin) {
|
||||
psWin->SetDeviceName(nullptr);
|
||||
psWin->SetDriverName(nullptr);
|
||||
psWin->SetDevMode(nullptr);
|
||||
}
|
||||
|
||||
// Free them, we won't need them for a while
|
||||
GlobalPrinters::GetInstance()->FreeGlobalPrinters();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// helper
|
||||
static char16_t * GetDefaultPrinterNameFromGlobalPrinters()
|
||||
{
|
||||
nsAutoString printerName;
|
||||
GlobalPrinters::GetInstance()->GetDefaultPrinterName(printerName);
|
||||
return ToNewUnicode(printerName);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget,
|
||||
nsIPrintSettings* aPrintSettings,
|
||||
bool aIsPrintPreview)
|
||||
{
|
||||
mPrintSettings = aPrintSettings;
|
||||
|
||||
nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
|
||||
if (aPrintSettings) {
|
||||
// If we're in the child and printing via the parent or we're printing to
|
||||
// PDF we only need information from the print settings.
|
||||
mPrintSettings->GetOutputFormat(&mOutputFormat);
|
||||
if ((XRE_IsContentProcess() &&
|
||||
Preferences::GetBool("print.print_via_parent")) ||
|
||||
mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
|
||||
if (psWin) {
|
||||
char16_t* deviceName;
|
||||
char16_t* driverName;
|
||||
psWin->GetDeviceName(&deviceName); // creates new memory (makes a copy)
|
||||
psWin->GetDriverName(&driverName); // creates new memory (makes a copy)
|
||||
|
||||
LPDEVMODEW devMode;
|
||||
psWin->GetDevMode(&devMode); // creates new memory (makes a copy)
|
||||
|
||||
if (deviceName && driverName && devMode) {
|
||||
// Scaling is special, it is one of the few
|
||||
// devMode items that we control in layout
|
||||
if (devMode->dmFields & DM_SCALE) {
|
||||
double scale = double(devMode->dmScale) / 100.0f;
|
||||
if (scale != 1.0) {
|
||||
aPrintSettings->SetScaling(scale);
|
||||
devMode->dmScale = 100;
|
||||
}
|
||||
}
|
||||
|
||||
SetDeviceName(deviceName);
|
||||
SetDriverName(driverName);
|
||||
SetDevMode(devMode);
|
||||
|
||||
// clean up
|
||||
free(deviceName);
|
||||
free(driverName);
|
||||
|
||||
return NS_OK;
|
||||
} else {
|
||||
PR_PL(("***** nsDeviceContextSpecWin::Init - deviceName/driverName/devMode was NULL!\n"));
|
||||
if (deviceName) free(deviceName);
|
||||
if (driverName) free(driverName);
|
||||
if (devMode) ::HeapFree(::GetProcessHeap(), 0, devMode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PR_PL(("***** nsDeviceContextSpecWin::Init - aPrintSettingswas NULL!\n"));
|
||||
}
|
||||
|
||||
// Get the Printer Name to be used and output format.
|
||||
char16_t * printerName = nullptr;
|
||||
if (mPrintSettings) {
|
||||
mPrintSettings->GetPrinterName(&printerName);
|
||||
}
|
||||
|
||||
// If there is no name then use the default printer
|
||||
if (!printerName || (printerName && !*printerName)) {
|
||||
printerName = GetDefaultPrinterNameFromGlobalPrinters();
|
||||
}
|
||||
|
||||
NS_ASSERTION(printerName, "We have to have a printer name");
|
||||
if (!printerName || !*printerName) return rv;
|
||||
|
||||
return GetDataFromPrinter(printerName, mPrintSettings);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
// Helper Function - Free and reallocate the string
|
||||
static void CleanAndCopyString(wchar_t*& aStr, const wchar_t* aNewStr)
|
||||
{
|
||||
if (aStr != nullptr) {
|
||||
if (aNewStr != nullptr && wcslen(aStr) > wcslen(aNewStr)) { // reuse it if we can
|
||||
wcscpy(aStr, aNewStr);
|
||||
return;
|
||||
} else {
|
||||
PR_Free(aStr);
|
||||
aStr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (nullptr != aNewStr) {
|
||||
aStr = (wchar_t *)PR_Malloc(sizeof(wchar_t)*(wcslen(aNewStr) + 1));
|
||||
wcscpy(aStr, aNewStr);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<PrintTarget> nsDeviceContextSpecWin::MakePrintTarget()
|
||||
{
|
||||
NS_ASSERTION(mDevMode, "DevMode can't be NULL here");
|
||||
|
||||
if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
|
||||
nsXPIDLString filename;
|
||||
mPrintSettings->GetToFileName(getter_Copies(filename));
|
||||
|
||||
double width, height;
|
||||
mPrintSettings->GetEffectivePageSize(&width, &height);
|
||||
if (width <= 0 || height <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// convert twips to points
|
||||
width /= TWIPS_PER_POINT_FLOAT;
|
||||
height /= TWIPS_PER_POINT_FLOAT;
|
||||
|
||||
nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
nsresult rv = file->InitWithPath(filename);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFileOutputStream> stream = do_CreateInstance("@mozilla.org/network/file-output-stream;1");
|
||||
rv = stream->Init(file, -1, -1, 0);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return PrintTargetPDF::CreateOrNull(stream, IntSize::Truncate(width, height));
|
||||
}
|
||||
|
||||
if (mDevMode) {
|
||||
NS_WARNING_ASSERTION(mDriverName, "No driver!");
|
||||
HDC dc = ::CreateDCW(mDriverName, mDeviceName, nullptr, mDevMode);
|
||||
if (!dc) {
|
||||
gfxCriticalError(gfxCriticalError::DefaultOptions(false))
|
||||
<< "Failed to create device context in GetSurfaceForPrinter";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The PrintTargetWindows takes over ownership of this DC
|
||||
return PrintTargetWindows::CreateOrNull(dc);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
float
|
||||
nsDeviceContextSpecWin::GetDPI()
|
||||
{
|
||||
// To match the previous printing code we need to return 72 when printing to
|
||||
// PDF and 144 when printing to a Windows surface.
|
||||
return mOutputFormat == nsIPrintSettings::kOutputFormatPDF ? 72.0f : 144.0f;
|
||||
}
|
||||
|
||||
float
|
||||
nsDeviceContextSpecWin::GetPrintingScale()
|
||||
{
|
||||
MOZ_ASSERT(mPrintSettings);
|
||||
|
||||
// To match the previous printing code there is no scaling for PDF.
|
||||
if (mOutputFormat == nsIPrintSettings::kOutputFormatPDF) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// The print settings will have the resolution stored from the real device.
|
||||
int32_t resolution;
|
||||
mPrintSettings->GetResolution(&resolution);
|
||||
return float(resolution) / GetDPI();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void nsDeviceContextSpecWin::SetDeviceName(char16ptr_t aDeviceName)
|
||||
{
|
||||
CleanAndCopyString(mDeviceName, aDeviceName);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void nsDeviceContextSpecWin::SetDriverName(char16ptr_t aDriverName)
|
||||
{
|
||||
CleanAndCopyString(mDriverName, aDriverName);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode)
|
||||
{
|
||||
if (mDevMode) {
|
||||
::HeapFree(::GetProcessHeap(), 0, mDevMode);
|
||||
}
|
||||
|
||||
mDevMode = aDevMode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
void
|
||||
nsDeviceContextSpecWin::GetDevMode(LPDEVMODEW &aDevMode)
|
||||
{
|
||||
aDevMode = mDevMode;
|
||||
}
|
||||
|
||||
#define DISPLAY_LAST_ERROR
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Setup the object's data member with the selected printer's data
|
||||
nsresult
|
||||
nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS)
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
if (!GlobalPrinters::GetInstance()->PrintersAreAllocated()) {
|
||||
rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
|
||||
if (NS_FAILED(rv)) {
|
||||
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't enumerate printers!\n"));
|
||||
DISPLAY_LAST_ERROR
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsHPRINTER hPrinter = nullptr;
|
||||
wchar_t *name = (wchar_t*)aName; // Windows APIs use non-const name argument
|
||||
|
||||
BOOL status = ::OpenPrinterW(name, &hPrinter, nullptr);
|
||||
if (status) {
|
||||
nsAutoPrinter autoPrinter(hPrinter);
|
||||
|
||||
LPDEVMODEW pDevMode;
|
||||
|
||||
// Allocate a buffer of the correct size.
|
||||
LONG needed = ::DocumentPropertiesW(nullptr, hPrinter, name, nullptr,
|
||||
nullptr, 0);
|
||||
if (needed < 0) {
|
||||
PR_PL(("**** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't get "
|
||||
"size of DEVMODE using DocumentPropertiesW(pDeviceName = \"%s\"). "
|
||||
"GetLastEror() = %08x\n",
|
||||
aName ? NS_ConvertUTF16toUTF8(aName).get() : "", GetLastError()));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
pDevMode = (LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
needed);
|
||||
if (!pDevMode) return NS_ERROR_FAILURE;
|
||||
|
||||
// Get the default DevMode for the printer and modify it for our needs.
|
||||
LONG ret = ::DocumentPropertiesW(nullptr, hPrinter, name,
|
||||
pDevMode, nullptr, DM_OUT_BUFFER);
|
||||
|
||||
if (ret == IDOK && aPS) {
|
||||
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
|
||||
MOZ_ASSERT(psWin);
|
||||
psWin->CopyToNative(pDevMode);
|
||||
// Sets back the changes we made to the DevMode into the Printer Driver
|
||||
ret = ::DocumentPropertiesW(nullptr, hPrinter, name,
|
||||
pDevMode, pDevMode,
|
||||
DM_IN_BUFFER | DM_OUT_BUFFER);
|
||||
|
||||
// We need to copy the final DEVMODE settings back to our print settings,
|
||||
// because they may have been set from invalid prefs.
|
||||
if (ret == IDOK) {
|
||||
// We need to get information from the device as well.
|
||||
nsAutoHDC printerDC(::CreateICW(kDriverName, aName, nullptr, pDevMode));
|
||||
if (NS_WARN_IF(!printerDC)) {
|
||||
::HeapFree(::GetProcessHeap(), 0, pDevMode);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
psWin->CopyFromNative(printerDC, pDevMode);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != IDOK) {
|
||||
::HeapFree(::GetProcessHeap(), 0, pDevMode);
|
||||
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", ret, ret));
|
||||
DISPLAY_LAST_ERROR
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
SetDevMode(pDevMode); // cache the pointer and takes responsibility for the memory
|
||||
|
||||
SetDeviceName(aName);
|
||||
|
||||
SetDriverName(kDriverName);
|
||||
|
||||
rv = NS_OK;
|
||||
} else {
|
||||
rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;
|
||||
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't open printer: [%s]\n", NS_ConvertUTF16toUTF8(aName).get()));
|
||||
DISPLAY_LAST_ERROR
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
// Printer Enumerator
|
||||
//***********************************************************
|
||||
nsPrinterEnumeratorWin::nsPrinterEnumeratorWin()
|
||||
{
|
||||
}
|
||||
|
||||
nsPrinterEnumeratorWin::~nsPrinterEnumeratorWin()
|
||||
{
|
||||
// Do not free printers here
|
||||
// GlobalPrinters::GetInstance()->FreeGlobalPrinters();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPrinterEnumeratorWin, nsIPrinterEnumerator)
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Return the Default Printer name
|
||||
NS_IMETHODIMP
|
||||
nsPrinterEnumeratorWin::GetDefaultPrinterName(char16_t * *aDefaultPrinterName)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDefaultPrinterName);
|
||||
|
||||
*aDefaultPrinterName = GetDefaultPrinterNameFromGlobalPrinters(); // helper
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, nsIPrintSettings *aPrintSettings)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPrinterName);
|
||||
NS_ENSURE_ARG_POINTER(aPrintSettings);
|
||||
|
||||
if (!*aPrinterName) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// When printing to PDF on Windows there is no associated printer driver.
|
||||
int16_t outputFormat;
|
||||
aPrintSettings->GetOutputFormat(&outputFormat);
|
||||
if (outputFormat == nsIPrintSettings::kOutputFormatPDF) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsDeviceContextSpecWin> devSpecWin = new nsDeviceContextSpecWin();
|
||||
if (!devSpecWin) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (NS_FAILED(GlobalPrinters::GetInstance()->EnumeratePrinterList())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
AutoFreeGlobalPrinters autoFreeGlobalPrinters;
|
||||
|
||||
// If the settings have already been initialized from prefs then pass these to
|
||||
// GetDataFromPrinter, so that they are saved to the printer.
|
||||
bool initializedFromPrefs;
|
||||
nsresult rv =
|
||||
aPrintSettings->GetIsInitializedFromPrefs(&initializedFromPrefs);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (initializedFromPrefs) {
|
||||
// If we pass in print settings to GetDataFromPrinter it already copies
|
||||
// things back to the settings, so we can return here.
|
||||
return devSpecWin->GetDataFromPrinter(aPrinterName, aPrintSettings);
|
||||
}
|
||||
|
||||
devSpecWin->GetDataFromPrinter(aPrinterName);
|
||||
|
||||
LPDEVMODEW devmode;
|
||||
devSpecWin->GetDevMode(devmode);
|
||||
if (NS_WARN_IF(!devmode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aPrintSettings->SetPrinterName(aPrinterName);
|
||||
|
||||
// We need to get information from the device as well.
|
||||
char16ptr_t printerName = aPrinterName;
|
||||
HDC dc = ::CreateICW(kDriverName, printerName, nullptr, devmode);
|
||||
if (NS_WARN_IF(!dc)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPrintSettings);
|
||||
MOZ_ASSERT(psWin);
|
||||
psWin->CopyFromNative(dc, devmode);
|
||||
::DeleteDC(dc);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Enumerate all the Printers from the global array and pass their
|
||||
// names back (usually to script)
|
||||
NS_IMETHODIMP
|
||||
nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator **aPrinterNameList)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPrinterNameList);
|
||||
*aPrinterNameList = nullptr;
|
||||
|
||||
nsresult rv = GlobalPrinters::GetInstance()->EnumeratePrinterList();
|
||||
if (NS_FAILED(rv)) {
|
||||
PR_PL(("***** nsDeviceContextSpecWin::GetPrinterNameList - Couldn't enumerate printers!\n"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint32_t numPrinters = GlobalPrinters::GetInstance()->GetNumPrinters();
|
||||
nsTArray<nsString> *printers = new nsTArray<nsString>(numPrinters);
|
||||
if (!printers)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsString* names = printers->AppendElements(numPrinters);
|
||||
for (uint32_t printerInx = 0; printerInx < numPrinters; ++printerInx) {
|
||||
LPWSTR name = GlobalPrinters::GetInstance()->GetItemFromList(printerInx);
|
||||
names[printerInx].Assign(name);
|
||||
}
|
||||
|
||||
return NS_NewAdoptingStringEnumerator(aPrinterNameList, printers);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
//-- Global Printers
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// THe array hold the name and port for each printer
|
||||
void
|
||||
GlobalPrinters::ReallocatePrinters()
|
||||
{
|
||||
if (PrintersAreAllocated()) {
|
||||
FreeGlobalPrinters();
|
||||
}
|
||||
mPrinters = new nsTArray<LPWSTR>();
|
||||
NS_ASSERTION(mPrinters, "Printers Array is NULL!");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void
|
||||
GlobalPrinters::FreeGlobalPrinters()
|
||||
{
|
||||
if (mPrinters != nullptr) {
|
||||
for (uint32_t i=0;i<mPrinters->Length();i++) {
|
||||
free(mPrinters->ElementAt(i));
|
||||
}
|
||||
delete mPrinters;
|
||||
mPrinters = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
nsresult
|
||||
GlobalPrinters::EnumerateNativePrinters()
|
||||
{
|
||||
nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE;
|
||||
PR_PL(("-----------------------\n"));
|
||||
PR_PL(("EnumerateNativePrinters\n"));
|
||||
|
||||
WCHAR szDefaultPrinterName[1024];
|
||||
DWORD status = GetProfileStringW(L"devices", 0, L",",
|
||||
szDefaultPrinterName,
|
||||
ArrayLength(szDefaultPrinterName));
|
||||
if (status > 0) {
|
||||
DWORD count = 0;
|
||||
LPWSTR sPtr = szDefaultPrinterName;
|
||||
LPWSTR ePtr = szDefaultPrinterName + status;
|
||||
LPWSTR prvPtr = sPtr;
|
||||
while (sPtr < ePtr) {
|
||||
if (*sPtr == 0) {
|
||||
LPWSTR name = wcsdup(prvPtr);
|
||||
mPrinters->AppendElement(name);
|
||||
PR_PL(("Printer Name: %s\n", prvPtr));
|
||||
prvPtr = sPtr+1;
|
||||
count++;
|
||||
}
|
||||
sPtr++;
|
||||
}
|
||||
rv = NS_OK;
|
||||
}
|
||||
PR_PL(("-----------------------\n"));
|
||||
return rv;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Uses the GetProfileString to get the default printer from the registry
|
||||
void
|
||||
GlobalPrinters::GetDefaultPrinterName(nsString& aDefaultPrinterName)
|
||||
{
|
||||
aDefaultPrinterName.Truncate();
|
||||
WCHAR szDefaultPrinterName[1024];
|
||||
DWORD status = GetProfileStringW(L"windows", L"device", 0,
|
||||
szDefaultPrinterName,
|
||||
ArrayLength(szDefaultPrinterName));
|
||||
if (status > 0) {
|
||||
WCHAR comma = ',';
|
||||
LPWSTR sPtr = szDefaultPrinterName;
|
||||
while (*sPtr != comma && *sPtr != 0)
|
||||
sPtr++;
|
||||
if (*sPtr == comma) {
|
||||
*sPtr = 0;
|
||||
}
|
||||
aDefaultPrinterName = szDefaultPrinterName;
|
||||
} else {
|
||||
aDefaultPrinterName = EmptyString();
|
||||
}
|
||||
|
||||
PR_PL(("DEFAULT PRINTER [%s]\n", aDefaultPrinterName.get()));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// This goes and gets the list of available printers and puts
|
||||
// the default printer at the beginning of the list
|
||||
nsresult
|
||||
GlobalPrinters::EnumeratePrinterList()
|
||||
{
|
||||
// reallocate and get a new list each time it is asked for
|
||||
// this deletes the list and re-allocates them
|
||||
ReallocatePrinters();
|
||||
|
||||
// any of these could only fail with an OUT_MEMORY_ERROR
|
||||
// PRINTER_ENUM_LOCAL should get the network printers on Win95
|
||||
nsresult rv = EnumerateNativePrinters();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// get the name of the default printer
|
||||
nsAutoString defPrinterName;
|
||||
GetDefaultPrinterName(defPrinterName);
|
||||
|
||||
// put the default printer at the beginning of list
|
||||
if (!defPrinterName.IsEmpty()) {
|
||||
for (uint32_t i=0;i<mPrinters->Length();i++) {
|
||||
LPWSTR name = mPrinters->ElementAt(i);
|
||||
if (defPrinterName.Equals(name)) {
|
||||
if (i > 0) {
|
||||
LPWSTR ptr = mPrinters->ElementAt(0);
|
||||
mPrinters->ElementAt(0) = name;
|
||||
mPrinters->ElementAt(i) = ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we at least tried to get the printers
|
||||
if (!PrintersAreAllocated()) {
|
||||
PR_PL(("***** nsDeviceContextSpecWin::EnumeratePrinterList - Printers aren`t allocated\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
84
widget/windows/nsDeviceContextSpecWin.h
Normal file
84
widget/windows/nsDeviceContextSpecWin.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsDeviceContextSpecWin_h___
|
||||
#define nsDeviceContextSpecWin_h___
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDeviceContextSpec.h"
|
||||
#include "nsIPrinterEnumerator.h"
|
||||
#include "nsIPrintSettings.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include <windows.h>
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class nsIWidget;
|
||||
|
||||
class nsDeviceContextSpecWin : public nsIDeviceContextSpec
|
||||
{
|
||||
public:
|
||||
nsDeviceContextSpecWin();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
virtual already_AddRefed<PrintTarget> MakePrintTarget() final;
|
||||
NS_IMETHOD BeginDocument(const nsAString& aTitle,
|
||||
const nsAString& aPrintToFileName,
|
||||
int32_t aStartPage,
|
||||
int32_t aEndPage) override { return NS_OK; }
|
||||
NS_IMETHOD EndDocument() override { return NS_OK; }
|
||||
NS_IMETHOD BeginPage() override { return NS_OK; }
|
||||
NS_IMETHOD EndPage() override { return NS_OK; }
|
||||
|
||||
NS_IMETHOD Init(nsIWidget* aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override;
|
||||
|
||||
float GetDPI() final;
|
||||
|
||||
float GetPrintingScale() final;
|
||||
|
||||
void GetDriverName(wchar_t *&aDriverName) const { aDriverName = mDriverName; }
|
||||
void GetDeviceName(wchar_t *&aDeviceName) const { aDeviceName = mDeviceName; }
|
||||
|
||||
// The GetDevMode will return a pointer to a DevMode
|
||||
// whether it is from the Global memory handle or just the DevMode
|
||||
// To get the DevMode from the Global memory Handle it must lock it
|
||||
// So this call must be paired with a call to UnlockGlobalHandle
|
||||
void GetDevMode(LPDEVMODEW &aDevMode);
|
||||
|
||||
// helper functions
|
||||
nsresult GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* aPS = nullptr);
|
||||
|
||||
protected:
|
||||
|
||||
void SetDeviceName(char16ptr_t aDeviceName);
|
||||
void SetDriverName(char16ptr_t aDriverName);
|
||||
void SetDevMode(LPDEVMODEW aDevMode);
|
||||
|
||||
virtual ~nsDeviceContextSpecWin();
|
||||
|
||||
wchar_t* mDriverName;
|
||||
wchar_t* mDeviceName;
|
||||
LPDEVMODEW mDevMode;
|
||||
|
||||
nsCOMPtr<nsIPrintSettings> mPrintSettings;
|
||||
int16_t mOutputFormat = nsIPrintSettings::kOutputFormatNative;
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Printer Enumerator
|
||||
//-------------------------------------------------------------------------
|
||||
class nsPrinterEnumeratorWin final : public nsIPrinterEnumerator
|
||||
{
|
||||
~nsPrinterEnumeratorWin();
|
||||
|
||||
public:
|
||||
nsPrinterEnumeratorWin();
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPRINTERENUMERATOR
|
||||
};
|
||||
|
||||
#endif
|
||||
641
widget/windows/nsDragService.cpp
Normal file
641
widget/windows/nsDragService.cpp
Normal file
|
|
@ -0,0 +1,641 @@
|
|||
/* -*- 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 <ole2.h>
|
||||
#include <oleidl.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
// shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsDragService.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsDataObj.h"
|
||||
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsNativeDragTarget.h"
|
||||
#include "nsNativeDragSource.h"
|
||||
#include "nsClipboard.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsDataObjCollection.h"
|
||||
|
||||
#include "nsArrayUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsIScreenManager.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsCWebBrowserPersist.h"
|
||||
#include "nsToolkit.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "gfxContext.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsMathUtils.h"
|
||||
#include "WinUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// DragService constructor
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
nsDragService::nsDragService()
|
||||
: mDataObject(nullptr), mSentLocalDropEvent(false)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// DragService destructor
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
nsDragService::~nsDragService()
|
||||
{
|
||||
NS_IF_RELEASE(mDataObject);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDragService::CreateDragImage(nsIDOMNode *aDOMNode,
|
||||
nsIScriptableRegion *aRegion,
|
||||
SHDRAGIMAGE *psdi)
|
||||
{
|
||||
if (!psdi)
|
||||
return false;
|
||||
|
||||
memset(psdi, 0, sizeof(SHDRAGIMAGE));
|
||||
if (!aDOMNode)
|
||||
return false;
|
||||
|
||||
// Prepare the drag image
|
||||
LayoutDeviceIntRect dragRect;
|
||||
RefPtr<SourceSurface> surface;
|
||||
nsPresContext* pc;
|
||||
DrawDrag(aDOMNode, aRegion, mScreenPosition, &dragRect, &surface, &pc);
|
||||
if (!surface)
|
||||
return false;
|
||||
|
||||
uint32_t bmWidth = dragRect.width, bmHeight = dragRect.height;
|
||||
|
||||
if (bmWidth == 0 || bmHeight == 0)
|
||||
return false;
|
||||
|
||||
psdi->crColorKey = CLR_NONE;
|
||||
|
||||
RefPtr<DataSourceSurface> dataSurface =
|
||||
Factory::CreateDataSourceSurface(IntSize(bmWidth, bmHeight),
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
NS_ENSURE_TRUE(dataSurface, false);
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> dt =
|
||||
Factory::CreateDrawTargetForData(BackendType::CAIRO,
|
||||
map.mData,
|
||||
dataSurface->GetSize(),
|
||||
map.mStride,
|
||||
dataSurface->GetFormat());
|
||||
if (!dt) {
|
||||
dataSurface->Unmap();
|
||||
return false;
|
||||
}
|
||||
|
||||
dt->DrawSurface(surface,
|
||||
Rect(0, 0, dataSurface->GetSize().width, dataSurface->GetSize().height),
|
||||
Rect(0, 0, surface->GetSize().width, surface->GetSize().height),
|
||||
DrawSurfaceOptions(),
|
||||
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
|
||||
dt->Flush();
|
||||
|
||||
BITMAPV5HEADER bmih;
|
||||
memset((void*)&bmih, 0, sizeof(BITMAPV5HEADER));
|
||||
bmih.bV5Size = sizeof(BITMAPV5HEADER);
|
||||
bmih.bV5Width = bmWidth;
|
||||
bmih.bV5Height = -(int32_t)bmHeight; // flip vertical
|
||||
bmih.bV5Planes = 1;
|
||||
bmih.bV5BitCount = 32;
|
||||
bmih.bV5Compression = BI_BITFIELDS;
|
||||
bmih.bV5RedMask = 0x00FF0000;
|
||||
bmih.bV5GreenMask = 0x0000FF00;
|
||||
bmih.bV5BlueMask = 0x000000FF;
|
||||
bmih.bV5AlphaMask = 0xFF000000;
|
||||
|
||||
HDC hdcSrc = CreateCompatibleDC(nullptr);
|
||||
void *lpBits = nullptr;
|
||||
if (hdcSrc) {
|
||||
psdi->hbmpDragImage =
|
||||
::CreateDIBSection(hdcSrc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
|
||||
(void**)&lpBits, nullptr, 0);
|
||||
if (psdi->hbmpDragImage && lpBits) {
|
||||
CopySurfaceDataToPackedArray(map.mData, static_cast<uint8_t*>(lpBits),
|
||||
dataSurface->GetSize(), map.mStride,
|
||||
BytesPerPixel(dataSurface->GetFormat()));
|
||||
}
|
||||
|
||||
psdi->sizeDragImage.cx = bmWidth;
|
||||
psdi->sizeDragImage.cy = bmHeight;
|
||||
|
||||
LayoutDeviceIntPoint screenPoint =
|
||||
ConvertToUnscaledDevPixels(pc, mScreenPosition);
|
||||
psdi->ptOffset.x = screenPoint.x - dragRect.x;
|
||||
psdi->ptOffset.y = screenPoint.y - dragRect.y;
|
||||
|
||||
DeleteDC(hdcSrc);
|
||||
}
|
||||
|
||||
dataSurface->Unmap();
|
||||
|
||||
return psdi->hbmpDragImage != nullptr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
nsresult
|
||||
nsDragService::InvokeDragSessionImpl(nsIArray* anArrayTransferables,
|
||||
nsIScriptableRegion* aRegion,
|
||||
uint32_t aActionType)
|
||||
{
|
||||
// Try and get source URI of the items that are being dragged
|
||||
nsIURI *uri = nullptr;
|
||||
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mSourceDocument));
|
||||
if (doc) {
|
||||
uri = doc->GetDocumentURI();
|
||||
}
|
||||
|
||||
uint32_t numItemsToDrag = 0;
|
||||
nsresult rv = anArrayTransferables->GetLength(&numItemsToDrag);
|
||||
if (!numItemsToDrag)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// The clipboard class contains some static utility methods that we
|
||||
// can use to create an IDataObject from the transferable
|
||||
|
||||
// if we're dragging more than one item, we need to create a
|
||||
// "collection" object to fake out the OS. This collection contains
|
||||
// one |IDataObject| for each transferable. If there is just the one
|
||||
// (most cases), only pass around the native |IDataObject|.
|
||||
RefPtr<IDataObject> itemToDrag;
|
||||
if (numItemsToDrag > 1) {
|
||||
nsDataObjCollection * dataObjCollection = new nsDataObjCollection();
|
||||
if (!dataObjCollection)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
itemToDrag = dataObjCollection;
|
||||
for (uint32_t i=0; i<numItemsToDrag; ++i) {
|
||||
nsCOMPtr<nsITransferable> trans =
|
||||
do_QueryElementAt(anArrayTransferables, i);
|
||||
if (trans) {
|
||||
// set the requestingPrincipal on the transferable
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(mSourceNode);
|
||||
trans->SetRequestingPrincipal(node->NodePrincipal());
|
||||
trans->SetContentPolicyType(mContentPolicyType);
|
||||
RefPtr<IDataObject> dataObj;
|
||||
rv = nsClipboard::CreateNativeDataObject(trans,
|
||||
getter_AddRefs(dataObj), uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Add the flavors to the collection object too
|
||||
rv = nsClipboard::SetupNativeDataObject(trans, dataObjCollection);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
dataObjCollection->AddDataObject(dataObj);
|
||||
}
|
||||
}
|
||||
} // if dragging multiple items
|
||||
else {
|
||||
nsCOMPtr<nsITransferable> trans =
|
||||
do_QueryElementAt(anArrayTransferables, 0);
|
||||
if (trans) {
|
||||
// set the requestingPrincipal on the transferable
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(mSourceNode);
|
||||
trans->SetRequestingPrincipal(node->NodePrincipal());
|
||||
trans->SetContentPolicyType(mContentPolicyType);
|
||||
rv = nsClipboard::CreateNativeDataObject(trans,
|
||||
getter_AddRefs(itemToDrag),
|
||||
uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
} // else dragging a single object
|
||||
|
||||
// Create a drag image if support is available
|
||||
IDragSourceHelper *pdsh;
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_IDragSourceHelper, (void**)&pdsh))) {
|
||||
SHDRAGIMAGE sdi;
|
||||
if (CreateDragImage(mSourceNode, aRegion, &sdi)) {
|
||||
if (FAILED(pdsh->InitializeFromBitmap(&sdi, itemToDrag)))
|
||||
DeleteObject(sdi.hbmpDragImage);
|
||||
}
|
||||
pdsh->Release();
|
||||
}
|
||||
|
||||
// Kick off the native drag session
|
||||
return StartInvokingDragSession(itemToDrag, aActionType);
|
||||
}
|
||||
|
||||
static bool
|
||||
LayoutDevicePointToCSSPoint(const LayoutDevicePoint& aDevPos,
|
||||
CSSPoint& aCSSPos)
|
||||
{
|
||||
nsCOMPtr<nsIScreenManager> screenMgr =
|
||||
do_GetService("@mozilla.org/gfx/screenmanager;1");
|
||||
if (!screenMgr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
screenMgr->ScreenForRect(NSToIntRound(aDevPos.x), NSToIntRound(aDevPos.y),
|
||||
1, 1, getter_AddRefs(screen));
|
||||
if (!screen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t w,h; // unused
|
||||
LayoutDeviceIntPoint screenOriginDev;
|
||||
screen->GetRect(&screenOriginDev.x, &screenOriginDev.y, &w, &h);
|
||||
|
||||
double scale;
|
||||
screen->GetDefaultCSSScaleFactor(&scale);
|
||||
LayoutDeviceToCSSScale devToCSSScale =
|
||||
CSSToLayoutDeviceScale(scale).Inverse();
|
||||
|
||||
// Desktop pixels and CSS pixels share the same screen origin.
|
||||
CSSIntPoint screenOriginCSS;
|
||||
screen->GetRectDisplayPix(&screenOriginCSS.x, &screenOriginCSS.y, &w, &h);
|
||||
|
||||
aCSSPos = (aDevPos - screenOriginDev) * devToCSSScale + screenOriginCSS;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
|
||||
uint32_t aActionType)
|
||||
{
|
||||
// To do the drag we need to create an object that
|
||||
// implements the IDataObject interface (for OLE)
|
||||
RefPtr<nsNativeDragSource> nativeDragSrc =
|
||||
new nsNativeDragSource(mDataTransfer);
|
||||
|
||||
// Now figure out what the native drag effect should be
|
||||
DWORD winDropRes;
|
||||
DWORD effects = DROPEFFECT_SCROLL;
|
||||
if (aActionType & DRAGDROP_ACTION_COPY) {
|
||||
effects |= DROPEFFECT_COPY;
|
||||
}
|
||||
if (aActionType & DRAGDROP_ACTION_MOVE) {
|
||||
effects |= DROPEFFECT_MOVE;
|
||||
}
|
||||
if (aActionType & DRAGDROP_ACTION_LINK) {
|
||||
effects |= DROPEFFECT_LINK;
|
||||
}
|
||||
|
||||
// XXX not sure why we bother to cache this, it can change during
|
||||
// the drag
|
||||
mDragAction = aActionType;
|
||||
mSentLocalDropEvent = false;
|
||||
|
||||
// Start dragging
|
||||
StartDragSession();
|
||||
OpenDragPopup();
|
||||
|
||||
RefPtr<IAsyncOperation> pAsyncOp;
|
||||
// Offer to do an async drag
|
||||
if (SUCCEEDED(aDataObj->QueryInterface(IID_IAsyncOperation,
|
||||
getter_AddRefs(pAsyncOp)))) {
|
||||
pAsyncOp->SetAsyncMode(VARIANT_TRUE);
|
||||
} else {
|
||||
NS_NOTREACHED("When did our data object stop being async");
|
||||
}
|
||||
|
||||
// Call the native D&D method
|
||||
HRESULT res = ::DoDragDrop(aDataObj, nativeDragSrc, effects, &winDropRes);
|
||||
|
||||
// In cases where the drop operation completed outside the application, update
|
||||
// the source node's nsIDOMDataTransfer dropEffect value so it is up to date.
|
||||
if (!mSentLocalDropEvent) {
|
||||
uint32_t dropResult;
|
||||
// Order is important, since multiple flags can be returned.
|
||||
if (winDropRes & DROPEFFECT_COPY)
|
||||
dropResult = DRAGDROP_ACTION_COPY;
|
||||
else if (winDropRes & DROPEFFECT_LINK)
|
||||
dropResult = DRAGDROP_ACTION_LINK;
|
||||
else if (winDropRes & DROPEFFECT_MOVE)
|
||||
dropResult = DRAGDROP_ACTION_MOVE;
|
||||
else
|
||||
dropResult = DRAGDROP_ACTION_NONE;
|
||||
|
||||
if (mDataTransfer) {
|
||||
if (res == DRAGDROP_S_DROP) // Success
|
||||
mDataTransfer->SetDropEffectInt(dropResult);
|
||||
else
|
||||
mDataTransfer->SetDropEffectInt(DRAGDROP_ACTION_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
mUserCancelled = nativeDragSrc->UserCancelled();
|
||||
|
||||
// We're done dragging, get the cursor position and end the drag
|
||||
// Use GetMessagePos to get the position of the mouse at the last message
|
||||
// seen by the event loop. (Bug 489729)
|
||||
// Note that we must convert this from device pixels back to Windows logical
|
||||
// pixels (bug 818927).
|
||||
DWORD pos = ::GetMessagePos();
|
||||
CSSPoint cssPos;
|
||||
if (!LayoutDevicePointToCSSPoint(LayoutDevicePoint(GET_X_LPARAM(pos),
|
||||
GET_Y_LPARAM(pos)),
|
||||
cssPos)) {
|
||||
// fallback to the simple scaling
|
||||
POINT pt = { GET_X_LPARAM(pos), GET_Y_LPARAM(pos) };
|
||||
HMONITOR monitor = ::MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
|
||||
double dpiScale = widget::WinUtils::LogToPhysFactor(monitor);
|
||||
cssPos.x = GET_X_LPARAM(pos) / dpiScale;
|
||||
cssPos.y = GET_Y_LPARAM(pos) / dpiScale;
|
||||
}
|
||||
// We have to abuse SetDragEndPoint to pass CSS pixels because
|
||||
// Event::GetScreenCoords will not convert pixels for dragend events
|
||||
// until bug 1224754 is fixed.
|
||||
SetDragEndPoint(LayoutDeviceIntPoint(NSToIntRound(cssPos.x),
|
||||
NSToIntRound(cssPos.y)));
|
||||
EndDragSession(true);
|
||||
|
||||
mDoingDrag = false;
|
||||
|
||||
return DRAGDROP_S_DROP == res ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Make Sure we have the right kind of object
|
||||
nsDataObjCollection*
|
||||
nsDragService::GetDataObjCollection(IDataObject* aDataObj)
|
||||
{
|
||||
nsDataObjCollection * dataObjCol = nullptr;
|
||||
if (aDataObj) {
|
||||
nsIDataObjCollection* dataObj;
|
||||
if (aDataObj->QueryInterface(IID_IDataObjCollection,
|
||||
(void**)&dataObj) == S_OK) {
|
||||
dataObjCol = static_cast<nsDataObjCollection*>(aDataObj);
|
||||
dataObj->Release();
|
||||
}
|
||||
}
|
||||
|
||||
return dataObjCol;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsDragService::GetNumDropItems(uint32_t * aNumItems)
|
||||
{
|
||||
if (!mDataObject) {
|
||||
*aNumItems = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (IsCollectionObject(mDataObject)) {
|
||||
nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject);
|
||||
if (dataObjCol) {
|
||||
*aNumItems = dataObjCol->GetNumDataObjects();
|
||||
}
|
||||
else {
|
||||
// If the count cannot be determined just return 0.
|
||||
// This can happen if we have collection data of type
|
||||
// MULTI_MIME ("Mozilla/IDataObjectCollectionFormat") on the clipboard
|
||||
// from another process but we can't obtain an IID_IDataObjCollection
|
||||
// from this process.
|
||||
*aNumItems = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Next check if we have a file drop. Return the number of files in
|
||||
// the file drop as the number of items we have, pretending like we
|
||||
// actually have > 1 drag item.
|
||||
FORMATETC fe2;
|
||||
SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
|
||||
if (mDataObject->QueryGetData(&fe2) == S_OK) {
|
||||
STGMEDIUM stm;
|
||||
if (mDataObject->GetData(&fe2, &stm) == S_OK) {
|
||||
HDROP hdrop = (HDROP)GlobalLock(stm.hGlobal);
|
||||
*aNumItems = ::DragQueryFileW(hdrop, 0xFFFFFFFF, nullptr, 0);
|
||||
::GlobalUnlock(stm.hGlobal);
|
||||
::ReleaseStgMedium(&stm);
|
||||
// Data may be provided later, so assume we have 1 item
|
||||
if (*aNumItems == 0)
|
||||
*aNumItems = 1;
|
||||
}
|
||||
else
|
||||
*aNumItems = 1;
|
||||
}
|
||||
else
|
||||
*aNumItems = 1;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsDragService::GetData(nsITransferable * aTransferable, uint32_t anItem)
|
||||
{
|
||||
// This typcially happens on a drop, the target would be asking
|
||||
// for it's transferable to be filled in
|
||||
// Use a static clipboard utility method for this
|
||||
if (!mDataObject)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult dataFound = NS_ERROR_FAILURE;
|
||||
|
||||
if (IsCollectionObject(mDataObject)) {
|
||||
// multiple items, use |anItem| as an index into our collection
|
||||
nsDataObjCollection * dataObjCol = GetDataObjCollection(mDataObject);
|
||||
uint32_t cnt = dataObjCol->GetNumDataObjects();
|
||||
if (anItem < cnt) {
|
||||
IDataObject * dataObj = dataObjCol->GetDataObjectAt(anItem);
|
||||
dataFound = nsClipboard::GetDataFromDataObject(dataObj, 0, nullptr,
|
||||
aTransferable);
|
||||
}
|
||||
else
|
||||
NS_WARNING("Index out of range!");
|
||||
}
|
||||
else {
|
||||
// If they are asking for item "0", we can just get it...
|
||||
if (anItem == 0) {
|
||||
dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem,
|
||||
nullptr, aTransferable);
|
||||
} else {
|
||||
// It better be a file drop, or else non-zero indexes are invalid!
|
||||
FORMATETC fe2;
|
||||
SET_FORMATETC(fe2, CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
|
||||
if (mDataObject->QueryGetData(&fe2) == S_OK)
|
||||
dataFound = nsClipboard::GetDataFromDataObject(mDataObject, anItem,
|
||||
nullptr, aTransferable);
|
||||
else
|
||||
NS_WARNING("Reqesting non-zero index, but clipboard data is not a collection!");
|
||||
}
|
||||
}
|
||||
return dataFound;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsDragService::SetIDataObject(IDataObject * aDataObj)
|
||||
{
|
||||
// When the native drag starts the DragService gets
|
||||
// the IDataObject that is being dragged
|
||||
NS_IF_RELEASE(mDataObject);
|
||||
mDataObject = aDataObj;
|
||||
NS_IF_ADDREF(mDataObject);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void
|
||||
nsDragService::SetDroppedLocal()
|
||||
{
|
||||
// Sent from the native drag handler, letting us know
|
||||
// a drop occurred within the application vs. outside of it.
|
||||
mSentLocalDropEvent = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsDragService::IsDataFlavorSupported(const char *aDataFlavor, bool *_retval)
|
||||
{
|
||||
if (!aDataFlavor || !mDataObject || !_retval)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (strcmp(aDataFlavor, kTextMime) == 0)
|
||||
NS_WARNING("DO NOT USE THE text/plain DATA FLAVOR ANY MORE. USE text/unicode INSTEAD");
|
||||
#endif
|
||||
|
||||
*_retval = false;
|
||||
|
||||
FORMATETC fe;
|
||||
UINT format = 0;
|
||||
|
||||
if (IsCollectionObject(mDataObject)) {
|
||||
// We know we have one of our special collection objects.
|
||||
format = nsClipboard::GetFormat(aDataFlavor);
|
||||
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
|
||||
TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
|
||||
|
||||
// See if any one of the IDataObjects in the collection supports
|
||||
// this data type
|
||||
nsDataObjCollection* dataObjCol = GetDataObjCollection(mDataObject);
|
||||
if (dataObjCol) {
|
||||
uint32_t cnt = dataObjCol->GetNumDataObjects();
|
||||
for (uint32_t i=0;i<cnt;++i) {
|
||||
IDataObject * dataObj = dataObjCol->GetDataObjectAt(i);
|
||||
if (S_OK == dataObj->QueryGetData(&fe))
|
||||
*_retval = true; // found it!
|
||||
}
|
||||
}
|
||||
} // if special collection object
|
||||
else {
|
||||
// Ok, so we have a single object. Check to see if has the correct
|
||||
// data type. Since this can come from an outside app, we also
|
||||
// need to see if we need to perform text->unicode conversion if
|
||||
// the client asked for unicode and it wasn't available.
|
||||
format = nsClipboard::GetFormat(aDataFlavor);
|
||||
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
|
||||
TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
|
||||
if (mDataObject->QueryGetData(&fe) == S_OK)
|
||||
*_retval = true; // found it!
|
||||
else {
|
||||
// We haven't found the exact flavor the client asked for, but
|
||||
// maybe we can still find it from something else that's on the
|
||||
// clipboard
|
||||
if (strcmp(aDataFlavor, kUnicodeMime) == 0) {
|
||||
// client asked for unicode and it wasn't present, check if we
|
||||
// have CF_TEXT. We'll handle the actual data substitution in
|
||||
// the data object.
|
||||
format = nsClipboard::GetFormat(kTextMime);
|
||||
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
|
||||
TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
|
||||
if (mDataObject->QueryGetData(&fe) == S_OK)
|
||||
*_retval = true; // found it!
|
||||
}
|
||||
else if (strcmp(aDataFlavor, kURLMime) == 0) {
|
||||
// client asked for a url and it wasn't present, but if we
|
||||
// have a file, then we have a URL to give them (the path, or
|
||||
// the internal URL if an InternetShortcut).
|
||||
format = nsClipboard::GetFormat(kFileMime);
|
||||
SET_FORMATETC(fe, format, 0, DVASPECT_CONTENT, -1,
|
||||
TYMED_HGLOBAL | TYMED_FILE | TYMED_GDI);
|
||||
if (mDataObject->QueryGetData(&fe) == S_OK)
|
||||
*_retval = true; // found it!
|
||||
}
|
||||
} // else try again
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// IsCollectionObject
|
||||
//
|
||||
// Determine if this is a single |IDataObject| or one of our private
|
||||
// collection objects. We know the difference because our collection
|
||||
// object will respond to supporting the private |MULTI_MIME| format.
|
||||
//
|
||||
bool
|
||||
nsDragService::IsCollectionObject(IDataObject* inDataObj)
|
||||
{
|
||||
bool isCollection = false;
|
||||
|
||||
// setup the format object to ask for the MULTI_MIME format. We only
|
||||
// need to do this once
|
||||
static UINT sFormat = 0;
|
||||
static FORMATETC sFE;
|
||||
if (!sFormat) {
|
||||
sFormat = nsClipboard::GetFormat(MULTI_MIME);
|
||||
SET_FORMATETC(sFE, sFormat, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL);
|
||||
}
|
||||
|
||||
// ask the object if it supports it. If yes, we have a collection
|
||||
// object
|
||||
if (inDataObj->QueryGetData(&sFE) == S_OK)
|
||||
isCollection = true;
|
||||
|
||||
return isCollection;
|
||||
|
||||
} // IsCollectionObject
|
||||
|
||||
|
||||
//
|
||||
// EndDragSession
|
||||
//
|
||||
// Override the default to make sure that we release the data object
|
||||
// when the drag ends. It seems that OLE doesn't like to let apps quit
|
||||
// w/out crashing when we're still holding onto their data
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsDragService::EndDragSession(bool aDoneDrag)
|
||||
{
|
||||
// Bug 100180: If we've got mouse events captured, make sure we release it -
|
||||
// that way, if we happen to call EndDragSession before diving into a nested
|
||||
// event loop, we can still respond to mouse events.
|
||||
if (::GetCapture()) {
|
||||
::ReleaseCapture();
|
||||
}
|
||||
|
||||
nsBaseDragService::EndDragSession(aDoneDrag);
|
||||
NS_IF_RELEASE(mDataObject);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
61
widget/windows/nsDragService.h
Normal file
61
widget/windows/nsDragService.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsDragService_h__
|
||||
#define nsDragService_h__
|
||||
|
||||
#include "nsBaseDragService.h"
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
struct IDataObject;
|
||||
class nsDataObjCollection;
|
||||
|
||||
/**
|
||||
* Native Win32 DragService wrapper
|
||||
*/
|
||||
|
||||
class nsDragService : public nsBaseDragService
|
||||
{
|
||||
public:
|
||||
nsDragService();
|
||||
virtual ~nsDragService();
|
||||
|
||||
// nsBaseDragService
|
||||
virtual nsresult InvokeDragSessionImpl(nsIArray* anArrayTransferables,
|
||||
nsIScriptableRegion* aRegion,
|
||||
uint32_t aActionType);
|
||||
|
||||
// nsIDragSession
|
||||
NS_IMETHOD GetData(nsITransferable * aTransferable, uint32_t anItem);
|
||||
NS_IMETHOD GetNumDropItems(uint32_t * aNumItems);
|
||||
NS_IMETHOD IsDataFlavorSupported(const char *aDataFlavor, bool *_retval);
|
||||
NS_IMETHOD EndDragSession(bool aDoneDrag);
|
||||
|
||||
// native impl.
|
||||
NS_IMETHOD SetIDataObject(IDataObject * aDataObj);
|
||||
NS_IMETHOD StartInvokingDragSession(IDataObject * aDataObj,
|
||||
uint32_t aActionType);
|
||||
|
||||
// A drop occurred within the application vs. outside of it.
|
||||
void SetDroppedLocal();
|
||||
|
||||
protected:
|
||||
nsDataObjCollection* GetDataObjCollection(IDataObject * aDataObj);
|
||||
|
||||
// determine if we have a single data object or one of our private
|
||||
// collections
|
||||
bool IsCollectionObject(IDataObject* inDataObj);
|
||||
|
||||
// Create a bitmap for drag operations
|
||||
bool CreateDragImage(nsIDOMNode *aDOMNode,
|
||||
nsIScriptableRegion *aRegion,
|
||||
SHDRAGIMAGE *psdi);
|
||||
|
||||
IDataObject * mDataObject;
|
||||
bool mSentLocalDropEvent;
|
||||
};
|
||||
|
||||
#endif // nsDragService_h__
|
||||
1383
widget/windows/nsFilePicker.cpp
Normal file
1383
widget/windows/nsFilePicker.cpp
Normal file
File diff suppressed because it is too large
Load diff
164
widget/windows/nsFilePicker.h
Normal file
164
widget/windows/nsFilePicker.h
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsFilePicker_h__
|
||||
#define nsFilePicker_h__
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// For Vista IFileDialog interfaces which aren't exposed
|
||||
// unless _WIN32_WINNT >= _WIN32_WINNT_LONGHORN.
|
||||
#if _WIN32_WINNT < _WIN32_WINNT_LONGHORN
|
||||
#define _WIN32_WINNT_bak _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_LONGHORN
|
||||
#define _WIN32_IE_bak _WIN32_IE
|
||||
#undef _WIN32_IE
|
||||
#define _WIN32_IE _WIN32_IE_IE70
|
||||
#endif
|
||||
|
||||
#include "nsIFile.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsBaseFilePicker.h"
|
||||
#include "nsString.h"
|
||||
#include "nsdefs.h"
|
||||
#include <commdlg.h>
|
||||
#include <shobjidl.h>
|
||||
#undef LogSeverity // SetupAPI.h #defines this as DWORD
|
||||
|
||||
class nsILoadContext;
|
||||
|
||||
class nsBaseWinFilePicker :
|
||||
public nsBaseFilePicker
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD GetDefaultString(nsAString& aDefaultString);
|
||||
NS_IMETHOD SetDefaultString(const nsAString& aDefaultString);
|
||||
NS_IMETHOD GetDefaultExtension(nsAString& aDefaultExtension);
|
||||
NS_IMETHOD SetDefaultExtension(const nsAString& aDefaultExtension);
|
||||
|
||||
protected:
|
||||
nsString mDefaultFilePath;
|
||||
nsString mDefaultFilename;
|
||||
nsString mDefaultExtension;
|
||||
};
|
||||
|
||||
/**
|
||||
* Native Windows FileSelector wrapper
|
||||
*/
|
||||
|
||||
class nsFilePicker :
|
||||
public IFileDialogEvents,
|
||||
public nsBaseWinFilePicker
|
||||
{
|
||||
virtual ~nsFilePicker();
|
||||
public:
|
||||
nsFilePicker();
|
||||
|
||||
NS_IMETHOD Init(mozIDOMWindowProxy *aParent, const nsAString& aTitle, int16_t aMode);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// IUnknown's QueryInterface
|
||||
STDMETHODIMP QueryInterface(REFIID refiid, void** ppvResult);
|
||||
|
||||
// nsIFilePicker (less what's in nsBaseFilePicker and nsBaseWinFilePicker)
|
||||
NS_IMETHOD GetFilterIndex(int32_t *aFilterIndex);
|
||||
NS_IMETHOD SetFilterIndex(int32_t aFilterIndex);
|
||||
NS_IMETHOD GetFile(nsIFile * *aFile);
|
||||
NS_IMETHOD GetFileURL(nsIURI * *aFileURL);
|
||||
NS_IMETHOD GetFiles(nsISimpleEnumerator **aFiles);
|
||||
NS_IMETHOD Show(int16_t *aReturnVal);
|
||||
NS_IMETHOD ShowW(int16_t *aReturnVal);
|
||||
NS_IMETHOD AppendFilter(const nsAString& aTitle, const nsAString& aFilter);
|
||||
|
||||
// IFileDialogEvents
|
||||
HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog *pfd);
|
||||
HRESULT STDMETHODCALLTYPE OnFolderChanging(IFileDialog *pfd, IShellItem *psiFolder);
|
||||
HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialog *pfd);
|
||||
HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialog *pfd);
|
||||
HRESULT STDMETHODCALLTYPE OnShareViolation(IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse);
|
||||
HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialog *pfd);
|
||||
HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse);
|
||||
|
||||
protected:
|
||||
enum PickerType {
|
||||
PICKER_TYPE_OPEN,
|
||||
PICKER_TYPE_SAVE,
|
||||
};
|
||||
|
||||
/* method from nsBaseFilePicker */
|
||||
virtual void InitNative(nsIWidget *aParent,
|
||||
const nsAString& aTitle);
|
||||
static void GetQualifiedPath(const wchar_t *aInPath, nsString &aOutPath);
|
||||
void GetFilterListArray(nsString& aFilterList);
|
||||
static bool GetFileNameWrapper(OPENFILENAMEW* ofn, PickerType aType);
|
||||
bool FilePickerWrapper(OPENFILENAMEW* ofn, PickerType aType);
|
||||
bool ShowXPFolderPicker(const nsString& aInitialDir);
|
||||
bool ShowXPFilePicker(const nsString& aInitialDir);
|
||||
bool ShowFolderPicker(const nsString& aInitialDir, bool &aWasInitError);
|
||||
bool ShowFilePicker(const nsString& aInitialDir, bool &aWasInitError);
|
||||
void AppendXPFilter(const nsAString& aTitle, const nsAString& aFilter);
|
||||
void RememberLastUsedDirectory();
|
||||
bool IsPrivacyModeEnabled();
|
||||
bool IsDefaultPathLink();
|
||||
bool IsDefaultPathHtml();
|
||||
void SetDialogHandle(HWND aWnd);
|
||||
bool ClosePickerIfNeeded(bool aIsXPDialog);
|
||||
static void PickerCallbackTimerFunc(nsITimer *aTimer, void *aPicker);
|
||||
static UINT_PTR CALLBACK MultiFilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
static UINT_PTR CALLBACK FilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
nsCOMPtr<nsILoadContext> mLoadContext;
|
||||
nsCOMPtr<nsIWidget> mParentWidget;
|
||||
nsString mTitle;
|
||||
nsCString mFile;
|
||||
nsString mFilterList;
|
||||
int16_t mSelectedType;
|
||||
nsCOMArray<nsIFile> mFiles;
|
||||
static char mLastUsedDirectory[];
|
||||
nsString mUnicodeFile;
|
||||
static char16_t *mLastUsedUnicodeDirectory;
|
||||
HWND mDlgWnd;
|
||||
|
||||
class ComDlgFilterSpec
|
||||
{
|
||||
public:
|
||||
ComDlgFilterSpec() {}
|
||||
~ComDlgFilterSpec() {}
|
||||
|
||||
const uint32_t Length() {
|
||||
return mSpecList.Length();
|
||||
}
|
||||
|
||||
const bool IsEmpty() {
|
||||
return (mSpecList.Length() == 0);
|
||||
}
|
||||
|
||||
const COMDLG_FILTERSPEC* get() {
|
||||
return mSpecList.Elements();
|
||||
}
|
||||
|
||||
void Append(const nsAString& aTitle, const nsAString& aFilter);
|
||||
private:
|
||||
AutoTArray<COMDLG_FILTERSPEC, 1> mSpecList;
|
||||
AutoTArray<nsString, 2> mStrings;
|
||||
};
|
||||
|
||||
ComDlgFilterSpec mComFilterList;
|
||||
DWORD mFDECookie;
|
||||
};
|
||||
|
||||
#if defined(_WIN32_WINNT_bak)
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_bak
|
||||
#undef _WIN32_IE
|
||||
#define _WIN32_IE _WIN32_IE_bak
|
||||
#endif
|
||||
|
||||
#endif // nsFilePicker_h__
|
||||
30
widget/windows/nsIdleServiceWin.cpp
Normal file
30
widget/windows/nsIdleServiceWin.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||
*/
|
||||
/* 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 "nsIdleServiceWin.h"
|
||||
#include <windows.h>
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(nsIdleServiceWin, nsIdleService)
|
||||
|
||||
bool
|
||||
nsIdleServiceWin::PollIdleTime(uint32_t *aIdleTime)
|
||||
{
|
||||
LASTINPUTINFO inputInfo;
|
||||
inputInfo.cbSize = sizeof(inputInfo);
|
||||
if (!::GetLastInputInfo(&inputInfo))
|
||||
return false;
|
||||
|
||||
*aIdleTime = SAFE_COMPARE_EVEN_WITH_WRAPPING(GetTickCount(), inputInfo.dwTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsIdleServiceWin::UsePollMode()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
46
widget/windows/nsIdleServiceWin.h
Normal file
46
widget/windows/nsIdleServiceWin.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
||||
*/
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsIdleServiceWin_h__
|
||||
#define nsIdleServiceWin_h__
|
||||
|
||||
#include "nsIdleService.h"
|
||||
|
||||
|
||||
/* NOTE: Compare of GetTickCount() could overflow. This corrects for
|
||||
* overflow situations.
|
||||
***/
|
||||
#ifndef SAFE_COMPARE_EVEN_WITH_WRAPPING
|
||||
#define SAFE_COMPARE_EVEN_WITH_WRAPPING(A, B) (((int)((long)A - (long)B) & 0xFFFFFFFF))
|
||||
#endif
|
||||
|
||||
|
||||
class nsIdleServiceWin : public nsIdleService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
bool PollIdleTime(uint32_t* aIdleTime) override;
|
||||
|
||||
static already_AddRefed<nsIdleServiceWin> GetInstance()
|
||||
{
|
||||
RefPtr<nsIdleServiceWin> idleService =
|
||||
nsIdleService::GetInstance().downcast<nsIdleServiceWin>();
|
||||
if (!idleService) {
|
||||
idleService = new nsIdleServiceWin();
|
||||
}
|
||||
|
||||
return idleService.forget();
|
||||
}
|
||||
|
||||
protected:
|
||||
nsIdleServiceWin() { }
|
||||
virtual ~nsIdleServiceWin() { }
|
||||
bool UsePollMode() override;
|
||||
};
|
||||
|
||||
#endif // nsIdleServiceWin_h__
|
||||
497
widget/windows/nsImageClipboard.cpp
Normal file
497
widget/windows/nsImageClipboard.cpp
Normal file
|
|
@ -0,0 +1,497 @@
|
|||
/* -*- Mode: C++; tab-width: 8; 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 "nsImageClipboard.h"
|
||||
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsGfxCIID.h"
|
||||
#include "nsMemory.h"
|
||||
#include "prmem.h"
|
||||
#include "imgIEncoder.h"
|
||||
#include "nsLiteralString.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
#define BFH_LENGTH 14
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
/* Things To Do 11/8/00
|
||||
|
||||
Check image metrics, can we support them? Do we need to?
|
||||
Any other render format? HTML?
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// nsImageToClipboard ctor
|
||||
//
|
||||
// Given an imgIContainer, convert it to a DIB that is ready to go on the win32 clipboard
|
||||
//
|
||||
nsImageToClipboard::nsImageToClipboard(imgIContainer* aInImage, bool aWantDIBV5)
|
||||
: mImage(aInImage)
|
||||
, mWantDIBV5(aWantDIBV5)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// nsImageToClipboard dtor
|
||||
//
|
||||
// Clean up after ourselves. We know that we have created the bitmap
|
||||
// successfully if we still have a pointer to the header.
|
||||
//
|
||||
nsImageToClipboard::~nsImageToClipboard()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GetPicture
|
||||
//
|
||||
// Call to get the actual bits that go on the clipboard. If an error
|
||||
// ocurred during conversion, |outBits| will be null.
|
||||
//
|
||||
// NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
|
||||
//
|
||||
nsresult
|
||||
nsImageToClipboard :: GetPicture ( HANDLE* outBits )
|
||||
{
|
||||
NS_ASSERTION ( outBits, "Bad parameter" );
|
||||
|
||||
return CreateFromImage ( mImage, outBits );
|
||||
|
||||
} // GetPicture
|
||||
|
||||
|
||||
//
|
||||
// CalcSize
|
||||
//
|
||||
// Computes # of bytes needed by a bitmap with the specified attributes.
|
||||
//
|
||||
int32_t
|
||||
nsImageToClipboard :: CalcSize ( int32_t aHeight, int32_t aColors, WORD aBitsPerPixel, int32_t aSpanBytes )
|
||||
{
|
||||
int32_t HeaderMem = sizeof(BITMAPINFOHEADER);
|
||||
|
||||
// add size of pallette to header size
|
||||
if (aBitsPerPixel < 16)
|
||||
HeaderMem += aColors * sizeof(RGBQUAD);
|
||||
|
||||
if (aHeight < 0)
|
||||
aHeight = -aHeight;
|
||||
|
||||
return (HeaderMem + (aHeight * aSpanBytes));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CalcSpanLength
|
||||
//
|
||||
// Computes the span bytes for determining the overall size of the image
|
||||
//
|
||||
int32_t
|
||||
nsImageToClipboard::CalcSpanLength(uint32_t aWidth, uint32_t aBitCount)
|
||||
{
|
||||
int32_t spanBytes = (aWidth * aBitCount) >> 5;
|
||||
|
||||
if ((aWidth * aBitCount) & 0x1F)
|
||||
spanBytes++;
|
||||
spanBytes <<= 2;
|
||||
|
||||
return spanBytes;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CreateFromImage
|
||||
//
|
||||
// Do the work to setup the bitmap header and copy the bits out of the
|
||||
// image.
|
||||
//
|
||||
nsresult
|
||||
nsImageToClipboard::CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap )
|
||||
{
|
||||
nsresult rv;
|
||||
*outBitmap = nullptr;
|
||||
|
||||
RefPtr<SourceSurface> surface =
|
||||
inImage->GetFrame(imgIContainer::FRAME_CURRENT,
|
||||
imgIContainer::FLAG_SYNC_DECODE);
|
||||
NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
|
||||
|
||||
MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
|
||||
surface->GetFormat() == SurfaceFormat::B8G8R8X8);
|
||||
|
||||
RefPtr<DataSourceSurface> dataSurface;
|
||||
if (surface->GetFormat() == SurfaceFormat::B8G8R8A8) {
|
||||
dataSurface = surface->GetDataSurface();
|
||||
} else {
|
||||
// XXXjwatt Bug 995923 - get rid of this copy and handle B8G8R8X8
|
||||
// directly below once bug 995807 is fixed.
|
||||
dataSurface = gfxUtils::
|
||||
CopySurfaceToDataSourceSurfaceWithFormat(surface,
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
}
|
||||
NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/bmp", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t format;
|
||||
nsAutoString options;
|
||||
if (mWantDIBV5) {
|
||||
options.AppendLiteral("version=5;bpp=");
|
||||
} else {
|
||||
options.AppendLiteral("version=3;bpp=");
|
||||
}
|
||||
switch (dataSurface->GetFormat()) {
|
||||
case SurfaceFormat::B8G8R8A8:
|
||||
format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
|
||||
options.AppendInt(32);
|
||||
break;
|
||||
#if 0
|
||||
// XXXjwatt Bug 995923 - fix |format| and reenable once bug 995807 is fixed.
|
||||
case SurfaceFormat::B8G8R8X8:
|
||||
format = imgIEncoder::INPUT_FORMAT_RGB;
|
||||
options.AppendInt(24);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
NS_NOTREACHED("Unexpected surface format");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
bool mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map);
|
||||
NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE);
|
||||
|
||||
rv = encoder->InitFromData(map.mData, 0,
|
||||
dataSurface->GetSize().width,
|
||||
dataSurface->GetSize().height,
|
||||
map.mStride,
|
||||
format, options);
|
||||
dataSurface->Unmap();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t size;
|
||||
encoder->GetImageBufferUsed(&size);
|
||||
NS_ENSURE_TRUE(size > BFH_LENGTH, NS_ERROR_FAILURE);
|
||||
HGLOBAL glob = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT,
|
||||
size - BFH_LENGTH);
|
||||
if (!glob)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
char *dst = (char*) ::GlobalLock(glob);
|
||||
char *src;
|
||||
rv = encoder->GetImageBuffer(&src);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
::CopyMemory(dst, src + BFH_LENGTH, size - BFH_LENGTH);
|
||||
::GlobalUnlock(glob);
|
||||
|
||||
*outBitmap = (HANDLE)glob;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsImageFromClipboard :: nsImageFromClipboard ()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
nsImageFromClipboard :: ~nsImageFromClipboard ( )
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// GetEncodedImageStream
|
||||
//
|
||||
// Take the raw clipboard image data and convert it to aMIMEFormat in the form of a nsIInputStream
|
||||
//
|
||||
nsresult
|
||||
nsImageFromClipboard ::GetEncodedImageStream (unsigned char * aClipboardData, const char * aMIMEFormat, nsIInputStream** aInputStream )
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER (aInputStream);
|
||||
NS_ENSURE_ARG_POINTER (aMIMEFormat);
|
||||
nsresult rv;
|
||||
*aInputStream = nullptr;
|
||||
|
||||
// pull the size information out of the BITMAPINFO header and
|
||||
// initialize the image
|
||||
BITMAPINFO* header = (BITMAPINFO *) aClipboardData;
|
||||
int32_t width = header->bmiHeader.biWidth;
|
||||
int32_t height = header->bmiHeader.biHeight;
|
||||
// neg. heights mean the Y axis is inverted and we don't handle that case
|
||||
NS_ENSURE_TRUE(height > 0, NS_ERROR_FAILURE);
|
||||
|
||||
unsigned char * rgbData = new unsigned char[width * height * 3 /* RGB */];
|
||||
|
||||
if (rgbData) {
|
||||
BYTE * pGlobal = (BYTE *) aClipboardData;
|
||||
// Convert the clipboard image into RGB packed pixel data
|
||||
rv = ConvertColorBitMap((unsigned char *) (pGlobal + header->bmiHeader.biSize), header, rgbData);
|
||||
// if that succeeded, encode the bitmap as aMIMEFormat data. Don't return early or we risk leaking rgbData
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoCString encoderCID(NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type="));
|
||||
|
||||
// Map image/jpg to image/jpeg (which is how the encoder is registered).
|
||||
if (strcmp(aMIMEFormat, kJPGImageMime) == 0)
|
||||
encoderCID.AppendLiteral("image/jpeg");
|
||||
else
|
||||
encoderCID.Append(aMIMEFormat);
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get(), &rv);
|
||||
if (NS_SUCCEEDED(rv)){
|
||||
rv = encoder->InitFromData(rgbData, 0, width, height, 3 * width /* RGB * # pixels in a row */,
|
||||
imgIEncoder::INPUT_FORMAT_RGB, EmptyString());
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
encoder.forget(aInputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete [] rgbData;
|
||||
}
|
||||
else
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return rv;
|
||||
} // GetImage
|
||||
|
||||
//
|
||||
// InvertRows
|
||||
//
|
||||
// Take the image data from the clipboard and invert the rows. Modifying aInitialBuffer in place.
|
||||
//
|
||||
void
|
||||
nsImageFromClipboard::InvertRows(unsigned char * aInitialBuffer, uint32_t aSizeOfBuffer, uint32_t aNumBytesPerRow)
|
||||
{
|
||||
if (!aNumBytesPerRow)
|
||||
return;
|
||||
|
||||
uint32_t numRows = aSizeOfBuffer / aNumBytesPerRow;
|
||||
unsigned char * row = new unsigned char[aNumBytesPerRow];
|
||||
|
||||
uint32_t currentRow = 0;
|
||||
uint32_t lastRow = (numRows - 1) * aNumBytesPerRow;
|
||||
while (currentRow < lastRow)
|
||||
{
|
||||
// store the current row into a temporary buffer
|
||||
memcpy(row, &aInitialBuffer[currentRow], aNumBytesPerRow);
|
||||
memcpy(&aInitialBuffer[currentRow], &aInitialBuffer[lastRow], aNumBytesPerRow);
|
||||
memcpy(&aInitialBuffer[lastRow], row, aNumBytesPerRow);
|
||||
lastRow -= aNumBytesPerRow;
|
||||
currentRow += aNumBytesPerRow;
|
||||
}
|
||||
|
||||
delete[] row;
|
||||
}
|
||||
|
||||
//
|
||||
// ConvertColorBitMap
|
||||
//
|
||||
// Takes the clipboard bitmap and converts it into a RGB packed pixel values.
|
||||
//
|
||||
nsresult
|
||||
nsImageFromClipboard::ConvertColorBitMap(unsigned char * aInputBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutBuffer)
|
||||
{
|
||||
uint8_t bitCount = pBitMapInfo->bmiHeader.biBitCount;
|
||||
uint32_t imageSize = pBitMapInfo->bmiHeader.biSizeImage; // may be zero for BI_RGB bitmaps which means we need to calculate by hand
|
||||
uint32_t bytesPerPixel = bitCount / 8;
|
||||
|
||||
if (bitCount <= 4)
|
||||
bytesPerPixel = 1;
|
||||
|
||||
// rows are DWORD aligned. Calculate how many real bytes are in each row in the bitmap. This number won't
|
||||
// correspond to biWidth.
|
||||
uint32_t rowSize = (bitCount * pBitMapInfo->bmiHeader.biWidth + 7) / 8; // +7 to round up
|
||||
if (rowSize % 4)
|
||||
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
|
||||
|
||||
// if our buffer includes a color map, skip over it
|
||||
if (bitCount <= 8)
|
||||
{
|
||||
int32_t bytesToSkip = (pBitMapInfo->bmiHeader.biClrUsed ? pBitMapInfo->bmiHeader.biClrUsed : (1 << bitCount) ) * sizeof(RGBQUAD);
|
||||
aInputBuffer += bytesToSkip;
|
||||
}
|
||||
|
||||
bitFields colorMasks; // only used if biCompression == BI_BITFIELDS
|
||||
|
||||
if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
|
||||
{
|
||||
// color table consists of 3 DWORDS containing the color masks...
|
||||
colorMasks.red = (*((uint32_t*)&(pBitMapInfo->bmiColors[0])));
|
||||
colorMasks.green = (*((uint32_t*)&(pBitMapInfo->bmiColors[1])));
|
||||
colorMasks.blue = (*((uint32_t*)&(pBitMapInfo->bmiColors[2])));
|
||||
CalcBitShift(&colorMasks);
|
||||
aInputBuffer += 3 * sizeof(DWORD);
|
||||
}
|
||||
else if (pBitMapInfo->bmiHeader.biCompression == BI_RGB && !imageSize) // BI_RGB can have a size of zero which means we figure it out
|
||||
{
|
||||
// XXX: note use rowSize here and not biWidth. rowSize accounts for the DWORD padding for each row
|
||||
imageSize = rowSize * pBitMapInfo->bmiHeader.biHeight;
|
||||
}
|
||||
|
||||
// The windows clipboard image format inverts the rows
|
||||
InvertRows(aInputBuffer, imageSize, rowSize);
|
||||
|
||||
if (!pBitMapInfo->bmiHeader.biCompression || pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
|
||||
{
|
||||
uint32_t index = 0;
|
||||
uint32_t writeIndex = 0;
|
||||
|
||||
unsigned char redValue, greenValue, blueValue;
|
||||
uint8_t colorTableEntry = 0;
|
||||
int8_t bit; // used for grayscale bitmaps where each bit is a pixel
|
||||
uint32_t numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth; // how many more pixels do we still need to read for the current row
|
||||
uint32_t pos = 0;
|
||||
|
||||
while (index < imageSize)
|
||||
{
|
||||
switch (bitCount)
|
||||
{
|
||||
case 1:
|
||||
for (bit = 7; bit >= 0 && numPixelsLeftInRow; bit--)
|
||||
{
|
||||
colorTableEntry = (aInputBuffer[index] >> bit) & 1;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
|
||||
numPixelsLeftInRow--;
|
||||
}
|
||||
pos += 1;
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
// each aInputBuffer[index] entry contains data for two pixels.
|
||||
// read the first pixel
|
||||
colorTableEntry = aInputBuffer[index] >> 4;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
|
||||
numPixelsLeftInRow--;
|
||||
|
||||
if (numPixelsLeftInRow) // now read the second pixel
|
||||
{
|
||||
colorTableEntry = aInputBuffer[index] & 0xF;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
|
||||
numPixelsLeftInRow--;
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbRed;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbGreen;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbBlue;
|
||||
numPixelsLeftInRow--;
|
||||
pos += 1;
|
||||
break;
|
||||
case 16:
|
||||
{
|
||||
uint16_t num = 0;
|
||||
num = (uint8_t) aInputBuffer[index+1];
|
||||
num <<= 8;
|
||||
num |= (uint8_t) aInputBuffer[index];
|
||||
|
||||
redValue = ((uint32_t) (((float)(num & 0xf800) / 0xf800) * 0xFF0000) & 0xFF0000)>> 16;
|
||||
greenValue = ((uint32_t)(((float)(num & 0x07E0) / 0x07E0) * 0x00FF00) & 0x00FF00)>> 8;
|
||||
blueValue = ((uint32_t)(((float)(num & 0x001F) / 0x001F) * 0x0000FF) & 0x0000FF);
|
||||
|
||||
// now we have the right RGB values...
|
||||
aOutBuffer[writeIndex++] = redValue;
|
||||
aOutBuffer[writeIndex++] = greenValue;
|
||||
aOutBuffer[writeIndex++] = blueValue;
|
||||
numPixelsLeftInRow--;
|
||||
pos += 2;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
case 24:
|
||||
if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
|
||||
{
|
||||
uint32_t val = *((uint32_t*) (aInputBuffer + index) );
|
||||
aOutBuffer[writeIndex++] = (val & colorMasks.red) >> colorMasks.redRightShift << colorMasks.redLeftShift;
|
||||
aOutBuffer[writeIndex++] = (val & colorMasks.green) >> colorMasks.greenRightShift << colorMasks.greenLeftShift;
|
||||
aOutBuffer[writeIndex++] = (val & colorMasks.blue) >> colorMasks.blueRightShift << colorMasks.blueLeftShift;
|
||||
numPixelsLeftInRow--;
|
||||
pos += 4; // we read in 4 bytes of data in order to process this pixel
|
||||
}
|
||||
else
|
||||
{
|
||||
aOutBuffer[writeIndex++] = aInputBuffer[index+2];
|
||||
aOutBuffer[writeIndex++] = aInputBuffer[index+1];
|
||||
aOutBuffer[writeIndex++] = aInputBuffer[index];
|
||||
numPixelsLeftInRow--;
|
||||
pos += bytesPerPixel; // 3 bytes for 24 bit data, 4 bytes for 32 bit data (we skip over the 4th byte)...
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// This is probably the wrong place to check this...
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
index += bytesPerPixel; // increment our loop counter
|
||||
|
||||
if (!numPixelsLeftInRow)
|
||||
{
|
||||
if (rowSize != pos)
|
||||
{
|
||||
// advance index to skip over remaining padding bytes
|
||||
index += (rowSize - pos);
|
||||
}
|
||||
numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
} // while we still have bytes to process
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsImageFromClipboard::CalcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength)
|
||||
{
|
||||
// find the rightmost 1
|
||||
uint8_t pos;
|
||||
bool started = false;
|
||||
aBegin = aLength = 0;
|
||||
for (pos = 0; pos <= 31; pos++)
|
||||
{
|
||||
if (!started && (aMask & (1 << pos)))
|
||||
{
|
||||
aBegin = pos;
|
||||
started = true;
|
||||
}
|
||||
else if (started && !(aMask & (1 << pos)))
|
||||
{
|
||||
aLength = pos - aBegin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsImageFromClipboard::CalcBitShift(bitFields * aColorMask)
|
||||
{
|
||||
uint8_t begin, length;
|
||||
// red
|
||||
CalcBitmask(aColorMask->red, begin, length);
|
||||
aColorMask->redRightShift = begin;
|
||||
aColorMask->redLeftShift = 8 - length;
|
||||
// green
|
||||
CalcBitmask(aColorMask->green, begin, length);
|
||||
aColorMask->greenRightShift = begin;
|
||||
aColorMask->greenLeftShift = 8 - length;
|
||||
// blue
|
||||
CalcBitmask(aColorMask->blue, begin, length);
|
||||
aColorMask->blueRightShift = begin;
|
||||
aColorMask->blueLeftShift = 8 - length;
|
||||
}
|
||||
93
widget/windows/nsImageClipboard.h
Normal file
93
widget/windows/nsImageClipboard.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef nsImageClipboard_h
|
||||
#define nsImageClipboard_h
|
||||
|
||||
/* Things To Do 11/8/00
|
||||
|
||||
Check image metrics, can we support them? Do we need to?
|
||||
Any other render format? HTML?
|
||||
|
||||
*/
|
||||
|
||||
#include "nsError.h"
|
||||
#include <windows.h>
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
|
||||
//
|
||||
// nsImageToClipboard
|
||||
//
|
||||
// A utility class that takes an imgIContainer and does all the bitmap magic
|
||||
// to allow us to put it on the clipboard
|
||||
//
|
||||
class nsImageToClipboard
|
||||
{
|
||||
public:
|
||||
nsImageToClipboard(imgIContainer* aInImage, bool aWantDIBV5 = true);
|
||||
~nsImageToClipboard();
|
||||
|
||||
// Call to get the actual bits that go on the clipboard. If |nullptr|, the
|
||||
// setup operations have failed.
|
||||
//
|
||||
// NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
|
||||
nsresult GetPicture ( HANDLE* outBits ) ;
|
||||
|
||||
private:
|
||||
|
||||
// Computes # of bytes needed by a bitmap with the specified attributes.
|
||||
int32_t CalcSize(int32_t aHeight, int32_t aColors, WORD aBitsPerPixel, int32_t aSpanBytes);
|
||||
int32_t CalcSpanLength(uint32_t aWidth, uint32_t aBitCount);
|
||||
|
||||
// Do the work
|
||||
nsresult CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap );
|
||||
|
||||
nsCOMPtr<imgIContainer> mImage; // the image we're working with
|
||||
bool mWantDIBV5;
|
||||
|
||||
}; // class nsImageToClipboard
|
||||
|
||||
|
||||
struct bitFields {
|
||||
uint32_t red;
|
||||
uint32_t green;
|
||||
uint32_t blue;
|
||||
uint8_t redLeftShift;
|
||||
uint8_t redRightShift;
|
||||
uint8_t greenLeftShift;
|
||||
uint8_t greenRightShift;
|
||||
uint8_t blueLeftShift;
|
||||
uint8_t blueRightShift;
|
||||
};
|
||||
|
||||
//
|
||||
// nsImageFromClipboard
|
||||
//
|
||||
// A utility class that takes a DIB from the win32 clipboard and does
|
||||
// all the bitmap magic to convert it to a PNG or a JPEG in the form of a nsIInputStream
|
||||
//
|
||||
class nsImageFromClipboard
|
||||
{
|
||||
public:
|
||||
nsImageFromClipboard () ;
|
||||
~nsImageFromClipboard ( ) ;
|
||||
|
||||
// Retrieve the newly created image
|
||||
nsresult GetEncodedImageStream (unsigned char * aClipboardData, const char * aMIMEFormat, nsIInputStream** outImage);
|
||||
|
||||
private:
|
||||
|
||||
void InvertRows(unsigned char * aInitialBuffer, uint32_t aSizeOfBuffer, uint32_t aNumBytesPerRow);
|
||||
nsresult ConvertColorBitMap(unsigned char * aInputBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutBuffer);
|
||||
void CalcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength);
|
||||
void CalcBitShift(bitFields * aColorMask);
|
||||
|
||||
}; // nsImageFromClipboard
|
||||
|
||||
#endif
|
||||
701
widget/windows/nsLookAndFeel.cpp
Normal file
701
widget/windows/nsLookAndFeel.cpp
Normal file
|
|
@ -0,0 +1,701 @@
|
|||
/* -*- 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 "nsLookAndFeel.h"
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsUXThemeData.h"
|
||||
#include "nsUXThemeConstants.h"
|
||||
#include "gfxFont.h"
|
||||
#include "WinUtils.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "gfxFontConstants.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
//static
|
||||
LookAndFeel::OperatingSystemVersion
|
||||
nsLookAndFeel::GetOperatingSystemVersion()
|
||||
{
|
||||
static OperatingSystemVersion version = eOperatingSystemVersion_Unknown;
|
||||
|
||||
if (version != eOperatingSystemVersion_Unknown) {
|
||||
return version;
|
||||
}
|
||||
|
||||
if (IsWin10OrLater()) {
|
||||
version = eOperatingSystemVersion_Windows10;
|
||||
} else if (IsWin8OrLater()) {
|
||||
version = eOperatingSystemVersion_Windows8;
|
||||
} else if (IsWin7OrLater()) {
|
||||
version = eOperatingSystemVersion_Windows7;
|
||||
} else if (IsVistaOrLater()) {
|
||||
version = eOperatingSystemVersion_WindowsVista;
|
||||
} else {
|
||||
version = eOperatingSystemVersion_WindowsXP;
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
static nsresult GetColorFromTheme(nsUXThemeClass cls,
|
||||
int32_t aPart,
|
||||
int32_t aState,
|
||||
int32_t aPropId,
|
||||
nscolor &aColor)
|
||||
{
|
||||
COLORREF color;
|
||||
HRESULT hr = GetThemeColor(nsUXThemeData::GetTheme(cls), aPart, aState, aPropId, &color);
|
||||
if (hr == S_OK)
|
||||
{
|
||||
aColor = COLOREF_2_NSRGB(color);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
static int32_t GetSystemParam(long flag, int32_t def)
|
||||
{
|
||||
DWORD value;
|
||||
return ::SystemParametersInfo(flag, 0, &value, 0) ? value : def;
|
||||
}
|
||||
|
||||
nsLookAndFeel::nsLookAndFeel()
|
||||
: nsXPLookAndFeel()
|
||||
, mUseAccessibilityTheme(0)
|
||||
{
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::TOUCH_ENABLED_DEVICE,
|
||||
WinUtils::IsTouchDeviceSupportPresent());
|
||||
}
|
||||
|
||||
nsLookAndFeel::~nsLookAndFeel()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
|
||||
int idx;
|
||||
switch (aID) {
|
||||
case eColorID_WindowBackground:
|
||||
idx = COLOR_WINDOW;
|
||||
break;
|
||||
case eColorID_WindowForeground:
|
||||
idx = COLOR_WINDOWTEXT;
|
||||
break;
|
||||
case eColorID_WidgetBackground:
|
||||
idx = COLOR_BTNFACE;
|
||||
break;
|
||||
case eColorID_WidgetForeground:
|
||||
idx = COLOR_BTNTEXT;
|
||||
break;
|
||||
case eColorID_WidgetSelectBackground:
|
||||
idx = COLOR_HIGHLIGHT;
|
||||
break;
|
||||
case eColorID_WidgetSelectForeground:
|
||||
idx = COLOR_HIGHLIGHTTEXT;
|
||||
break;
|
||||
case eColorID_Widget3DHighlight:
|
||||
idx = COLOR_BTNHIGHLIGHT;
|
||||
break;
|
||||
case eColorID_Widget3DShadow:
|
||||
idx = COLOR_BTNSHADOW;
|
||||
break;
|
||||
case eColorID_TextBackground:
|
||||
idx = COLOR_WINDOW;
|
||||
break;
|
||||
case eColorID_TextForeground:
|
||||
idx = COLOR_WINDOWTEXT;
|
||||
break;
|
||||
case eColorID_TextSelectBackground:
|
||||
case eColorID_IMESelectedRawTextBackground:
|
||||
case eColorID_IMESelectedConvertedTextBackground:
|
||||
idx = COLOR_HIGHLIGHT;
|
||||
break;
|
||||
case eColorID_TextSelectForeground:
|
||||
case eColorID_IMESelectedRawTextForeground:
|
||||
case eColorID_IMESelectedConvertedTextForeground:
|
||||
idx = COLOR_HIGHLIGHTTEXT;
|
||||
break;
|
||||
case eColorID_IMERawInputBackground:
|
||||
case eColorID_IMEConvertedTextBackground:
|
||||
aColor = NS_TRANSPARENT;
|
||||
return NS_OK;
|
||||
case eColorID_IMERawInputForeground:
|
||||
case eColorID_IMEConvertedTextForeground:
|
||||
aColor = NS_SAME_AS_FOREGROUND_COLOR;
|
||||
return NS_OK;
|
||||
case eColorID_IMERawInputUnderline:
|
||||
case eColorID_IMEConvertedTextUnderline:
|
||||
aColor = NS_SAME_AS_FOREGROUND_COLOR;
|
||||
return NS_OK;
|
||||
case eColorID_IMESelectedRawTextUnderline:
|
||||
case eColorID_IMESelectedConvertedTextUnderline:
|
||||
aColor = NS_TRANSPARENT;
|
||||
return NS_OK;
|
||||
case eColorID_SpellCheckerUnderline:
|
||||
aColor = NS_RGB(0xff, 0, 0);
|
||||
return NS_OK;
|
||||
|
||||
// New CSS 2 Color definitions
|
||||
case eColorID_activeborder:
|
||||
idx = COLOR_ACTIVEBORDER;
|
||||
break;
|
||||
case eColorID_activecaption:
|
||||
idx = COLOR_ACTIVECAPTION;
|
||||
break;
|
||||
case eColorID_appworkspace:
|
||||
idx = COLOR_APPWORKSPACE;
|
||||
break;
|
||||
case eColorID_background:
|
||||
idx = COLOR_BACKGROUND;
|
||||
break;
|
||||
case eColorID_buttonface:
|
||||
case eColorID__moz_buttonhoverface:
|
||||
idx = COLOR_BTNFACE;
|
||||
break;
|
||||
case eColorID_buttonhighlight:
|
||||
idx = COLOR_BTNHIGHLIGHT;
|
||||
break;
|
||||
case eColorID_buttonshadow:
|
||||
idx = COLOR_BTNSHADOW;
|
||||
break;
|
||||
case eColorID_buttontext:
|
||||
case eColorID__moz_buttonhovertext:
|
||||
idx = COLOR_BTNTEXT;
|
||||
break;
|
||||
case eColorID_captiontext:
|
||||
idx = COLOR_CAPTIONTEXT;
|
||||
break;
|
||||
case eColorID_graytext:
|
||||
idx = COLOR_GRAYTEXT;
|
||||
break;
|
||||
case eColorID_highlight:
|
||||
case eColorID__moz_html_cellhighlight:
|
||||
case eColorID__moz_menuhover:
|
||||
idx = COLOR_HIGHLIGHT;
|
||||
break;
|
||||
case eColorID__moz_menubarhovertext:
|
||||
if (!IsVistaOrLater() || !IsAppThemed())
|
||||
{
|
||||
idx = nsUXThemeData::sFlatMenus ?
|
||||
COLOR_HIGHLIGHTTEXT :
|
||||
COLOR_MENUTEXT;
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
case eColorID__moz_menuhovertext:
|
||||
if (IsVistaOrLater() && IsAppThemed())
|
||||
{
|
||||
res = ::GetColorFromTheme(eUXMenu,
|
||||
MENU_POPUPITEM, MPI_HOT, TMT_TEXTCOLOR, aColor);
|
||||
if (NS_SUCCEEDED(res))
|
||||
return res;
|
||||
// fall through to highlight case
|
||||
}
|
||||
case eColorID_highlighttext:
|
||||
case eColorID__moz_html_cellhighlighttext:
|
||||
idx = COLOR_HIGHLIGHTTEXT;
|
||||
break;
|
||||
case eColorID_inactiveborder:
|
||||
idx = COLOR_INACTIVEBORDER;
|
||||
break;
|
||||
case eColorID_inactivecaption:
|
||||
idx = COLOR_INACTIVECAPTION;
|
||||
break;
|
||||
case eColorID_inactivecaptiontext:
|
||||
idx = COLOR_INACTIVECAPTIONTEXT;
|
||||
break;
|
||||
case eColorID_infobackground:
|
||||
idx = COLOR_INFOBK;
|
||||
break;
|
||||
case eColorID_infotext:
|
||||
idx = COLOR_INFOTEXT;
|
||||
break;
|
||||
case eColorID_menu:
|
||||
idx = COLOR_MENU;
|
||||
break;
|
||||
case eColorID_menutext:
|
||||
case eColorID__moz_menubartext:
|
||||
idx = COLOR_MENUTEXT;
|
||||
break;
|
||||
case eColorID_scrollbar:
|
||||
idx = COLOR_SCROLLBAR;
|
||||
break;
|
||||
case eColorID_threeddarkshadow:
|
||||
idx = COLOR_3DDKSHADOW;
|
||||
break;
|
||||
case eColorID_threedface:
|
||||
idx = COLOR_3DFACE;
|
||||
break;
|
||||
case eColorID_threedhighlight:
|
||||
idx = COLOR_3DHIGHLIGHT;
|
||||
break;
|
||||
case eColorID_threedlightshadow:
|
||||
idx = COLOR_3DLIGHT;
|
||||
break;
|
||||
case eColorID_threedshadow:
|
||||
idx = COLOR_3DSHADOW;
|
||||
break;
|
||||
case eColorID_window:
|
||||
idx = COLOR_WINDOW;
|
||||
break;
|
||||
case eColorID_windowframe:
|
||||
idx = COLOR_WINDOWFRAME;
|
||||
break;
|
||||
case eColorID_windowtext:
|
||||
idx = COLOR_WINDOWTEXT;
|
||||
break;
|
||||
case eColorID__moz_eventreerow:
|
||||
case eColorID__moz_oddtreerow:
|
||||
case eColorID__moz_field:
|
||||
case eColorID__moz_combobox:
|
||||
idx = COLOR_WINDOW;
|
||||
break;
|
||||
case eColorID__moz_fieldtext:
|
||||
case eColorID__moz_comboboxtext:
|
||||
idx = COLOR_WINDOWTEXT;
|
||||
break;
|
||||
case eColorID__moz_dialog:
|
||||
case eColorID__moz_cellhighlight:
|
||||
idx = COLOR_3DFACE;
|
||||
break;
|
||||
case eColorID__moz_win_mediatext:
|
||||
if (IsVistaOrLater() && IsAppThemed()) {
|
||||
res = ::GetColorFromTheme(eUXMediaToolbar,
|
||||
TP_BUTTON, TS_NORMAL, TMT_TEXTCOLOR, aColor);
|
||||
if (NS_SUCCEEDED(res))
|
||||
return res;
|
||||
}
|
||||
// if we've gotten here just return -moz-dialogtext instead
|
||||
idx = COLOR_WINDOWTEXT;
|
||||
break;
|
||||
case eColorID__moz_win_communicationstext:
|
||||
if (IsVistaOrLater() && IsAppThemed())
|
||||
{
|
||||
res = ::GetColorFromTheme(eUXCommunicationsToolbar,
|
||||
TP_BUTTON, TS_NORMAL, TMT_TEXTCOLOR, aColor);
|
||||
if (NS_SUCCEEDED(res))
|
||||
return res;
|
||||
}
|
||||
// if we've gotten here just return -moz-dialogtext instead
|
||||
idx = COLOR_WINDOWTEXT;
|
||||
break;
|
||||
case eColorID__moz_dialogtext:
|
||||
case eColorID__moz_cellhighlighttext:
|
||||
idx = COLOR_WINDOWTEXT;
|
||||
break;
|
||||
case eColorID__moz_dragtargetzone:
|
||||
idx = COLOR_HIGHLIGHTTEXT;
|
||||
break;
|
||||
case eColorID__moz_buttondefault:
|
||||
idx = COLOR_3DDKSHADOW;
|
||||
break;
|
||||
case eColorID__moz_nativehyperlinktext:
|
||||
idx = COLOR_HOTLIGHT;
|
||||
break;
|
||||
default:
|
||||
idx = COLOR_WINDOW;
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD color = ::GetSysColor(idx);
|
||||
aColor = COLOREF_2_NSRGB(color);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult)
|
||||
{
|
||||
nsresult res = nsXPLookAndFeel::GetIntImpl(aID, aResult);
|
||||
if (NS_SUCCEEDED(res))
|
||||
return res;
|
||||
res = NS_OK;
|
||||
|
||||
switch (aID) {
|
||||
case eIntID_CaretBlinkTime:
|
||||
aResult = (int32_t)::GetCaretBlinkTime();
|
||||
break;
|
||||
case eIntID_CaretWidth:
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_ShowCaretDuringSelection:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_SelectTextfieldsOnKeyFocus:
|
||||
// Select textfield content when focused by kbd
|
||||
// used by EventStateManager::sTextfieldSelectModel
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_SubmenuDelay:
|
||||
// This will default to the Windows' default
|
||||
// (400ms) on error.
|
||||
aResult = GetSystemParam(SPI_GETMENUSHOWDELAY, 400);
|
||||
break;
|
||||
case eIntID_TooltipDelay:
|
||||
aResult = 500;
|
||||
break;
|
||||
case eIntID_MenusCanOverlapOSBar:
|
||||
// we want XUL popups to be able to overlap the task bar.
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_DragThresholdX:
|
||||
// The system metric is the number of pixels at which a drag should
|
||||
// start. Our look and feel metric is the number of pixels you can
|
||||
// move before starting a drag, so subtract 1.
|
||||
|
||||
aResult = ::GetSystemMetrics(SM_CXDRAG) - 1;
|
||||
break;
|
||||
case eIntID_DragThresholdY:
|
||||
aResult = ::GetSystemMetrics(SM_CYDRAG) - 1;
|
||||
break;
|
||||
case eIntID_UseAccessibilityTheme:
|
||||
// High contrast is a misnomer under Win32 -- any theme can be used with it,
|
||||
// e.g. normal contrast with large fonts, low contrast, etc.
|
||||
// The high contrast flag really means -- use this theme and don't override it.
|
||||
if (XRE_IsContentProcess()) {
|
||||
// If we're running in the content process, then the parent should
|
||||
// have sent us the accessibility state when nsLookAndFeel
|
||||
// initialized, and stashed it in the mUseAccessibilityTheme cache.
|
||||
aResult = mUseAccessibilityTheme;
|
||||
} else {
|
||||
// Otherwise, we can ask the OS to see if we're using High Contrast
|
||||
// mode.
|
||||
aResult = nsUXThemeData::IsHighContrastOn();
|
||||
}
|
||||
break;
|
||||
case eIntID_ScrollArrowStyle:
|
||||
aResult = eScrollArrowStyle_Single;
|
||||
break;
|
||||
case eIntID_ScrollSliderStyle:
|
||||
aResult = eScrollThumbStyle_Proportional;
|
||||
break;
|
||||
case eIntID_TreeOpenDelay:
|
||||
aResult = 1000;
|
||||
break;
|
||||
case eIntID_TreeCloseDelay:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_TreeLazyScrollDelay:
|
||||
aResult = 150;
|
||||
break;
|
||||
case eIntID_TreeScrollDelay:
|
||||
aResult = 100;
|
||||
break;
|
||||
case eIntID_TreeScrollLinesMax:
|
||||
aResult = 3;
|
||||
break;
|
||||
case eIntID_WindowsClassic:
|
||||
aResult = !IsAppThemed();
|
||||
break;
|
||||
case eIntID_TouchEnabled:
|
||||
aResult = WinUtils::IsTouchDeviceSupportPresent();
|
||||
break;
|
||||
case eIntID_WindowsDefaultTheme:
|
||||
aResult = nsUXThemeData::IsDefaultWindowTheme();
|
||||
break;
|
||||
case eIntID_WindowsThemeIdentifier:
|
||||
aResult = nsUXThemeData::GetNativeThemeId();
|
||||
break;
|
||||
|
||||
case eIntID_OperatingSystemVersionIdentifier:
|
||||
{
|
||||
aResult = GetOperatingSystemVersion();
|
||||
break;
|
||||
}
|
||||
|
||||
case eIntID_MacGraphiteTheme:
|
||||
aResult = 0;
|
||||
res = NS_ERROR_NOT_IMPLEMENTED;
|
||||
break;
|
||||
case eIntID_DWMCompositor:
|
||||
aResult = nsUXThemeData::CheckForCompositor();
|
||||
break;
|
||||
case eIntID_WindowsGlass:
|
||||
// Aero Glass is only available prior to Windows 8 when DWM is used.
|
||||
aResult = (nsUXThemeData::CheckForCompositor() && !IsWin8OrLater());
|
||||
break;
|
||||
case eIntID_AlertNotificationOrigin:
|
||||
aResult = 0;
|
||||
{
|
||||
// Get task bar window handle
|
||||
HWND shellWindow = FindWindowW(L"Shell_TrayWnd", nullptr);
|
||||
|
||||
if (shellWindow != nullptr)
|
||||
{
|
||||
// Determine position
|
||||
APPBARDATA appBarData;
|
||||
appBarData.hWnd = shellWindow;
|
||||
appBarData.cbSize = sizeof(appBarData);
|
||||
if (SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData))
|
||||
{
|
||||
// Set alert origin as a bit field - see LookAndFeel.h
|
||||
// 0 represents bottom right, sliding vertically.
|
||||
switch(appBarData.uEdge)
|
||||
{
|
||||
case ABE_LEFT:
|
||||
aResult = NS_ALERT_HORIZONTAL | NS_ALERT_LEFT;
|
||||
break;
|
||||
case ABE_RIGHT:
|
||||
aResult = NS_ALERT_HORIZONTAL;
|
||||
break;
|
||||
case ABE_TOP:
|
||||
aResult = NS_ALERT_TOP;
|
||||
// fall through for the right-to-left handling.
|
||||
case ABE_BOTTOM:
|
||||
// If the task bar is right-to-left,
|
||||
// move the origin to the left
|
||||
if (::GetWindowLong(shellWindow, GWL_EXSTYLE) &
|
||||
WS_EX_LAYOUTRTL)
|
||||
aResult |= NS_ALERT_LEFT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case eIntID_IMERawInputUnderlineStyle:
|
||||
case eIntID_IMEConvertedTextUnderlineStyle:
|
||||
aResult = NS_STYLE_TEXT_DECORATION_STYLE_DASHED;
|
||||
break;
|
||||
case eIntID_IMESelectedRawTextUnderlineStyle:
|
||||
case eIntID_IMESelectedConvertedTextUnderline:
|
||||
aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE;
|
||||
break;
|
||||
case eIntID_SpellCheckerUnderlineStyle:
|
||||
aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
|
||||
break;
|
||||
case eIntID_ScrollbarButtonAutoRepeatBehavior:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_SwipeAnimationEnabled:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_ColorPickerAvailable:
|
||||
aResult = true;
|
||||
break;
|
||||
case eIntID_UseOverlayScrollbars:
|
||||
aResult = false;
|
||||
break;
|
||||
case eIntID_AllowOverlayScrollbarsOverlap:
|
||||
aResult = 0;
|
||||
break;
|
||||
case eIntID_ScrollbarDisplayOnMouseMove:
|
||||
aResult = 1;
|
||||
break;
|
||||
case eIntID_ScrollbarFadeBeginDelay:
|
||||
aResult = 2500;
|
||||
break;
|
||||
case eIntID_ScrollbarFadeDuration:
|
||||
aResult = 350;
|
||||
break;
|
||||
case eIntID_ContextMenuOffsetVertical:
|
||||
case eIntID_ContextMenuOffsetHorizontal:
|
||||
aResult = 2;
|
||||
break;
|
||||
default:
|
||||
aResult = 0;
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult)
|
||||
{
|
||||
nsresult res = nsXPLookAndFeel::GetFloatImpl(aID, aResult);
|
||||
if (NS_SUCCEEDED(res))
|
||||
return res;
|
||||
res = NS_OK;
|
||||
|
||||
switch (aID) {
|
||||
case eFloatID_IMEUnderlineRelativeSize:
|
||||
aResult = 1.0f;
|
||||
break;
|
||||
case eFloatID_SpellCheckerUnderlineRelativeSize:
|
||||
aResult = 1.0f;
|
||||
break;
|
||||
default:
|
||||
aResult = -1.0;
|
||||
res = NS_ERROR_FAILURE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetSysFontInfo(HDC aHDC, LookAndFeel::FontID anID,
|
||||
nsString &aFontName,
|
||||
gfxFontStyle &aFontStyle)
|
||||
{
|
||||
LOGFONTW* ptrLogFont = nullptr;
|
||||
LOGFONTW logFont;
|
||||
NONCLIENTMETRICSW ncm;
|
||||
char16_t name[LF_FACESIZE];
|
||||
bool useShellDlg = false;
|
||||
|
||||
// Depending on which stock font we want, there are a couple of
|
||||
// places we might have to look it up.
|
||||
switch (anID) {
|
||||
case LookAndFeel::eFont_Icon:
|
||||
if (!::SystemParametersInfoW(SPI_GETICONTITLELOGFONT,
|
||||
sizeof(logFont), (PVOID)&logFont, 0))
|
||||
return false;
|
||||
|
||||
ptrLogFont = &logFont;
|
||||
break;
|
||||
|
||||
default:
|
||||
ncm.cbSize = sizeof(NONCLIENTMETRICSW);
|
||||
if (!::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
|
||||
sizeof(ncm), (PVOID)&ncm, 0))
|
||||
return false;
|
||||
|
||||
switch (anID) {
|
||||
case LookAndFeel::eFont_Menu:
|
||||
case LookAndFeel::eFont_PullDownMenu:
|
||||
ptrLogFont = &ncm.lfMenuFont;
|
||||
break;
|
||||
case LookAndFeel::eFont_Caption:
|
||||
ptrLogFont = &ncm.lfCaptionFont;
|
||||
break;
|
||||
case LookAndFeel::eFont_SmallCaption:
|
||||
ptrLogFont = &ncm.lfSmCaptionFont;
|
||||
break;
|
||||
case LookAndFeel::eFont_StatusBar:
|
||||
case LookAndFeel::eFont_Tooltips:
|
||||
ptrLogFont = &ncm.lfStatusFont;
|
||||
break;
|
||||
case LookAndFeel::eFont_Widget:
|
||||
case LookAndFeel::eFont_Dialog:
|
||||
case LookAndFeel::eFont_Button:
|
||||
case LookAndFeel::eFont_Field:
|
||||
case LookAndFeel::eFont_List:
|
||||
// XXX It's not clear to me whether this is exactly the right
|
||||
// set of LookAndFeel values to map to the dialog font; we may
|
||||
// want to add or remove cases here after reviewing the visual
|
||||
// results under various Windows versions.
|
||||
useShellDlg = true;
|
||||
// Fall through so that we can get size from lfMessageFont;
|
||||
// but later we'll use the (virtual) "MS Shell Dlg 2" font name
|
||||
// instead of the LOGFONT's.
|
||||
default:
|
||||
ptrLogFont = &ncm.lfMessageFont;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Get scaling factor from physical to logical pixels
|
||||
double pixelScale = 1.0 / WinUtils::SystemScaleFactor();
|
||||
|
||||
// The lfHeight is in pixels, and it needs to be adjusted for the
|
||||
// device it will be displayed on.
|
||||
// Screens and Printers will differ in DPI
|
||||
//
|
||||
// So this accounts for the difference in the DeviceContexts
|
||||
// The pixelScale will typically be 1.0 for the screen
|
||||
// (though larger for hi-dpi screens where the Windows resolution
|
||||
// scale factor is 125% or 150% or even more), and could be
|
||||
// any value when going to a printer, for example pixelScale is
|
||||
// 6.25 when going to a 600dpi printer.
|
||||
float pixelHeight = -ptrLogFont->lfHeight;
|
||||
if (pixelHeight < 0) {
|
||||
HFONT hFont = ::CreateFontIndirectW(ptrLogFont);
|
||||
if (!hFont)
|
||||
return false;
|
||||
HGDIOBJ hObject = ::SelectObject(aHDC, hFont);
|
||||
TEXTMETRIC tm;
|
||||
::GetTextMetrics(aHDC, &tm);
|
||||
::SelectObject(aHDC, hObject);
|
||||
::DeleteObject(hFont);
|
||||
pixelHeight = tm.tmAscent;
|
||||
}
|
||||
pixelHeight *= pixelScale;
|
||||
|
||||
// we have problem on Simplified Chinese system because the system
|
||||
// report the default font size is 8 points. but if we use 8, the text
|
||||
// display very ugly. force it to be at 9 points (12 pixels) on that
|
||||
// system (cp936), but leave other sizes alone.
|
||||
if (pixelHeight < 12 && ::GetACP() == 936)
|
||||
pixelHeight = 12;
|
||||
|
||||
aFontStyle.size = pixelHeight;
|
||||
|
||||
// FIXME: What about oblique?
|
||||
aFontStyle.style =
|
||||
(ptrLogFont->lfItalic) ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL;
|
||||
|
||||
// FIXME: Other weights?
|
||||
aFontStyle.weight =
|
||||
(ptrLogFont->lfWeight == FW_BOLD ?
|
||||
NS_FONT_WEIGHT_BOLD : NS_FONT_WEIGHT_NORMAL);
|
||||
|
||||
// FIXME: Set aFontStyle->stretch correctly!
|
||||
aFontStyle.stretch = NS_FONT_STRETCH_NORMAL;
|
||||
|
||||
aFontStyle.systemFont = true;
|
||||
|
||||
if (useShellDlg) {
|
||||
aFontName = NS_LITERAL_STRING("MS Shell Dlg 2");
|
||||
} else {
|
||||
memcpy(name, ptrLogFont->lfFaceName, LF_FACESIZE*sizeof(char16_t));
|
||||
aFontName = name;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsLookAndFeel::GetFontImpl(FontID anID, nsString &aFontName,
|
||||
gfxFontStyle &aFontStyle,
|
||||
float aDevPixPerCSSPixel)
|
||||
{
|
||||
HDC tdc = GetDC(nullptr);
|
||||
bool status = GetSysFontInfo(tdc, anID, aFontName, aFontStyle);
|
||||
ReleaseDC(nullptr, tdc);
|
||||
// now convert the logical font size from GetSysFontInfo into device pixels for layout
|
||||
aFontStyle.size *= aDevPixPerCSSPixel;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
char16_t
|
||||
nsLookAndFeel::GetPasswordCharacterImpl()
|
||||
{
|
||||
#define UNICODE_BLACK_CIRCLE_CHAR 0x25cf
|
||||
return UNICODE_BLACK_CIRCLE_CHAR;
|
||||
}
|
||||
|
||||
nsTArray<LookAndFeelInt>
|
||||
nsLookAndFeel::GetIntCacheImpl()
|
||||
{
|
||||
nsTArray<LookAndFeelInt> lookAndFeelIntCache =
|
||||
nsXPLookAndFeel::GetIntCacheImpl();
|
||||
|
||||
LookAndFeelInt useAccessibilityTheme;
|
||||
useAccessibilityTheme.id = eIntID_UseAccessibilityTheme;
|
||||
useAccessibilityTheme.value = GetInt(eIntID_UseAccessibilityTheme);
|
||||
lookAndFeelIntCache.AppendElement(useAccessibilityTheme);
|
||||
|
||||
return lookAndFeelIntCache;
|
||||
}
|
||||
|
||||
void
|
||||
nsLookAndFeel::SetIntCacheImpl(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache)
|
||||
{
|
||||
for (auto entry : aLookAndFeelIntCache) {
|
||||
if (entry.id == eIntID_UseAccessibilityTheme) {
|
||||
mUseAccessibilityTheme = entry.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
65
widget/windows/nsLookAndFeel.h
Normal file
65
widget/windows/nsLookAndFeel.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __nsLookAndFeel
|
||||
#define __nsLookAndFeel
|
||||
#include "nsXPLookAndFeel.h"
|
||||
|
||||
/*
|
||||
* Gesture System Metrics
|
||||
*/
|
||||
#ifndef SM_DIGITIZER
|
||||
#define SM_DIGITIZER 94
|
||||
#define TABLET_CONFIG_NONE 0x00000000
|
||||
#define NID_INTEGRATED_TOUCH 0x00000001
|
||||
#define NID_EXTERNAL_TOUCH 0x00000002
|
||||
#define NID_INTEGRATED_PEN 0x00000004
|
||||
#define NID_EXTERNAL_PEN 0x00000008
|
||||
#define NID_MULTI_INPUT 0x00000040
|
||||
#define NID_READY 0x00000080
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Tablet mode detection
|
||||
*/
|
||||
#ifndef SM_SYSTEMDOCKED
|
||||
#define SM_CONVERTIBLESLATEMODE 0x00002003
|
||||
#define SM_SYSTEMDOCKED 0x00002004
|
||||
typedef enum _AR_STATE
|
||||
{
|
||||
AR_ENABLED = 0x0,
|
||||
AR_DISABLED = 0x1,
|
||||
AR_SUPPRESSED = 0x2,
|
||||
AR_REMOTESESSION = 0x4,
|
||||
AR_MULTIMON = 0x8,
|
||||
AR_NOSENSOR = 0x10,
|
||||
AR_NOT_SUPPORTED = 0x20,
|
||||
AR_DOCKED = 0x40,
|
||||
AR_LAPTOP = 0x80
|
||||
} AR_STATE, *PAR_STATE;
|
||||
#endif
|
||||
|
||||
class nsLookAndFeel: public nsXPLookAndFeel {
|
||||
static OperatingSystemVersion GetOperatingSystemVersion();
|
||||
public:
|
||||
nsLookAndFeel();
|
||||
virtual ~nsLookAndFeel();
|
||||
|
||||
virtual nsresult NativeGetColor(ColorID aID, nscolor &aResult);
|
||||
virtual nsresult GetIntImpl(IntID aID, int32_t &aResult);
|
||||
virtual nsresult GetFloatImpl(FloatID aID, float &aResult);
|
||||
virtual bool GetFontImpl(FontID aID, nsString& aFontName,
|
||||
gfxFontStyle& aFontStyle,
|
||||
float aDevPixPerCSSPixel);
|
||||
virtual char16_t GetPasswordCharacterImpl();
|
||||
|
||||
virtual nsTArray<LookAndFeelInt> GetIntCacheImpl();
|
||||
virtual void SetIntCacheImpl(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache);
|
||||
|
||||
private:
|
||||
int32_t mUseAccessibilityTheme;
|
||||
};
|
||||
|
||||
#endif
|
||||
109
widget/windows/nsNativeDragSource.cpp
Normal file
109
widget/windows/nsNativeDragSource.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/* -*- 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 "nsNativeDragSource.h"
|
||||
#include <stdio.h>
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsToolkit.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsIDragService.h"
|
||||
|
||||
/*
|
||||
* class nsNativeDragSource
|
||||
*/
|
||||
nsNativeDragSource::nsNativeDragSource(nsIDOMDataTransfer* aDataTransfer) :
|
||||
m_cRef(0),
|
||||
m_hCursor(nullptr),
|
||||
mUserCancelled(false)
|
||||
{
|
||||
mDataTransfer = do_QueryInterface(aDataTransfer);
|
||||
}
|
||||
|
||||
nsNativeDragSource::~nsNativeDragSource()
|
||||
{
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
nsNativeDragSource::QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
*ppv=nullptr;
|
||||
|
||||
if (IID_IUnknown==riid || IID_IDropSource==riid)
|
||||
*ppv=this;
|
||||
|
||||
if (nullptr!=*ppv) {
|
||||
((LPUNKNOWN)*ppv)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
nsNativeDragSource::AddRef(void)
|
||||
{
|
||||
++m_cRef;
|
||||
NS_LOG_ADDREF(this, m_cRef, "nsNativeDragSource", sizeof(*this));
|
||||
return m_cRef;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
nsNativeDragSource::Release(void)
|
||||
{
|
||||
--m_cRef;
|
||||
NS_LOG_RELEASE(this, m_cRef, "nsNativeDragSource");
|
||||
if (0 != m_cRef)
|
||||
return m_cRef;
|
||||
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
nsNativeDragSource::QueryContinueDrag(BOOL fEsc, DWORD grfKeyState)
|
||||
{
|
||||
static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
|
||||
|
||||
nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
|
||||
if (dragService) {
|
||||
DWORD pos = ::GetMessagePos();
|
||||
dragService->DragMoved(GET_X_LPARAM(pos), GET_Y_LPARAM(pos));
|
||||
}
|
||||
|
||||
if (fEsc) {
|
||||
mUserCancelled = true;
|
||||
return DRAGDROP_S_CANCEL;
|
||||
}
|
||||
|
||||
if (!(grfKeyState & MK_LBUTTON) || (grfKeyState & MK_RBUTTON))
|
||||
return DRAGDROP_S_DROP;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
nsNativeDragSource::GiveFeedback(DWORD dwEffect)
|
||||
{
|
||||
// For drags involving tabs, we do some custom work with cursors.
|
||||
if (mDataTransfer) {
|
||||
nsAutoString cursor;
|
||||
mDataTransfer->GetMozCursor(cursor);
|
||||
if (cursor.EqualsLiteral("default")) {
|
||||
m_hCursor = ::LoadCursor(0, IDC_ARROW);
|
||||
} else {
|
||||
m_hCursor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_hCursor) {
|
||||
::SetCursor(m_hCursor);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Let the system choose which cursor to apply.
|
||||
return DRAGDROP_S_USEDEFAULTCURSORS;
|
||||
}
|
||||
66
widget/windows/nsNativeDragSource.h
Normal file
66
widget/windows/nsNativeDragSource.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef _nsNativeDragSource_h_
|
||||
#define _nsNativeDragSource_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsIDOMDataTransfer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include <ole2.h>
|
||||
#include <oleidl.h>
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
//class nsIDragSource;
|
||||
|
||||
/*
|
||||
* nsNativeDragSource implements the IDropSource interface and gets
|
||||
* most of its behavior from the associated adapter (m_dragDrop).
|
||||
*/
|
||||
class nsNativeDragSource final : public IDropSource
|
||||
{
|
||||
public:
|
||||
|
||||
// construct an nsNativeDragSource referencing adapter
|
||||
// nsNativeDragSource(nsIDragSource * adapter);
|
||||
nsNativeDragSource(nsIDOMDataTransfer* aDataTransfer);
|
||||
~nsNativeDragSource();
|
||||
|
||||
// IUnknown methods - see iunknown.h for documentation
|
||||
|
||||
STDMETHODIMP QueryInterface(REFIID, void**);
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IDropSource methods - see idropsrc.h for documentation
|
||||
|
||||
// Return DRAGDROP_S_USEDEFAULTCURSORS if this object lets OLE provide
|
||||
// default cursors, otherwise return NOERROR. This method gets called in
|
||||
// response to changes that the target makes to dEffect (DragEnter,
|
||||
// DragOver).
|
||||
STDMETHODIMP GiveFeedback(DWORD dEffect);
|
||||
|
||||
// This method gets called if there is any change in the mouse or key
|
||||
// state. Return DRAGDROP_S_CANCEL to stop the drag, DRAGDROP_S_DROP
|
||||
// to execute the drop, otherwise NOERROR.
|
||||
STDMETHODIMP QueryContinueDrag(BOOL fESC, DWORD grfKeyState);
|
||||
|
||||
bool UserCancelled() { return mUserCancelled; }
|
||||
|
||||
protected:
|
||||
// Reference count
|
||||
ULONG m_cRef;
|
||||
|
||||
// Data object, hold information about cursor state
|
||||
nsCOMPtr<nsIDOMDataTransfer> mDataTransfer;
|
||||
|
||||
// Custom drag cursor
|
||||
HCURSOR m_hCursor;
|
||||
|
||||
// true if the user cancelled the drag by pressing escape
|
||||
bool mUserCancelled;
|
||||
};
|
||||
|
||||
#endif // _nsNativeDragSource_h_
|
||||
|
||||
486
widget/windows/nsNativeDragTarget.cpp
Normal file
486
widget/windows/nsNativeDragTarget.cpp
Normal file
|
|
@ -0,0 +1,486 @@
|
|||
/* -*- 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 <stdio.h>
|
||||
#include "nsIDragService.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsNativeDragTarget.h"
|
||||
#include "nsDragService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsIWidget.h"
|
||||
#include "nsWindow.h"
|
||||
#include "nsClipboard.h"
|
||||
#include "KeyboardLayout.h"
|
||||
|
||||
#include "mozilla/MouseEvents.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
/* Define Interface IDs */
|
||||
static NS_DEFINE_IID(kIDragServiceIID, NS_IDRAGSERVICE_IID);
|
||||
|
||||
// This is cached for Leave notification
|
||||
static POINTL gDragLastPoint;
|
||||
|
||||
/*
|
||||
* class nsNativeDragTarget
|
||||
*/
|
||||
nsNativeDragTarget::nsNativeDragTarget(nsIWidget * aWidget)
|
||||
: m_cRef(0),
|
||||
mEffectsAllowed(DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK),
|
||||
mEffectsPreferred(DROPEFFECT_NONE),
|
||||
mTookOwnRef(false), mWidget(aWidget), mDropTargetHelper(nullptr)
|
||||
{
|
||||
static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
|
||||
|
||||
mHWnd = (HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
|
||||
/*
|
||||
* Create/Get the DragService that we have implemented
|
||||
*/
|
||||
CallGetService(kCDragServiceCID, &mDragService);
|
||||
}
|
||||
|
||||
nsNativeDragTarget::~nsNativeDragTarget()
|
||||
{
|
||||
NS_RELEASE(mDragService);
|
||||
|
||||
if (mDropTargetHelper) {
|
||||
mDropTargetHelper->Release();
|
||||
mDropTargetHelper = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// IUnknown methods - see iunknown.h for documentation
|
||||
STDMETHODIMP
|
||||
nsNativeDragTarget::QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
*ppv=nullptr;
|
||||
|
||||
if (IID_IUnknown == riid || IID_IDropTarget == riid)
|
||||
*ppv=this;
|
||||
|
||||
if (nullptr!=*ppv) {
|
||||
((LPUNKNOWN)*ppv)->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
nsNativeDragTarget::AddRef(void)
|
||||
{
|
||||
++m_cRef;
|
||||
NS_LOG_ADDREF(this, m_cRef, "nsNativeDragTarget", sizeof(*this));
|
||||
return m_cRef;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) nsNativeDragTarget::Release(void)
|
||||
{
|
||||
--m_cRef;
|
||||
NS_LOG_RELEASE(this, m_cRef, "nsNativeDragTarget");
|
||||
if (0 != m_cRef)
|
||||
return m_cRef;
|
||||
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nsNativeDragTarget::GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect,
|
||||
uint32_t * aGeckoAction)
|
||||
{
|
||||
// If a window is disabled or a modal window is on top of it
|
||||
// (which implies it is disabled), then we should not allow dropping.
|
||||
if (!mWidget->IsEnabled()) {
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the user explicitly uses a modifier key, they want the associated action
|
||||
// Shift + Control -> LINK, Shift -> MOVE, Ctrl -> COPY
|
||||
DWORD desiredEffect = DROPEFFECT_NONE;
|
||||
if ((grfKeyState & MK_CONTROL) && (grfKeyState & MK_SHIFT)) {
|
||||
desiredEffect = DROPEFFECT_LINK;
|
||||
} else if (grfKeyState & MK_SHIFT) {
|
||||
desiredEffect = DROPEFFECT_MOVE;
|
||||
} else if (grfKeyState & MK_CONTROL) {
|
||||
desiredEffect = DROPEFFECT_COPY;
|
||||
}
|
||||
|
||||
// Determine the desired effect from what is allowed and preferred.
|
||||
if (!(desiredEffect &= mEffectsAllowed)) {
|
||||
// No modifier key effect is set which is also allowed, check
|
||||
// the preference of the data.
|
||||
desiredEffect = mEffectsPreferred & mEffectsAllowed;
|
||||
if (!desiredEffect) {
|
||||
// No preference is set, so just fall back to the allowed effect itself
|
||||
desiredEffect = mEffectsAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise we should specify the first available effect
|
||||
// from MOVE, COPY, or LINK.
|
||||
if (desiredEffect & DROPEFFECT_MOVE) {
|
||||
*pdwEffect = DROPEFFECT_MOVE;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_MOVE;
|
||||
} else if (desiredEffect & DROPEFFECT_COPY) {
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY;
|
||||
} else if (desiredEffect & DROPEFFECT_LINK) {
|
||||
*pdwEffect = DROPEFFECT_LINK;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK;
|
||||
} else {
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
IsKeyDown(char key)
|
||||
{
|
||||
return GetKeyState(key) < 0;
|
||||
}
|
||||
|
||||
void
|
||||
nsNativeDragTarget::DispatchDragDropEvent(EventMessage aEventMessage,
|
||||
const POINTL& aPT)
|
||||
{
|
||||
nsEventStatus status;
|
||||
WidgetDragEvent event(true, aEventMessage, mWidget);
|
||||
|
||||
nsWindow * win = static_cast<nsWindow *>(mWidget);
|
||||
win->InitEvent(event);
|
||||
POINT cpos;
|
||||
|
||||
cpos.x = aPT.x;
|
||||
cpos.y = aPT.y;
|
||||
|
||||
if (mHWnd != nullptr) {
|
||||
::ScreenToClient(mHWnd, &cpos);
|
||||
event.mRefPoint = LayoutDeviceIntPoint(cpos.x, cpos.y);
|
||||
} else {
|
||||
event.mRefPoint = LayoutDeviceIntPoint(0, 0);
|
||||
}
|
||||
|
||||
ModifierKeyState modifierKeyState;
|
||||
modifierKeyState.InitInputEvent(event);
|
||||
|
||||
event.inputSource = static_cast<nsBaseDragService*>(mDragService)->GetInputSource();
|
||||
|
||||
mWidget->DispatchEvent(&event, status);
|
||||
}
|
||||
|
||||
void
|
||||
nsNativeDragTarget::ProcessDrag(EventMessage aEventMessage,
|
||||
DWORD grfKeyState,
|
||||
POINTL ptl,
|
||||
DWORD* pdwEffect)
|
||||
{
|
||||
// Before dispatching the event make sure we have the correct drop action set
|
||||
uint32_t geckoAction;
|
||||
GetGeckoDragAction(grfKeyState, pdwEffect, &geckoAction);
|
||||
|
||||
// Set the current action into the Gecko specific type
|
||||
nsCOMPtr<nsIDragSession> currSession;
|
||||
mDragService->GetCurrentSession(getter_AddRefs(currSession));
|
||||
if (!currSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
currSession->SetDragAction(geckoAction);
|
||||
|
||||
// Dispatch the event into Gecko
|
||||
DispatchDragDropEvent(aEventMessage, ptl);
|
||||
|
||||
// If TakeChildProcessDragAction returns something other than
|
||||
// DRAGDROP_ACTION_UNINITIALIZED, it means that the last event was sent
|
||||
// to the child process and this event is also being sent to the child
|
||||
// process. In this case, use the last event's action instead.
|
||||
nsDragService* dragService = static_cast<nsDragService *>(mDragService);
|
||||
currSession->GetDragAction(&geckoAction);
|
||||
|
||||
int32_t childDragAction = dragService->TakeChildProcessDragAction();
|
||||
if (childDragAction != nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
|
||||
geckoAction = childDragAction;
|
||||
}
|
||||
|
||||
if (nsIDragService::DRAGDROP_ACTION_LINK & geckoAction) {
|
||||
*pdwEffect = DROPEFFECT_LINK;
|
||||
}
|
||||
else if (nsIDragService::DRAGDROP_ACTION_COPY & geckoAction) {
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
}
|
||||
else if (nsIDragService::DRAGDROP_ACTION_MOVE & geckoAction) {
|
||||
*pdwEffect = DROPEFFECT_MOVE;
|
||||
}
|
||||
else {
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
}
|
||||
|
||||
if (aEventMessage != eDrop) {
|
||||
// Get the cached drag effect from the drag service, the data member should
|
||||
// have been set by whoever handled the WidgetGUIEvent or nsIDOMEvent on
|
||||
// drags.
|
||||
bool canDrop;
|
||||
currSession->GetCanDrop(&canDrop);
|
||||
if (!canDrop) {
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the cached value
|
||||
currSession->SetCanDrop(false);
|
||||
}
|
||||
|
||||
// IDropTarget methods
|
||||
STDMETHODIMP
|
||||
nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
|
||||
DWORD grfKeyState,
|
||||
POINTL ptl,
|
||||
DWORD* pdwEffect)
|
||||
{
|
||||
if (!mDragService) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
mEffectsAllowed = *pdwEffect;
|
||||
AddLinkSupportIfCanBeGenerated(pIDataSource);
|
||||
|
||||
// Drag and drop image helper
|
||||
if (GetDropTargetHelper()) {
|
||||
POINT pt = { ptl.x, ptl.y };
|
||||
GetDropTargetHelper()->DragEnter(mHWnd, pIDataSource, &pt, *pdwEffect);
|
||||
}
|
||||
|
||||
// save a ref to this, in case the window is destroyed underneath us
|
||||
NS_ASSERTION(!mTookOwnRef, "own ref already taken!");
|
||||
this->AddRef();
|
||||
mTookOwnRef = true;
|
||||
|
||||
// tell the drag service about this drag (it may have come from an
|
||||
// outside app).
|
||||
mDragService->StartDragSession();
|
||||
|
||||
void* tempOutData = nullptr;
|
||||
uint32_t tempDataLen = 0;
|
||||
nsresult loadResult = nsClipboard::GetNativeDataOffClipboard(
|
||||
pIDataSource, 0, ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT), nullptr, &tempOutData, &tempDataLen);
|
||||
if (NS_SUCCEEDED(loadResult) && tempOutData) {
|
||||
mEffectsPreferred = *((DWORD*)tempOutData);
|
||||
free(tempOutData);
|
||||
} else {
|
||||
// We have no preference if we can't obtain it
|
||||
mEffectsPreferred = DROPEFFECT_NONE;
|
||||
}
|
||||
|
||||
// Set the native data object into drag service
|
||||
//
|
||||
// This cast is ok because in the constructor we created a
|
||||
// the actual implementation we wanted, so we know this is
|
||||
// a nsDragService. It should be a private interface, though.
|
||||
nsDragService * winDragService =
|
||||
static_cast<nsDragService *>(mDragService);
|
||||
winDragService->SetIDataObject(pIDataSource);
|
||||
|
||||
// Now process the native drag state and then dispatch the event
|
||||
ProcessDrag(eDragEnter, grfKeyState, ptl, pdwEffect);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsNativeDragTarget::AddLinkSupportIfCanBeGenerated(LPDATAOBJECT aIDataSource)
|
||||
{
|
||||
// If we don't have a link effect, but we can generate one, fix the
|
||||
// drop effect to include it.
|
||||
if (!(mEffectsAllowed & DROPEFFECT_LINK) && aIDataSource) {
|
||||
if (S_OK == ::OleQueryLinkFromData(aIDataSource)) {
|
||||
mEffectsAllowed |= DROPEFFECT_LINK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
nsNativeDragTarget::DragOver(DWORD grfKeyState,
|
||||
POINTL ptl,
|
||||
LPDWORD pdwEffect)
|
||||
{
|
||||
if (!mDragService) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// If a LINK effect could be generated previously from a DragEnter(),
|
||||
// then we should include it as an allowed effect.
|
||||
mEffectsAllowed = (*pdwEffect) | (mEffectsAllowed & DROPEFFECT_LINK);
|
||||
|
||||
nsCOMPtr<nsIDragSession> currentDragSession;
|
||||
mDragService->GetCurrentSession(getter_AddRefs(currentDragSession));
|
||||
if (!currentDragSession) {
|
||||
return S_OK; // Drag was canceled.
|
||||
}
|
||||
|
||||
// without the AddRef() |this| can get destroyed in an event handler
|
||||
this->AddRef();
|
||||
|
||||
// Drag and drop image helper
|
||||
if (GetDropTargetHelper()) {
|
||||
POINT pt = { ptl.x, ptl.y };
|
||||
GetDropTargetHelper()->DragOver(&pt, *pdwEffect);
|
||||
}
|
||||
|
||||
mDragService->FireDragEventAtSource(eDrag);
|
||||
// Now process the native drag state and then dispatch the event
|
||||
ProcessDrag(eDragOver, grfKeyState, ptl, pdwEffect);
|
||||
|
||||
this->Release();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
nsNativeDragTarget::DragLeave()
|
||||
{
|
||||
if (!mDragService) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Drag and drop image helper
|
||||
if (GetDropTargetHelper()) {
|
||||
GetDropTargetHelper()->DragLeave();
|
||||
}
|
||||
|
||||
// dispatch the event into Gecko
|
||||
DispatchDragDropEvent(eDragExit, gDragLastPoint);
|
||||
|
||||
nsCOMPtr<nsIDragSession> currentDragSession;
|
||||
mDragService->GetCurrentSession(getter_AddRefs(currentDragSession));
|
||||
|
||||
if (currentDragSession) {
|
||||
nsCOMPtr<nsIDOMNode> sourceNode;
|
||||
currentDragSession->GetSourceNode(getter_AddRefs(sourceNode));
|
||||
|
||||
if (!sourceNode) {
|
||||
// We're leaving a window while doing a drag that was
|
||||
// initiated in a different app. End the drag session, since
|
||||
// we're done with it for now (until the user drags back into
|
||||
// mozilla).
|
||||
mDragService->EndDragSession(false);
|
||||
}
|
||||
}
|
||||
|
||||
// release the ref that was taken in DragEnter
|
||||
NS_ASSERTION(mTookOwnRef, "want to release own ref, but not taken!");
|
||||
if (mTookOwnRef) {
|
||||
this->Release();
|
||||
mTookOwnRef = false;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsNativeDragTarget::DragCancel()
|
||||
{
|
||||
// Cancel the drag session if we did DragEnter.
|
||||
if (mTookOwnRef) {
|
||||
if (GetDropTargetHelper()) {
|
||||
GetDropTargetHelper()->DragLeave();
|
||||
}
|
||||
if (mDragService) {
|
||||
mDragService->EndDragSession(false);
|
||||
}
|
||||
this->Release(); // matching the AddRef in DragEnter
|
||||
mTookOwnRef = false;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
nsNativeDragTarget::Drop(LPDATAOBJECT pData,
|
||||
DWORD grfKeyState,
|
||||
POINTL aPT,
|
||||
LPDWORD pdwEffect)
|
||||
{
|
||||
if (!mDragService) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
mEffectsAllowed = *pdwEffect;
|
||||
AddLinkSupportIfCanBeGenerated(pData);
|
||||
|
||||
// Drag and drop image helper
|
||||
if (GetDropTargetHelper()) {
|
||||
POINT pt = { aPT.x, aPT.y };
|
||||
GetDropTargetHelper()->Drop(pData, &pt, *pdwEffect);
|
||||
}
|
||||
|
||||
// Set the native data object into the drag service
|
||||
//
|
||||
// This cast is ok because in the constructor we created a
|
||||
// the actual implementation we wanted, so we know this is
|
||||
// a nsDragService (but it should still be a private interface)
|
||||
nsDragService* winDragService = static_cast<nsDragService*>(mDragService);
|
||||
winDragService->SetIDataObject(pData);
|
||||
|
||||
// NOTE: ProcessDrag spins the event loop which may destroy arbitrary objects.
|
||||
// We use strong refs to prevent it from destroying these:
|
||||
RefPtr<nsNativeDragTarget> kungFuDeathGrip = this;
|
||||
nsCOMPtr<nsIDragService> serv = mDragService;
|
||||
|
||||
// Now process the native drag state and then dispatch the event
|
||||
ProcessDrag(eDrop, grfKeyState, aPT, pdwEffect);
|
||||
|
||||
nsCOMPtr<nsIDragSession> currentDragSession;
|
||||
serv->GetCurrentSession(getter_AddRefs(currentDragSession));
|
||||
if (!currentDragSession) {
|
||||
return S_OK; // DragCancel() was called.
|
||||
}
|
||||
|
||||
// Let the win drag service know whether this session experienced
|
||||
// a drop event within the application. Drop will not oocur if the
|
||||
// drop landed outside the app. (used in tab tear off, bug 455884)
|
||||
winDragService->SetDroppedLocal();
|
||||
|
||||
// tell the drag service we're done with the session
|
||||
// Use GetMessagePos to get the position of the mouse at the last message
|
||||
// seen by the event loop. (Bug 489729)
|
||||
DWORD pos = ::GetMessagePos();
|
||||
POINT cpos;
|
||||
cpos.x = GET_X_LPARAM(pos);
|
||||
cpos.y = GET_Y_LPARAM(pos);
|
||||
winDragService->SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
|
||||
serv->EndDragSession(true);
|
||||
|
||||
// release the ref that was taken in DragEnter
|
||||
NS_ASSERTION(mTookOwnRef, "want to release own ref, but not taken!");
|
||||
if (mTookOwnRef) {
|
||||
this->Release();
|
||||
mTookOwnRef = false;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* By lazy loading mDropTargetHelper we save 50-70ms of startup time
|
||||
* which is ~5% of startup time.
|
||||
*/
|
||||
IDropTargetHelper*
|
||||
nsNativeDragTarget::GetDropTargetHelper()
|
||||
{
|
||||
if (!mDropTargetHelper) {
|
||||
CoCreateInstance(CLSID_DragDropHelper, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_IDropTargetHelper, (LPVOID*)&mDropTargetHelper);
|
||||
}
|
||||
|
||||
return mDropTargetHelper;
|
||||
}
|
||||
102
widget/windows/nsNativeDragTarget.h
Normal file
102
widget/windows/nsNativeDragTarget.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/* -*- 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/. */
|
||||
#ifndef _nsNativeDragTarget_h_
|
||||
#define _nsNativeDragTarget_h_
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDragSession.h"
|
||||
#include <ole2.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#ifndef IDropTargetHelper
|
||||
#include <shobjidl.h> // Vista drag image interfaces
|
||||
#undef LogSeverity // SetupAPI.h #defines this as DWORD
|
||||
#endif
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
|
||||
class nsIDragService;
|
||||
class nsIWidget;
|
||||
|
||||
/*
|
||||
* nsNativeDragTarget implements the IDropTarget interface and gets most of its
|
||||
* behavior from the associated adapter (m_dragDrop).
|
||||
*/
|
||||
|
||||
class nsNativeDragTarget final : public IDropTarget
|
||||
{
|
||||
public:
|
||||
nsNativeDragTarget(nsIWidget * aWidget);
|
||||
~nsNativeDragTarget();
|
||||
|
||||
// IUnknown members - see iunknown.h for documentation
|
||||
STDMETHODIMP QueryInterface(REFIID, void**);
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
|
||||
// IDataTarget members
|
||||
|
||||
// Set pEffect based on whether this object can support a drop based on
|
||||
// the data available from pSource, the key and mouse states specified
|
||||
// in grfKeyState, and the coordinates specified by point. This is
|
||||
// called by OLE when a drag enters this object's window (as registered
|
||||
// by Initialize).
|
||||
STDMETHODIMP DragEnter(LPDATAOBJECT pSource, DWORD grfKeyState,
|
||||
POINTL point, DWORD* pEffect);
|
||||
|
||||
// Similar to DragEnter except it is called frequently while the drag
|
||||
// is over this object's window.
|
||||
STDMETHODIMP DragOver(DWORD grfKeyState, POINTL point, DWORD* pEffect);
|
||||
|
||||
// Release the drag-drop source and put internal state back to the point
|
||||
// before the call to DragEnter. This is called when the drag leaves
|
||||
// without a drop occurring.
|
||||
STDMETHODIMP DragLeave();
|
||||
|
||||
// If point is within our region of interest and pSource's data supports
|
||||
// one of our formats, get the data and set pEffect according to
|
||||
// grfKeyState (DROPEFFECT_MOVE if the control key was not pressed,
|
||||
// DROPEFFECT_COPY if the control key was pressed). Otherwise return
|
||||
// E_FAIL.
|
||||
STDMETHODIMP Drop(LPDATAOBJECT pSource, DWORD grfKeyState,
|
||||
POINTL point, DWORD* pEffect);
|
||||
/**
|
||||
* Cancel the current drag session, if any.
|
||||
*/
|
||||
void DragCancel();
|
||||
|
||||
protected:
|
||||
|
||||
void GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect,
|
||||
uint32_t * aGeckoAction);
|
||||
void ProcessDrag(mozilla::EventMessage aEventMessage, DWORD grfKeyState,
|
||||
POINTL pt, DWORD* pdwEffect);
|
||||
void DispatchDragDropEvent(mozilla::EventMessage aEventMessage,
|
||||
const POINTL& aPT);
|
||||
void AddLinkSupportIfCanBeGenerated(LPDATAOBJECT aIDataSource);
|
||||
|
||||
// Native Stuff
|
||||
ULONG m_cRef; // reference count
|
||||
HWND mHWnd;
|
||||
DWORD mEffectsAllowed;
|
||||
DWORD mEffectsPreferred;
|
||||
bool mTookOwnRef;
|
||||
|
||||
// Gecko Stuff
|
||||
nsIWidget * mWidget;
|
||||
nsIDragService * mDragService;
|
||||
// Drag target helper
|
||||
IDropTargetHelper * GetDropTargetHelper();
|
||||
|
||||
|
||||
private:
|
||||
// Drag target helper
|
||||
IDropTargetHelper * mDropTargetHelper;
|
||||
};
|
||||
|
||||
#endif // _nsNativeDragTarget_h_
|
||||
|
||||
|
||||
4168
widget/windows/nsNativeThemeWin.cpp
Normal file
4168
widget/windows/nsNativeThemeWin.cpp
Normal file
File diff suppressed because it is too large
Load diff
128
widget/windows/nsNativeThemeWin.h
Normal file
128
widget/windows/nsNativeThemeWin.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsNativeThemeWin_h
|
||||
#define nsNativeThemeWin_h
|
||||
|
||||
#include "nsITheme.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsNativeTheme.h"
|
||||
#include "gfxTypes.h"
|
||||
#include <windows.h>
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsSize.h"
|
||||
|
||||
class nsNativeThemeWin : private nsNativeTheme,
|
||||
public nsITheme {
|
||||
virtual ~nsNativeThemeWin();
|
||||
|
||||
public:
|
||||
typedef mozilla::TimeStamp TimeStamp;
|
||||
typedef mozilla::TimeDuration TimeDuration;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// The nsITheme interface.
|
||||
NS_IMETHOD DrawWidgetBackground(nsRenderingContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aDirtyRect) override;
|
||||
|
||||
NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
nsIntMargin* aResult) override;
|
||||
|
||||
virtual bool GetWidgetPadding(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
nsIntMargin* aResult) override;
|
||||
|
||||
virtual bool GetWidgetOverflow(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
nsRect* aOverflowRect) override;
|
||||
|
||||
NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
mozilla::LayoutDeviceIntSize* aResult,
|
||||
bool* aIsOverridable) override;
|
||||
|
||||
virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) override;
|
||||
|
||||
NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,
|
||||
nsIAtom* aAttribute, bool* aShouldRepaint,
|
||||
const nsAttrValue* aOldValue) override;
|
||||
|
||||
NS_IMETHOD ThemeChanged() override;
|
||||
|
||||
bool ThemeSupportsWidget(nsPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType) override;
|
||||
|
||||
bool WidgetIsContainer(uint8_t aWidgetType) override;
|
||||
|
||||
bool ThemeDrawsFocusForWidget(uint8_t aWidgetType) override;
|
||||
|
||||
bool ThemeNeedsComboboxDropmarker() override;
|
||||
|
||||
virtual bool WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType) override;
|
||||
|
||||
enum {
|
||||
eThemeGeometryTypeWindowButtons = eThemeGeometryTypeUnknown + 1
|
||||
};
|
||||
virtual ThemeGeometryType ThemeGeometryTypeForWidget(nsIFrame* aFrame,
|
||||
uint8_t aWidgetType) override;
|
||||
|
||||
virtual bool ShouldHideScrollbars() override;
|
||||
|
||||
nsNativeThemeWin();
|
||||
|
||||
protected:
|
||||
HANDLE GetTheme(uint8_t aWidgetType);
|
||||
nsresult GetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType,
|
||||
int32_t& aPart, int32_t& aState);
|
||||
nsresult ClassicGetThemePartAndState(nsIFrame* aFrame, uint8_t aWidgetType,
|
||||
int32_t& aPart, int32_t& aState, bool& aFocused);
|
||||
nsresult ClassicDrawWidgetBackground(nsRenderingContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
const nsRect& aRect,
|
||||
const nsRect& aClipRect);
|
||||
nsresult ClassicGetWidgetBorder(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
nsIntMargin* aResult);
|
||||
bool ClassicGetWidgetPadding(nsDeviceContext* aContext,
|
||||
nsIFrame* aFrame,
|
||||
uint8_t aWidgetType,
|
||||
nsIntMargin* aResult);
|
||||
nsresult ClassicGetMinimumWidgetSize(nsIFrame* aFrame, uint8_t aWidgetType,
|
||||
mozilla::LayoutDeviceIntSize* aResult,
|
||||
bool* aIsOverridable);
|
||||
bool ClassicThemeSupportsWidget(nsIFrame* aFrame, uint8_t aWidgetType);
|
||||
void DrawCheckedRect(HDC hdc, const RECT& rc, int32_t fore, int32_t back,
|
||||
HBRUSH defaultBack);
|
||||
uint32_t GetWidgetNativeDrawingFlags(uint8_t aWidgetType);
|
||||
int32_t StandardGetState(nsIFrame* aFrame, uint8_t aWidgetType, bool wantFocused);
|
||||
bool IsMenuActive(nsIFrame* aFrame, uint8_t aWidgetType);
|
||||
RECT CalculateProgressOverlayRect(nsIFrame* aFrame, RECT* aWidgetRect,
|
||||
bool aIsVertical, bool aIsIndeterminate,
|
||||
bool aIsClassic);
|
||||
void DrawThemedProgressMeter(nsIFrame* aFrame, int aWidgetType,
|
||||
HANDLE aTheme, HDC aHdc,
|
||||
int aPart, int aState,
|
||||
RECT* aWidgetRect, RECT* aClipRect,
|
||||
gfxFloat aAppUnits);
|
||||
|
||||
private:
|
||||
TimeStamp mProgressDeterminateTimeStamp;
|
||||
TimeStamp mProgressIndeterminateTimeStamp;
|
||||
};
|
||||
|
||||
#endif
|
||||
162
widget/windows/nsPrintOptionsWin.cpp
Normal file
162
widget/windows/nsPrintOptionsWin.cpp
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/* -*- 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 "nsCOMPtr.h"
|
||||
#include "nsPrintOptionsWin.h"
|
||||
#include "nsPrintSettingsWin.h"
|
||||
#include "nsPrintDialogUtil.h"
|
||||
|
||||
#include "nsGfxCIID.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIWebBrowserPrint.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
const char kPrinterEnumeratorContractID[] = "@mozilla.org/gfx/printerenumerator;1";
|
||||
|
||||
using namespace mozilla::embedding;
|
||||
|
||||
/** ---------------------------------------------------
|
||||
* See documentation in nsPrintOptionsWin.h
|
||||
* @update 6/21/00 dwc
|
||||
*/
|
||||
nsPrintOptionsWin::nsPrintOptionsWin()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** ---------------------------------------------------
|
||||
* See documentation in nsPrintOptionsImpl.h
|
||||
* @update 6/21/00 dwc
|
||||
*/
|
||||
nsPrintOptionsWin::~nsPrintOptionsWin()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintOptionsWin::SerializeToPrintData(nsIPrintSettings* aSettings,
|
||||
nsIWebBrowserPrint* aWBP,
|
||||
PrintData* data)
|
||||
{
|
||||
nsresult rv = nsPrintOptions::SerializeToPrintData(aSettings, aWBP, data);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Windows wants this information for its print dialogs
|
||||
if (aWBP) {
|
||||
aWBP->GetIsFramesetDocument(&data->isFramesetDocument());
|
||||
aWBP->GetIsFramesetFrameSelected(&data->isFramesetFrameSelected());
|
||||
aWBP->GetIsIFrameSelected(&data->isIFrameSelected());
|
||||
aWBP->GetIsRangeSelection(&data->isRangeSelection());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aSettings);
|
||||
if (!psWin) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
char16_t* deviceName;
|
||||
char16_t* driverName;
|
||||
|
||||
psWin->GetDeviceName(&deviceName);
|
||||
psWin->GetDriverName(&driverName);
|
||||
|
||||
data->deviceName().Assign(deviceName);
|
||||
data->driverName().Assign(driverName);
|
||||
|
||||
free(deviceName);
|
||||
free(driverName);
|
||||
|
||||
// When creating the print dialog on Windows, we only need to send certain
|
||||
// print settings information from the parent to the child not vice versa.
|
||||
if (XRE_IsParentProcess()) {
|
||||
psWin->GetPrintableWidthInInches(&data->printableWidthInInches());
|
||||
psWin->GetPrintableHeightInInches(&data->printableHeightInInches());
|
||||
|
||||
// A DEVMODE can actually be of arbitrary size. If it turns out that it'll
|
||||
// make our IPC message larger than the limit, then we'll error out.
|
||||
LPDEVMODEW devModeRaw;
|
||||
psWin->GetDevMode(&devModeRaw); // This actually allocates a copy of the
|
||||
// the nsIPrintSettingsWin DEVMODE, so
|
||||
// we're now responsible for deallocating
|
||||
// it. We'll use an nsAutoDevMode helper
|
||||
// to do this.
|
||||
if (devModeRaw) {
|
||||
nsAutoDevMode devMode(devModeRaw);
|
||||
devModeRaw = nullptr;
|
||||
|
||||
size_t devModeTotalSize = devMode->dmSize + devMode->dmDriverExtra;
|
||||
size_t msgTotalSize = sizeof(PrintData) + devModeTotalSize;
|
||||
|
||||
if (msgTotalSize > IPC::MAX_MESSAGE_SIZE) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Instead of reaching in and manually reading each member, we'll just
|
||||
// copy the bits over.
|
||||
const char* devModeData = reinterpret_cast<const char*>(devMode.get());
|
||||
nsTArray<uint8_t> arrayBuf;
|
||||
arrayBuf.AppendElements(devModeData, devModeTotalSize);
|
||||
data->devModeData().SwapElements(arrayBuf);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintOptionsWin::DeserializeToPrintSettings(const PrintData& data,
|
||||
nsIPrintSettings* settings)
|
||||
{
|
||||
nsresult rv = nsPrintOptions::DeserializeToPrintSettings(data, settings);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(settings);
|
||||
if (!settings) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
psWin->SetDeviceName(data.deviceName().get());
|
||||
psWin->SetDriverName(data.driverName().get());
|
||||
|
||||
psWin->SetPrintableWidthInInches(data.printableWidthInInches());
|
||||
psWin->SetPrintableHeightInInches(data.printableHeightInInches());
|
||||
|
||||
if (data.devModeData().IsEmpty()) {
|
||||
psWin->SetDevMode(nullptr);
|
||||
} else {
|
||||
// Check minimum length of DEVMODE data.
|
||||
auto devModeDataLength = data.devModeData().Length();
|
||||
if (devModeDataLength < sizeof(DEVMODEW)) {
|
||||
NS_WARNING("DEVMODE data is too short.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
DEVMODEW* devMode = reinterpret_cast<DEVMODEW*>(
|
||||
const_cast<uint8_t*>(data.devModeData().Elements()));
|
||||
|
||||
// Check actual length of DEVMODE data.
|
||||
if ((devMode->dmSize + devMode->dmDriverExtra) != devModeDataLength) {
|
||||
NS_WARNING("DEVMODE length is incorrect.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
psWin->SetDevMode(devMode); // Copies
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsPrintOptionsWin::_CreatePrintSettings(nsIPrintSettings **_retval)
|
||||
{
|
||||
*_retval = nullptr;
|
||||
nsPrintSettingsWin* printSettings = new nsPrintSettingsWin(); // does not initially ref count
|
||||
NS_ENSURE_TRUE(printSettings, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
NS_ADDREF(*_retval = printSettings); // ref count
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
36
widget/windows/nsPrintOptionsWin.h
Normal file
36
widget/windows/nsPrintOptionsWin.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; 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/. */
|
||||
|
||||
#ifndef nsPrintOptionsWin_h__
|
||||
#define nsPrintOptionsWin_h__
|
||||
|
||||
#include "mozilla/embedding/PPrinting.h"
|
||||
#include "nsPrintOptionsImpl.h"
|
||||
|
||||
class nsIPrintSettings;
|
||||
class nsIWebBrowserPrint;
|
||||
|
||||
//*****************************************************************************
|
||||
//*** nsPrintOptions
|
||||
//*****************************************************************************
|
||||
class nsPrintOptionsWin : public nsPrintOptions
|
||||
{
|
||||
public:
|
||||
nsPrintOptionsWin();
|
||||
virtual ~nsPrintOptionsWin();
|
||||
|
||||
NS_IMETHODIMP SerializeToPrintData(nsIPrintSettings* aSettings,
|
||||
nsIWebBrowserPrint* aWBP,
|
||||
mozilla::embedding::PrintData* data);
|
||||
NS_IMETHODIMP DeserializeToPrintSettings(const mozilla::embedding::PrintData& data,
|
||||
nsIPrintSettings* settings);
|
||||
|
||||
virtual nsresult _CreatePrintSettings(nsIPrintSettings **_retval);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* nsPrintOptions_h__ */
|
||||
528
widget/windows/nsPrintSettingsWin.cpp
Normal file
528
widget/windows/nsPrintSettingsWin.cpp
Normal file
|
|
@ -0,0 +1,528 @@
|
|||
/* -*- 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 "nsPrintSettingsWin.h"
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
// Using paper sizes from wingdi.h and the units given there, plus a little
|
||||
// extra research for the ones it doesn't give. Looks like the list hasn't
|
||||
// changed since Windows 2000, so should be fairly stable now.
|
||||
const short kPaperSizeUnits[] = {
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // Not Used default to mm as DEVMODE
|
||||
// uses tenths of mm, just in case
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTERSMALL
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_TABLOID
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LEDGER
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LEGAL
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_STATEMENT
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_EXECUTIVE
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4SMALL
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B4
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_FOLIO
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_QUARTO
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_10X14
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_11X17
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_NOTE
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_9
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_10
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_11
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_12
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_14
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_CSHEET
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_DSHEET
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ESHEET
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_DL
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C5
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C3
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C4
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C6
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_C65
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B4
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B5
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_B6
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_ITALY
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_MONARCH
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_ENV_PERSONAL
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_FANFOLD_US
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_FANFOLD_STD_GERMAN
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_FANFOLD_LGL_GERMAN
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ISO_B4
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JAPANESE_POSTCARD
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_9X11
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_10X11
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_15X11
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_ENV_INVITE
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_RESERVED_48
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_RESERVED_49
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_EXTRA
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LEGAL_EXTRA
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_TABLOID_EXTRA
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_A4_EXTRA
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_TRANSVERSE
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_TRANSVERSE
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_EXTRA_TRANSVERSE
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A_PLUS
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B_PLUS
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_PLUS
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_PLUS
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_TRANSVERSE
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_TRANSVERSE
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_EXTRA
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_EXTRA
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_EXTRA
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A2
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_TRANSVERSE
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_EXTRA_TRANSVERSE
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_DBL_JAPANESE_POSTCARD
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A6
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU2
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU3
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU3
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU4
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_LETTER_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A3_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A4_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A5_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B4_JIS_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B5_JIS_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JAPANESE_POSTCARD_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_A6_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU2_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_KAKU3_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU3_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_CHOU4_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B6_JIS
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_B6_JIS_ROTATED
|
||||
nsIPrintSettings::kPaperSizeInches, // DMPAPER_12X11
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_YOU4
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_JENV_YOU4_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P16K
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32K
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32KBIG
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_1
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_2
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_3
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_4
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_5
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_6
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_7
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_8
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_9
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_10
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P16K_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32K_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_P32KBIG_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_1_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_2_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_3_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_4_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_5_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_6_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_7_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_8_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_9_ROTATED
|
||||
nsIPrintSettings::kPaperSizeMillimeters, // DMPAPER_PENV_10_ROTATED
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(nsPrintSettingsWin,
|
||||
nsPrintSettings,
|
||||
nsIPrintSettingsWin)
|
||||
|
||||
/** ---------------------------------------------------
|
||||
* See documentation in nsPrintSettingsWin.h
|
||||
* @update
|
||||
*/
|
||||
nsPrintSettingsWin::nsPrintSettingsWin() :
|
||||
nsPrintSettings(),
|
||||
mDeviceName(nullptr),
|
||||
mDriverName(nullptr),
|
||||
mDevMode(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** ---------------------------------------------------
|
||||
* See documentation in nsPrintSettingsWin.h
|
||||
* @update
|
||||
*/
|
||||
nsPrintSettingsWin::nsPrintSettingsWin(const nsPrintSettingsWin& aPS) :
|
||||
mDeviceName(nullptr),
|
||||
mDriverName(nullptr),
|
||||
mDevMode(nullptr)
|
||||
{
|
||||
*this = aPS;
|
||||
}
|
||||
|
||||
/** ---------------------------------------------------
|
||||
* See documentation in nsPrintSettingsWin.h
|
||||
* @update
|
||||
*/
|
||||
nsPrintSettingsWin::~nsPrintSettingsWin()
|
||||
{
|
||||
if (mDeviceName) free(mDeviceName);
|
||||
if (mDriverName) free(mDriverName);
|
||||
if (mDevMode) ::HeapFree(::GetProcessHeap(), 0, mDevMode);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrintSettingsWin::SetDeviceName(const char16_t * aDeviceName)
|
||||
{
|
||||
if (mDeviceName) {
|
||||
free(mDeviceName);
|
||||
}
|
||||
mDeviceName = aDeviceName?wcsdup(char16ptr_t(aDeviceName)):nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP nsPrintSettingsWin::GetDeviceName(char16_t **aDeviceName)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDeviceName);
|
||||
*aDeviceName = mDeviceName?reinterpret_cast<char16_t*>(wcsdup(mDeviceName)):nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrintSettingsWin::SetDriverName(const char16_t * aDriverName)
|
||||
{
|
||||
if (mDriverName) {
|
||||
free(mDriverName);
|
||||
}
|
||||
mDriverName = aDriverName?wcsdup(char16ptr_t(aDriverName)):nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP nsPrintSettingsWin::GetDriverName(char16_t **aDriverName)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDriverName);
|
||||
*aDriverName = mDriverName?reinterpret_cast<char16_t*>(wcsdup(mDriverName)):nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsPrintSettingsWin::CopyDevMode(DEVMODEW* aInDevMode, DEVMODEW *& aOutDevMode)
|
||||
{
|
||||
aOutDevMode = nullptr;
|
||||
size_t size = aInDevMode->dmSize + aInDevMode->dmDriverExtra;
|
||||
aOutDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, size);
|
||||
if (aOutDevMode) {
|
||||
memcpy(aOutDevMode, aInDevMode, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrintSettingsWin::GetDevMode(DEVMODEW * *aDevMode)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDevMode);
|
||||
|
||||
if (mDevMode) {
|
||||
CopyDevMode(mDevMode, *aDevMode);
|
||||
} else {
|
||||
*aDevMode = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPrintSettingsWin::SetDevMode(DEVMODEW * aDevMode)
|
||||
{
|
||||
if (mDevMode) {
|
||||
::HeapFree(::GetProcessHeap(), 0, mDevMode);
|
||||
mDevMode = nullptr;
|
||||
}
|
||||
|
||||
if (aDevMode) {
|
||||
CopyDevMode(aDevMode, mDevMode);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintSettingsWin::GetPrintableWidthInInches(double* aPrintableWidthInInches)
|
||||
{
|
||||
MOZ_ASSERT(aPrintableWidthInInches);
|
||||
*aPrintableWidthInInches = mPrintableWidthInInches;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintSettingsWin::SetPrintableWidthInInches(double aPrintableWidthInInches)
|
||||
{
|
||||
mPrintableWidthInInches = aPrintableWidthInInches;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintSettingsWin::GetPrintableHeightInInches(double* aPrintableHeightInInches)
|
||||
{
|
||||
MOZ_ASSERT(aPrintableHeightInInches);
|
||||
*aPrintableHeightInInches = mPrintableHeightInInches;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintSettingsWin::SetPrintableHeightInInches(double aPrintableHeightInInches)
|
||||
{
|
||||
mPrintableHeightInInches = aPrintableHeightInInches;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintSettingsWin::GetEffectivePageSize(double *aWidth, double *aHeight)
|
||||
{
|
||||
// If printable page size not set, fall back to nsPrintSettings.
|
||||
if (mPrintableWidthInInches == 0l || mPrintableHeightInInches == 0l) {
|
||||
return nsPrintSettings::GetEffectivePageSize(aWidth, aHeight);
|
||||
}
|
||||
|
||||
if (mOrientation == kPortraitOrientation) {
|
||||
*aWidth = NS_INCHES_TO_TWIPS(mPrintableWidthInInches);
|
||||
*aHeight = NS_INCHES_TO_TWIPS(mPrintableHeightInInches);
|
||||
} else {
|
||||
*aHeight = NS_INCHES_TO_TWIPS(mPrintableWidthInInches);
|
||||
*aWidth = NS_INCHES_TO_TWIPS(mPrintableHeightInInches);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsPrintSettingsWin::CopyFromNative(HDC aHdc, DEVMODEW* aDevMode)
|
||||
{
|
||||
MOZ_ASSERT(aHdc);
|
||||
MOZ_ASSERT(aDevMode);
|
||||
|
||||
mIsInitedFromPrinter = true;
|
||||
if (aDevMode->dmFields & DM_ORIENTATION) {
|
||||
mOrientation = int32_t(aDevMode->dmOrientation == DMORIENT_PORTRAIT
|
||||
? kPortraitOrientation : kLandscapeOrientation);
|
||||
}
|
||||
|
||||
if (aDevMode->dmFields & DM_COPIES) {
|
||||
mNumCopies = aDevMode->dmCopies;
|
||||
}
|
||||
|
||||
// Since we do the scaling, grab their value and reset back to 100.
|
||||
if (aDevMode->dmFields & DM_SCALE) {
|
||||
double scale = double(aDevMode->dmScale) / 100.0f;
|
||||
if (mScaling == 1.0 || scale != 1.0) {
|
||||
mScaling = scale;
|
||||
}
|
||||
aDevMode->dmScale = 100;
|
||||
}
|
||||
|
||||
if (aDevMode->dmFields & DM_PAPERSIZE) {
|
||||
mPaperData = aDevMode->dmPaperSize;
|
||||
// If not a paper size we know about, the unit will be the last one saved.
|
||||
if (mPaperData > 0 &&
|
||||
mPaperData < int32_t(mozilla::ArrayLength(kPaperSizeUnits))) {
|
||||
mPaperSizeUnit = kPaperSizeUnits[mPaperData];
|
||||
}
|
||||
} else {
|
||||
mPaperData = -1;
|
||||
}
|
||||
|
||||
// The length and width in DEVMODE are always in tenths of a millimeter.
|
||||
double sizeUnitToTenthsOfAmm =
|
||||
10L * (mPaperSizeUnit == kPaperSizeInches ? MM_PER_INCH_FLOAT : 1L);
|
||||
if (aDevMode->dmFields & DM_PAPERLENGTH) {
|
||||
mPaperHeight = aDevMode->dmPaperLength / sizeUnitToTenthsOfAmm;
|
||||
} else {
|
||||
mPaperHeight = -1l;
|
||||
}
|
||||
|
||||
if (aDevMode->dmFields & DM_PAPERWIDTH) {
|
||||
mPaperWidth = aDevMode->dmPaperWidth / sizeUnitToTenthsOfAmm;
|
||||
} else {
|
||||
mPaperWidth = -1l;
|
||||
}
|
||||
|
||||
// On Windows we currently create a surface using the printable area of the
|
||||
// page and don't set the unwriteable [sic] margins. Using the unwriteable
|
||||
// margins doesn't appear to work on Windows, but I am not sure if this is a
|
||||
// bug elsewhere in our code or a Windows quirk.
|
||||
// Note: we only scale the printing using the LOGPIXELSY, so we use that
|
||||
// when calculating the surface width as well as the height.
|
||||
int32_t printableWidthInDots = GetDeviceCaps(aHdc, HORZRES);
|
||||
int32_t printableHeightInDots = GetDeviceCaps(aHdc, VERTRES);
|
||||
int32_t heightDPI = GetDeviceCaps(aHdc, LOGPIXELSY);
|
||||
|
||||
// Keep these values in portrait format, so we can reflect our own changes
|
||||
// to mOrientation.
|
||||
if (mOrientation == kPortraitOrientation) {
|
||||
mPrintableWidthInInches = double(printableWidthInDots) / heightDPI;
|
||||
mPrintableHeightInInches = double(printableHeightInDots) / heightDPI;
|
||||
} else {
|
||||
mPrintableHeightInInches = double(printableWidthInDots) / heightDPI;
|
||||
mPrintableWidthInInches = double(printableHeightInDots) / heightDPI;
|
||||
}
|
||||
|
||||
// Using Y to match existing code for print scaling calculations.
|
||||
mResolution = heightDPI;
|
||||
}
|
||||
|
||||
void
|
||||
nsPrintSettingsWin::CopyToNative(DEVMODEW* aDevMode)
|
||||
{
|
||||
MOZ_ASSERT(aDevMode);
|
||||
|
||||
if (mPaperData >= 0) {
|
||||
aDevMode->dmPaperSize = mPaperData;
|
||||
aDevMode->dmFields |= DM_PAPERSIZE;
|
||||
} else {
|
||||
aDevMode->dmPaperSize = 0;
|
||||
aDevMode->dmFields &= ~DM_PAPERSIZE;
|
||||
}
|
||||
|
||||
// The length and width in DEVMODE are always in tenths of a millimeter.
|
||||
double sizeUnitToTenthsOfAmm =
|
||||
10L * (mPaperSizeUnit == kPaperSizeInches ? MM_PER_INCH_FLOAT : 1L);
|
||||
|
||||
// Note: small page sizes can be required here for sticker, label and slide
|
||||
// printers etc. see bug 1271900.
|
||||
if (mPaperHeight > 0) {
|
||||
aDevMode->dmPaperLength = mPaperHeight * sizeUnitToTenthsOfAmm;
|
||||
aDevMode->dmFields |= DM_PAPERLENGTH;
|
||||
} else {
|
||||
aDevMode->dmPaperLength = 0;
|
||||
aDevMode->dmFields &= ~DM_PAPERLENGTH;
|
||||
}
|
||||
|
||||
if (mPaperWidth > 0) {
|
||||
aDevMode->dmPaperWidth = mPaperWidth * sizeUnitToTenthsOfAmm;
|
||||
aDevMode->dmFields |= DM_PAPERWIDTH;
|
||||
} else {
|
||||
aDevMode->dmPaperWidth = 0;
|
||||
aDevMode->dmFields &= ~DM_PAPERWIDTH;
|
||||
}
|
||||
|
||||
// Setup Orientation
|
||||
aDevMode->dmOrientation = mOrientation == kPortraitOrientation
|
||||
? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE;
|
||||
aDevMode->dmFields |= DM_ORIENTATION;
|
||||
|
||||
// Setup Number of Copies
|
||||
aDevMode->dmCopies = mNumCopies;
|
||||
aDevMode->dmFields |= DM_COPIES;
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
nsresult
|
||||
nsPrintSettingsWin::_Clone(nsIPrintSettings **_retval)
|
||||
{
|
||||
RefPtr<nsPrintSettingsWin> printSettings = new nsPrintSettingsWin(*this);
|
||||
printSettings.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
nsPrintSettingsWin& nsPrintSettingsWin::operator=(const nsPrintSettingsWin& rhs)
|
||||
{
|
||||
if (this == &rhs) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
((nsPrintSettings&) *this) = rhs;
|
||||
|
||||
if (mDeviceName) {
|
||||
free(mDeviceName);
|
||||
}
|
||||
|
||||
if (mDriverName) {
|
||||
free(mDriverName);
|
||||
}
|
||||
|
||||
// Use free because we used the native malloc to create the memory
|
||||
if (mDevMode) {
|
||||
::HeapFree(::GetProcessHeap(), 0, mDevMode);
|
||||
}
|
||||
|
||||
mDeviceName = rhs.mDeviceName?wcsdup(rhs.mDeviceName):nullptr;
|
||||
mDriverName = rhs.mDriverName?wcsdup(rhs.mDriverName):nullptr;
|
||||
|
||||
if (rhs.mDevMode) {
|
||||
CopyDevMode(rhs.mDevMode, mDevMode);
|
||||
} else {
|
||||
mDevMode = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
nsresult
|
||||
nsPrintSettingsWin::_Assign(nsIPrintSettings *aPS)
|
||||
{
|
||||
nsPrintSettingsWin *psWin = static_cast<nsPrintSettingsWin*>(aPS);
|
||||
*this = *psWin;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Testing of assign and clone
|
||||
// This define turns on the testing module below
|
||||
// so at start up it writes and reads the prefs.
|
||||
#ifdef DEBUG_rodsX
|
||||
#include "nsIPrintOptions.h"
|
||||
#include "nsIServiceManager.h"
|
||||
class Tester {
|
||||
public:
|
||||
Tester();
|
||||
};
|
||||
Tester::Tester()
|
||||
{
|
||||
nsCOMPtr<nsIPrintSettings> ps;
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrintOptions> printService = do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = printService->CreatePrintSettings(getter_AddRefs(ps));
|
||||
}
|
||||
|
||||
if (ps) {
|
||||
ps->SetPrintOptions(nsIPrintSettings::kPrintOddPages, true);
|
||||
ps->SetPrintOptions(nsIPrintSettings::kPrintEvenPages, false);
|
||||
ps->SetMarginTop(1.0);
|
||||
ps->SetMarginLeft(1.0);
|
||||
ps->SetMarginBottom(1.0);
|
||||
ps->SetMarginRight(1.0);
|
||||
ps->SetScaling(0.5);
|
||||
ps->SetPrintBGColors(true);
|
||||
ps->SetPrintBGImages(true);
|
||||
ps->SetPrintRange(15);
|
||||
ps->SetHeaderStrLeft(NS_ConvertUTF8toUTF16("Left").get());
|
||||
ps->SetHeaderStrCenter(NS_ConvertUTF8toUTF16("Center").get());
|
||||
ps->SetHeaderStrRight(NS_ConvertUTF8toUTF16("Right").get());
|
||||
ps->SetFooterStrLeft(NS_ConvertUTF8toUTF16("Left").get());
|
||||
ps->SetFooterStrCenter(NS_ConvertUTF8toUTF16("Center").get());
|
||||
ps->SetFooterStrRight(NS_ConvertUTF8toUTF16("Right").get());
|
||||
ps->SetPaperName(NS_ConvertUTF8toUTF16("Paper Name").get());
|
||||
ps->SetPaperData(1);
|
||||
ps->SetPaperWidth(100.0);
|
||||
ps->SetPaperHeight(50.0);
|
||||
ps->SetPaperSizeUnit(nsIPrintSettings::kPaperSizeMillimeters);
|
||||
ps->SetPrintReversed(true);
|
||||
ps->SetPrintInColor(true);
|
||||
ps->SetOrientation(nsIPrintSettings::kLandscapeOrientation);
|
||||
ps->SetPrintCommand(NS_ConvertUTF8toUTF16("Command").get());
|
||||
ps->SetNumCopies(2);
|
||||
ps->SetPrinterName(NS_ConvertUTF8toUTF16("Printer Name").get());
|
||||
ps->SetPrintToFile(true);
|
||||
ps->SetToFileName(NS_ConvertUTF8toUTF16("File Name").get());
|
||||
ps->SetPrintPageDelay(1000);
|
||||
|
||||
nsCOMPtr<nsIPrintSettings> ps2;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = printService->CreatePrintSettings(getter_AddRefs(ps2));
|
||||
}
|
||||
|
||||
ps2->Assign(ps);
|
||||
|
||||
nsCOMPtr<nsIPrintSettings> psClone;
|
||||
ps2->Clone(getter_AddRefs(psClone));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Tester gTester;
|
||||
#endif
|
||||
59
widget/windows/nsPrintSettingsWin.h
Normal file
59
widget/windows/nsPrintSettingsWin.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- Mode: IDL; tab-width: 4; 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/. */
|
||||
|
||||
#ifndef nsPrintSettingsWin_h__
|
||||
#define nsPrintSettingsWin_h__
|
||||
|
||||
#include "nsPrintSettingsImpl.h"
|
||||
#include "nsIPrintSettingsWin.h"
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//*** nsPrintSettingsWin
|
||||
//*****************************************************************************
|
||||
class nsPrintSettingsWin : public nsPrintSettings,
|
||||
public nsIPrintSettingsWin
|
||||
{
|
||||
virtual ~nsPrintSettingsWin();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIPRINTSETTINGSWIN
|
||||
|
||||
nsPrintSettingsWin();
|
||||
nsPrintSettingsWin(const nsPrintSettingsWin& aPS);
|
||||
|
||||
/**
|
||||
* Makes a new copy
|
||||
*/
|
||||
virtual nsresult _Clone(nsIPrintSettings **_retval);
|
||||
|
||||
/**
|
||||
* Assigns values
|
||||
*/
|
||||
virtual nsresult _Assign(nsIPrintSettings* aPS);
|
||||
|
||||
/**
|
||||
* Assignment
|
||||
*/
|
||||
nsPrintSettingsWin& operator=(const nsPrintSettingsWin& rhs);
|
||||
|
||||
NS_IMETHOD GetEffectivePageSize(double *aWidth, double *aHeight) override;
|
||||
|
||||
protected:
|
||||
void CopyDevMode(DEVMODEW* aInDevMode, DEVMODEW *& aOutDevMode);
|
||||
|
||||
wchar_t* mDeviceName;
|
||||
wchar_t* mDriverName;
|
||||
LPDEVMODEW mDevMode;
|
||||
double mPrintableWidthInInches = 0l;
|
||||
double mPrintableHeightInInches = 0l;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* nsPrintSettingsWin_h__ */
|
||||
181
widget/windows/nsScreenManagerWin.cpp
Normal file
181
widget/windows/nsScreenManagerWin.cpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/* -*- 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 "nsScreenManagerWin.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "nsScreenWin.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "WinUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
BOOL CALLBACK CountMonitors(HMONITOR, HDC, LPRECT, LPARAM ioCount);
|
||||
|
||||
nsScreenManagerWin::nsScreenManagerWin()
|
||||
: mNumberOfScreens(0)
|
||||
{
|
||||
// nothing to do. I guess we could cache a bunch of information
|
||||
// here, but we want to ask the device at runtime in case anything
|
||||
// has changed.
|
||||
}
|
||||
|
||||
|
||||
nsScreenManagerWin::~nsScreenManagerWin()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// addref, release, QI
|
||||
NS_IMPL_ISUPPORTS(nsScreenManagerWin, nsIScreenManager)
|
||||
|
||||
|
||||
//
|
||||
// CreateNewScreenObject
|
||||
//
|
||||
// Utility routine. Creates a new screen object from the given device handle
|
||||
//
|
||||
// NOTE: For this "single-monitor" impl, we just always return the cached primary
|
||||
// screen. This should change when a multi-monitor impl is done.
|
||||
//
|
||||
nsIScreen*
|
||||
nsScreenManagerWin::CreateNewScreenObject(HMONITOR inScreen)
|
||||
{
|
||||
nsIScreen* retScreen = nullptr;
|
||||
|
||||
// look through our screen list, hoping to find it. If it's not there,
|
||||
// add it and return the new one.
|
||||
for (unsigned i = 0; i < mScreenList.Length(); ++i) {
|
||||
ScreenListItem& curr = mScreenList[i];
|
||||
if (inScreen == curr.mMon) {
|
||||
NS_IF_ADDREF(retScreen = curr.mScreen.get());
|
||||
return retScreen;
|
||||
}
|
||||
} // for each screen.
|
||||
|
||||
retScreen = new nsScreenWin(inScreen);
|
||||
mScreenList.AppendElement(ScreenListItem(inScreen, retScreen));
|
||||
|
||||
NS_IF_ADDREF(retScreen);
|
||||
return retScreen;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenManagerWin::ScreenForId(uint32_t aId, nsIScreen **outScreen)
|
||||
{
|
||||
*outScreen = nullptr;
|
||||
|
||||
for (unsigned i = 0; i < mScreenList.Length(); ++i) {
|
||||
ScreenListItem& curr = mScreenList[i];
|
||||
uint32_t id;
|
||||
nsresult rv = curr.mScreen->GetId(&id);
|
||||
if (NS_SUCCEEDED(rv) && id == aId) {
|
||||
NS_IF_ADDREF(*outScreen = curr.mScreen.get());
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//
|
||||
// ScreenForRect
|
||||
//
|
||||
// Returns the screen that contains the rectangle. If the rect overlaps
|
||||
// multiple screens, it picks the screen with the greatest area of intersection.
|
||||
//
|
||||
// The coordinates are in pixels (not twips) and in logical screen coordinates.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsScreenManagerWin::ScreenForRect(int32_t inLeft, int32_t inTop,
|
||||
int32_t inWidth, int32_t inHeight,
|
||||
nsIScreen **outScreen)
|
||||
{
|
||||
if (!(inWidth || inHeight)) {
|
||||
NS_WARNING("trying to find screen for sizeless window, using primary monitor");
|
||||
*outScreen = CreateNewScreenObject(nullptr); // addrefs
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
gfx::Rect logicalBounds(inLeft, inTop, inWidth, inHeight);
|
||||
HMONITOR genScreen = widget::WinUtils::MonitorFromRect(logicalBounds);
|
||||
|
||||
*outScreen = CreateNewScreenObject(genScreen); // addrefs
|
||||
|
||||
return NS_OK;
|
||||
|
||||
} // ScreenForRect
|
||||
|
||||
|
||||
//
|
||||
// GetPrimaryScreen
|
||||
//
|
||||
// The screen with the menubar/taskbar. This shouldn't be needed very
|
||||
// often.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsScreenManagerWin::GetPrimaryScreen(nsIScreen** aPrimaryScreen)
|
||||
{
|
||||
*aPrimaryScreen = CreateNewScreenObject(nullptr); // addrefs
|
||||
return NS_OK;
|
||||
|
||||
} // GetPrimaryScreen
|
||||
|
||||
|
||||
//
|
||||
// CountMonitors
|
||||
//
|
||||
// Will be called once for every monitor in the system. Just
|
||||
// increments the parameter, which holds a ptr to a PRUin32 holding the
|
||||
// count up to this point.
|
||||
//
|
||||
BOOL CALLBACK
|
||||
CountMonitors(HMONITOR, HDC, LPRECT, LPARAM ioParam)
|
||||
{
|
||||
uint32_t* countPtr = reinterpret_cast<uint32_t*>(ioParam);
|
||||
++(*countPtr);
|
||||
|
||||
return TRUE; // continue the enumeration
|
||||
|
||||
} // CountMonitors
|
||||
|
||||
|
||||
//
|
||||
// GetNumberOfScreens
|
||||
//
|
||||
// Returns how many physical screens are available.
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsScreenManagerWin::GetNumberOfScreens(uint32_t *aNumberOfScreens)
|
||||
{
|
||||
if (mNumberOfScreens)
|
||||
*aNumberOfScreens = mNumberOfScreens;
|
||||
else {
|
||||
uint32_t count = 0;
|
||||
BOOL result = ::EnumDisplayMonitors(nullptr, nullptr, (MONITORENUMPROC)CountMonitors, (LPARAM)&count);
|
||||
if (!result)
|
||||
return NS_ERROR_FAILURE;
|
||||
*aNumberOfScreens = mNumberOfScreens = count;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
} // GetNumberOfScreens
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenManagerWin::GetSystemDefaultScale(float *aDefaultScale)
|
||||
{
|
||||
HMONITOR primary = widget::WinUtils::GetPrimaryMonitor();
|
||||
*aDefaultScale = float(widget::WinUtils::LogToPhysFactor(primary));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenManagerWin::ScreenForNativeWidget(void *aWidget, nsIScreen **outScreen)
|
||||
{
|
||||
HMONITOR mon = MonitorFromWindow((HWND) aWidget, MONITOR_DEFAULTTOPRIMARY);
|
||||
*outScreen = CreateNewScreenObject(mon);
|
||||
return NS_OK;
|
||||
}
|
||||
50
widget/windows/nsScreenManagerWin.h
Normal file
50
widget/windows/nsScreenManagerWin.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsScreenManagerWin_h___
|
||||
#define nsScreenManagerWin_h___
|
||||
|
||||
#include "nsIScreenManager.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIScreen;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
class ScreenListItem
|
||||
{
|
||||
public:
|
||||
ScreenListItem ( HMONITOR inMon, nsIScreen* inScreen )
|
||||
: mMon(inMon), mScreen(inScreen) { } ;
|
||||
|
||||
HMONITOR mMon;
|
||||
nsCOMPtr<nsIScreen> mScreen;
|
||||
};
|
||||
|
||||
class nsScreenManagerWin final : public nsIScreenManager
|
||||
{
|
||||
public:
|
||||
nsScreenManagerWin ( );
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISCREENMANAGER
|
||||
|
||||
private:
|
||||
~nsScreenManagerWin();
|
||||
|
||||
nsIScreen* CreateNewScreenObject ( HMONITOR inScreen ) ;
|
||||
|
||||
uint32_t mNumberOfScreens;
|
||||
|
||||
// cache the screens to avoid the memory allocations
|
||||
AutoTArray<ScreenListItem, 8> mScreenList;
|
||||
|
||||
};
|
||||
|
||||
#endif // nsScreenManagerWin_h___
|
||||
199
widget/windows/nsScreenWin.cpp
Normal file
199
widget/windows/nsScreenWin.cpp
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/* -*- 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 "nsScreenWin.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "WinUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static uint32_t sScreenId;
|
||||
|
||||
nsScreenWin::nsScreenWin(HMONITOR inScreen)
|
||||
: mScreen(inScreen)
|
||||
, mId(++sScreenId)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
HDC hDCScreen = ::GetDC(nullptr);
|
||||
NS_ASSERTION(hDCScreen,"GetDC Failure");
|
||||
NS_ASSERTION(::GetDeviceCaps(hDCScreen, TECHNOLOGY) == DT_RASDISPLAY, "Not a display screen");
|
||||
::ReleaseDC(nullptr,hDCScreen);
|
||||
#endif
|
||||
|
||||
// nothing else to do. I guess we could cache a bunch of information
|
||||
// here, but we want to ask the device at runtime in case anything
|
||||
// has changed.
|
||||
}
|
||||
|
||||
|
||||
nsScreenWin::~nsScreenWin()
|
||||
{
|
||||
// nothing to see here.
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenWin::GetId(uint32_t *outId)
|
||||
{
|
||||
*outId = mId;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenWin::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
|
||||
{
|
||||
BOOL success = FALSE;
|
||||
if (mScreen) {
|
||||
MONITORINFO info;
|
||||
info.cbSize = sizeof(MONITORINFO);
|
||||
success = ::GetMonitorInfoW(mScreen, &info);
|
||||
if (success) {
|
||||
*outLeft = info.rcMonitor.left;
|
||||
*outTop = info.rcMonitor.top;
|
||||
*outWidth = info.rcMonitor.right - info.rcMonitor.left;
|
||||
*outHeight = info.rcMonitor.bottom - info.rcMonitor.top;
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
HDC hDCScreen = ::GetDC(nullptr);
|
||||
NS_ASSERTION(hDCScreen,"GetDC Failure");
|
||||
|
||||
*outTop = *outLeft = 0;
|
||||
*outWidth = ::GetDeviceCaps(hDCScreen, HORZRES);
|
||||
*outHeight = ::GetDeviceCaps(hDCScreen, VERTRES);
|
||||
|
||||
::ReleaseDC(nullptr, hDCScreen);
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
} // GetRect
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenWin::GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight)
|
||||
{
|
||||
BOOL success = FALSE;
|
||||
|
||||
if (mScreen) {
|
||||
MONITORINFO info;
|
||||
info.cbSize = sizeof(MONITORINFO);
|
||||
success = ::GetMonitorInfoW(mScreen, &info);
|
||||
if (success) {
|
||||
*outLeft = info.rcWork.left;
|
||||
*outTop = info.rcWork.top;
|
||||
*outWidth = info.rcWork.right - info.rcWork.left;
|
||||
*outHeight = info.rcWork.bottom - info.rcWork.top;
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
RECT workArea;
|
||||
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
|
||||
*outLeft = workArea.left;
|
||||
*outTop = workArea.top;
|
||||
*outWidth = workArea.right - workArea.left;
|
||||
*outHeight = workArea.bottom - workArea.top;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
} // GetAvailRect
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenWin::GetRectDisplayPix(int32_t *outLeft, int32_t *outTop,
|
||||
int32_t *outWidth, int32_t *outHeight)
|
||||
{
|
||||
if (widget::WinUtils::IsPerMonitorDPIAware()) {
|
||||
// on per-monitor-dpi config, display pixels are device pixels
|
||||
return GetRect(outLeft, outTop, outWidth, outHeight);
|
||||
}
|
||||
int32_t left, top, width, height;
|
||||
nsresult rv = GetRect(&left, &top, &width, &height);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
double scaleFactor = 1.0 / widget::WinUtils::LogToPhysFactor(mScreen);
|
||||
*outLeft = NSToIntRound(left * scaleFactor);
|
||||
*outTop = NSToIntRound(top * scaleFactor);
|
||||
*outWidth = NSToIntRound(width * scaleFactor);
|
||||
*outHeight = NSToIntRound(height * scaleFactor);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenWin::GetAvailRectDisplayPix(int32_t *outLeft, int32_t *outTop,
|
||||
int32_t *outWidth, int32_t *outHeight)
|
||||
{
|
||||
if (widget::WinUtils::IsPerMonitorDPIAware()) {
|
||||
// on per-monitor-dpi config, display pixels are device pixels
|
||||
return GetAvailRect(outLeft, outTop, outWidth, outHeight);
|
||||
}
|
||||
int32_t left, top, width, height;
|
||||
nsresult rv = GetAvailRect(&left, &top, &width, &height);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
double scaleFactor = 1.0 / widget::WinUtils::LogToPhysFactor(mScreen);
|
||||
*outLeft = NSToIntRound(left * scaleFactor);
|
||||
*outTop = NSToIntRound(top * scaleFactor);
|
||||
*outWidth = NSToIntRound(width * scaleFactor);
|
||||
*outHeight = NSToIntRound(height * scaleFactor);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenWin :: GetPixelDepth(int32_t *aPixelDepth)
|
||||
{
|
||||
//XXX not sure how to get this info for multiple monitors, this might be ok...
|
||||
HDC hDCScreen = ::GetDC(nullptr);
|
||||
NS_ASSERTION(hDCScreen,"GetDC Failure");
|
||||
|
||||
int32_t depth = ::GetDeviceCaps(hDCScreen, BITSPIXEL);
|
||||
if (depth == 32) {
|
||||
// If a device uses 32 bits per pixel, it's still only using 8 bits
|
||||
// per color component, which is what our callers want to know.
|
||||
// (Some devices report 32 and some devices report 24.)
|
||||
depth = 24;
|
||||
}
|
||||
*aPixelDepth = depth;
|
||||
|
||||
::ReleaseDC(nullptr, hDCScreen);
|
||||
return NS_OK;
|
||||
|
||||
} // GetPixelDepth
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenWin::GetColorDepth(int32_t *aColorDepth)
|
||||
{
|
||||
return GetPixelDepth(aColorDepth);
|
||||
|
||||
} // GetColorDepth
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenWin::GetContentsScaleFactor(double *aContentsScaleFactor)
|
||||
{
|
||||
if (widget::WinUtils::IsPerMonitorDPIAware()) {
|
||||
*aContentsScaleFactor = 1.0;
|
||||
} else {
|
||||
*aContentsScaleFactor = widget::WinUtils::LogToPhysFactor(mScreen);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScreenWin::GetDefaultCSSScaleFactor(double* aScaleFactor)
|
||||
{
|
||||
double scale = nsIWidget::DefaultScaleOverride();
|
||||
if (scale > 0.0) {
|
||||
*aScaleFactor = scale;
|
||||
} else {
|
||||
*aScaleFactor = widget::WinUtils::LogToPhysFactor(mScreen);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
45
widget/windows/nsScreenWin.h
Normal file
45
widget/windows/nsScreenWin.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsScreenWin_h___
|
||||
#define nsScreenWin_h___
|
||||
|
||||
#include <windows.h>
|
||||
#include "nsBaseScreen.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
class nsScreenWin final : public nsBaseScreen
|
||||
{
|
||||
public:
|
||||
nsScreenWin ( HMONITOR inScreen );
|
||||
~nsScreenWin();
|
||||
|
||||
NS_IMETHOD GetId(uint32_t* aId);
|
||||
|
||||
// These methods return the size in device (physical) pixels
|
||||
NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
|
||||
NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
|
||||
|
||||
// And these methods get the screen size in 'desktop pixels' (AKA 'logical pixels')
|
||||
// that are dependent on the logical DPI setting in windows
|
||||
NS_IMETHOD GetRectDisplayPix(int32_t *outLeft, int32_t *outTop,
|
||||
int32_t *outWidth, int32_t *outHeight);
|
||||
NS_IMETHOD GetAvailRectDisplayPix(int32_t *outLeft, int32_t *outTop,
|
||||
int32_t *outWidth, int32_t *outHeight);
|
||||
|
||||
NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth);
|
||||
NS_IMETHOD GetColorDepth(int32_t* aColorDepth);
|
||||
|
||||
NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor) override;
|
||||
|
||||
NS_IMETHOD GetDefaultCSSScaleFactor(double* aScaleFactor) override;
|
||||
|
||||
private:
|
||||
HMONITOR mScreen;
|
||||
uint32_t mId;
|
||||
};
|
||||
|
||||
#endif // nsScreenWin_h___
|
||||
305
widget/windows/nsSound.cpp
Normal file
305
widget/windows/nsSound.cpp
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
/* -*- 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 "nscore.h"
|
||||
#include "plstr.h"
|
||||
#include <stdio.h>
|
||||
#include "nsString.h"
|
||||
#include <windows.h>
|
||||
|
||||
// mmsystem.h is needed to build with WIN32_LEAN_AND_MEAN
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include "nsSound.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "prtime.h"
|
||||
#include "prprf.h"
|
||||
#include "prmem.h"
|
||||
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using mozilla::LogLevel;
|
||||
|
||||
PRLogModuleInfo* gWin32SoundLog = nullptr;
|
||||
|
||||
class nsSoundPlayer: public mozilla::Runnable {
|
||||
public:
|
||||
nsSoundPlayer(nsSound *aSound, const wchar_t* aSoundName) :
|
||||
mSoundName(aSoundName), mSound(aSound)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
nsSoundPlayer(nsSound *aSound, const nsAString& aSoundName) :
|
||||
mSoundName(aSoundName), mSound(aSound)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
protected:
|
||||
nsString mSoundName;
|
||||
nsSound *mSound; // Strong, but this will be released from SoundReleaser.
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
|
||||
void Init()
|
||||
{
|
||||
NS_GetCurrentThread(getter_AddRefs(mThread));
|
||||
NS_ASSERTION(mThread, "failed to get current thread");
|
||||
NS_IF_ADDREF(mSound);
|
||||
}
|
||||
|
||||
class SoundReleaser: public mozilla::Runnable {
|
||||
public:
|
||||
SoundReleaser(nsSound* aSound) :
|
||||
mSound(aSound)
|
||||
{
|
||||
}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
protected:
|
||||
nsSound *mSound;
|
||||
};
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSoundPlayer::Run()
|
||||
{
|
||||
PR_SetCurrentThreadName("Play Sound");
|
||||
|
||||
NS_PRECONDITION(!mSoundName.IsEmpty(), "Sound name should not be empty");
|
||||
::PlaySoundW(mSoundName.get(), nullptr,
|
||||
SND_NODEFAULT | SND_ALIAS | SND_ASYNC);
|
||||
nsCOMPtr<nsIRunnable> releaser = new SoundReleaser(mSound);
|
||||
// Don't release nsSound from here, because here is not an owning thread of
|
||||
// the nsSound. nsSound must be released in its owning thread.
|
||||
mThread->Dispatch(releaser, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSoundPlayer::SoundReleaser::Run()
|
||||
{
|
||||
mSound->ShutdownOldPlayerThread();
|
||||
NS_IF_RELEASE(mSound);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SND_PURGE
|
||||
// Not available on Windows CE, and according to MSDN
|
||||
// doesn't do anything on recent windows either.
|
||||
#define SND_PURGE 0
|
||||
#endif
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSound, nsISound, nsIStreamLoaderObserver)
|
||||
|
||||
|
||||
nsSound::nsSound()
|
||||
{
|
||||
if (!gWin32SoundLog) {
|
||||
gWin32SoundLog = PR_NewLogModule("nsSound");
|
||||
}
|
||||
|
||||
mLastSound = nullptr;
|
||||
}
|
||||
|
||||
nsSound::~nsSound()
|
||||
{
|
||||
NS_ASSERTION(!mPlayerThread, "player thread is not null but should be");
|
||||
PurgeLastSound();
|
||||
}
|
||||
|
||||
void nsSound::ShutdownOldPlayerThread()
|
||||
{
|
||||
nsCOMPtr<nsIThread> playerThread(mPlayerThread.forget());
|
||||
if (playerThread)
|
||||
playerThread->Shutdown();
|
||||
}
|
||||
|
||||
void nsSound::PurgeLastSound()
|
||||
{
|
||||
if (mLastSound) {
|
||||
// Halt any currently playing sound.
|
||||
::PlaySound(nullptr, nullptr, SND_PURGE);
|
||||
|
||||
// Now delete the buffer.
|
||||
free(mLastSound);
|
||||
mLastSound = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsSound::Beep()
|
||||
{
|
||||
::MessageBeep(0);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
|
||||
nsISupports *context,
|
||||
nsresult aStatus,
|
||||
uint32_t dataLen,
|
||||
const uint8_t *data)
|
||||
{
|
||||
// print a load error on bad status
|
||||
if (NS_FAILED(aStatus)) {
|
||||
#ifdef DEBUG
|
||||
if (aLoader) {
|
||||
nsCOMPtr<nsIRequest> request;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
aLoader->GetRequest(getter_AddRefs(request));
|
||||
if (request)
|
||||
channel = do_QueryInterface(request);
|
||||
if (channel) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
channel->GetURI(getter_AddRefs(uri));
|
||||
if (uri) {
|
||||
nsAutoCString uriSpec;
|
||||
uri->GetSpec(uriSpec);
|
||||
MOZ_LOG(gWin32SoundLog, LogLevel::Info,
|
||||
("Failed to load %s\n", uriSpec.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return aStatus;
|
||||
}
|
||||
|
||||
ShutdownOldPlayerThread();
|
||||
PurgeLastSound();
|
||||
|
||||
if (data && dataLen > 0) {
|
||||
DWORD flags = SND_MEMORY | SND_NODEFAULT;
|
||||
// We try to make a copy so we can play it async.
|
||||
mLastSound = (uint8_t *) malloc(dataLen);
|
||||
if (mLastSound) {
|
||||
memcpy(mLastSound, data, dataLen);
|
||||
data = mLastSound;
|
||||
flags |= SND_ASYNC;
|
||||
}
|
||||
::PlaySoundW(reinterpret_cast<LPCWSTR>(data), 0, flags);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsSound::Play(nsIURL *aURL)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
#ifdef DEBUG_SOUND
|
||||
char *url;
|
||||
aURL->GetSpec(&url);
|
||||
MOZ_LOG(gWin32SoundLog, LogLevel::Info,
|
||||
("%s\n", url));
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIStreamLoader> loader;
|
||||
rv = NS_NewStreamLoader(getter_AddRefs(loader),
|
||||
aURL,
|
||||
this, // aObserver
|
||||
nsContentUtils::GetSystemPrincipal(),
|
||||
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
|
||||
nsIContentPolicy::TYPE_OTHER);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsSound::Init()
|
||||
{
|
||||
// This call halts a sound if it was still playing.
|
||||
// We have to use the sound library for something to make sure
|
||||
// it is initialized.
|
||||
// If we wait until the first sound is played, there will
|
||||
// be a time lag as the library gets loaded.
|
||||
::PlaySound(nullptr, nullptr, SND_PURGE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias)
|
||||
{
|
||||
ShutdownOldPlayerThread();
|
||||
PurgeLastSound();
|
||||
|
||||
if (!NS_IsMozAliasSound(aSoundAlias)) {
|
||||
if (aSoundAlias.IsEmpty())
|
||||
return NS_OK;
|
||||
nsCOMPtr<nsIRunnable> player = new nsSoundPlayer(this, aSoundAlias);
|
||||
NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(mPlayerThread), player);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_WARNING("nsISound::playSystemSound is called with \"_moz_\" events, they are obsolete, use nsISound::playEventSound instead");
|
||||
|
||||
uint32_t eventId;
|
||||
if (aSoundAlias.Equals(NS_SYSSOUND_MAIL_BEEP))
|
||||
eventId = EVENT_NEW_MAIL_RECEIVED;
|
||||
else if (aSoundAlias.Equals(NS_SYSSOUND_CONFIRM_DIALOG))
|
||||
eventId = EVENT_CONFIRM_DIALOG_OPEN;
|
||||
else if (aSoundAlias.Equals(NS_SYSSOUND_ALERT_DIALOG))
|
||||
eventId = EVENT_ALERT_DIALOG_OPEN;
|
||||
else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_EXECUTE))
|
||||
eventId = EVENT_MENU_EXECUTE;
|
||||
else if (aSoundAlias.Equals(NS_SYSSOUND_MENU_POPUP))
|
||||
eventId = EVENT_MENU_POPUP;
|
||||
else
|
||||
return NS_OK;
|
||||
|
||||
return PlayEventSound(eventId);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsSound::PlayEventSound(uint32_t aEventId)
|
||||
{
|
||||
ShutdownOldPlayerThread();
|
||||
PurgeLastSound();
|
||||
|
||||
const wchar_t *sound = nullptr;
|
||||
switch (aEventId) {
|
||||
case EVENT_NEW_MAIL_RECEIVED:
|
||||
sound = L"MailBeep";
|
||||
break;
|
||||
case EVENT_ALERT_DIALOG_OPEN:
|
||||
sound = L"SystemExclamation";
|
||||
break;
|
||||
case EVENT_CONFIRM_DIALOG_OPEN:
|
||||
sound = L"SystemQuestion";
|
||||
break;
|
||||
case EVENT_MENU_EXECUTE:
|
||||
sound = L"MenuCommand";
|
||||
break;
|
||||
case EVENT_MENU_POPUP:
|
||||
sound = L"MenuPopup";
|
||||
break;
|
||||
case EVENT_EDITOR_MAX_LEN:
|
||||
sound = L".Default";
|
||||
break;
|
||||
default:
|
||||
// Win32 plays no sounds at NS_SYSSOUND_PROMPT_DIALOG and
|
||||
// NS_SYSSOUND_SELECT_DIALOG.
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ASSERTION(sound, "sound is null");
|
||||
|
||||
nsCOMPtr<nsIRunnable> player = new nsSoundPlayer(this, sound);
|
||||
NS_ENSURE_TRUE(player, NS_ERROR_OUT_OF_MEMORY);
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(mPlayerThread), player);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
37
widget/windows/nsSound.h
Normal file
37
widget/windows/nsSound.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef __nsSound_h__
|
||||
#define __nsSound_h__
|
||||
|
||||
#include "nsISound.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIThread;
|
||||
|
||||
class nsSound : public nsISound,
|
||||
public nsIStreamLoaderObserver
|
||||
|
||||
{
|
||||
public:
|
||||
nsSound();
|
||||
void ShutdownOldPlayerThread();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISOUND
|
||||
NS_DECL_NSISTREAMLOADEROBSERVER
|
||||
|
||||
private:
|
||||
virtual ~nsSound();
|
||||
void PurgeLastSound();
|
||||
|
||||
private:
|
||||
uint8_t* mLastSound;
|
||||
nsCOMPtr<nsIThread> mPlayerThread;
|
||||
};
|
||||
|
||||
#endif /* __nsSound_h__ */
|
||||
81
widget/windows/nsToolkit.cpp
Normal file
81
widget/windows/nsToolkit.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- 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 "nsToolkit.h"
|
||||
#include "nsAppShell.h"
|
||||
#include "nsWindow.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "prmon.h"
|
||||
#include "prtime.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include <objbase.h>
|
||||
#include "WinUtils.h"
|
||||
|
||||
#include "nsUXThemeData.h"
|
||||
|
||||
// unknwn.h is needed to build with WIN32_LEAN_AND_MEAN
|
||||
#include <unknwn.h>
|
||||
|
||||
using namespace mozilla::widget;
|
||||
|
||||
nsToolkit* nsToolkit::gToolkit = nullptr;
|
||||
HINSTANCE nsToolkit::mDllInstance = 0;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// constructor
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
nsToolkit::nsToolkit()
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsToolkit);
|
||||
|
||||
#if defined(MOZ_STATIC_COMPONENT_LIBS)
|
||||
nsToolkit::Startup(GetModuleHandle(nullptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// destructor
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
nsToolkit::~nsToolkit()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsToolkit);
|
||||
}
|
||||
|
||||
void
|
||||
nsToolkit::Startup(HMODULE hModule)
|
||||
{
|
||||
nsToolkit::mDllInstance = hModule;
|
||||
WinUtils::Initialize();
|
||||
nsUXThemeData::Initialize();
|
||||
}
|
||||
|
||||
void
|
||||
nsToolkit::Shutdown()
|
||||
{
|
||||
delete gToolkit;
|
||||
gToolkit = nullptr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Return the nsToolkit for the current thread. If a toolkit does not
|
||||
// yet exist, then one will be created...
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// static
|
||||
nsToolkit* nsToolkit::GetToolkit()
|
||||
{
|
||||
if (!gToolkit) {
|
||||
gToolkit = new nsToolkit();
|
||||
}
|
||||
|
||||
return gToolkit;
|
||||
}
|
||||
49
widget/windows/nsToolkit.h
Normal file
49
widget/windows/nsToolkit.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef nsToolkit_h__
|
||||
#define nsToolkit_h__
|
||||
|
||||
#include "nsdefs.h"
|
||||
|
||||
#include "nsITimer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include <windows.h>
|
||||
|
||||
// Avoid including windowsx.h to prevent macro pollution
|
||||
#ifndef GET_X_LPARAM
|
||||
#define GET_X_LPARAM(pt) (short(LOWORD(pt)))
|
||||
#endif
|
||||
#ifndef GET_Y_LPARAM
|
||||
#define GET_Y_LPARAM(pt) (short(HIWORD(pt)))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Wrapper around the thread running the message pump.
|
||||
* The toolkit abstraction is necessary because the message pump must
|
||||
* execute within the same thread that created the widget under Win32.
|
||||
*/
|
||||
|
||||
class nsToolkit
|
||||
{
|
||||
public:
|
||||
nsToolkit();
|
||||
|
||||
private:
|
||||
~nsToolkit();
|
||||
|
||||
public:
|
||||
static nsToolkit* GetToolkit();
|
||||
|
||||
static HINSTANCE mDllInstance;
|
||||
|
||||
static void Startup(HMODULE hModule);
|
||||
static void Shutdown();
|
||||
|
||||
protected:
|
||||
static nsToolkit* gToolkit;
|
||||
};
|
||||
|
||||
#endif // TOOLKIT_H
|
||||
251
widget/windows/nsUXThemeConstants.h
Normal file
251
widget/windows/nsUXThemeConstants.h
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef nsUXThemeConstants_h
|
||||
#define nsUXThemeConstants_h
|
||||
|
||||
/*
|
||||
* The following constants are used to determine how a widget is drawn using
|
||||
* Windows' Theme API. For more information on theme parts and states see
|
||||
* http://msdn.microsoft.com/en-us/library/bb773210(VS.85).aspx
|
||||
*/
|
||||
|
||||
#include <vssym32.h>
|
||||
#include <vsstyle.h>
|
||||
|
||||
#define THEME_COLOR 204
|
||||
#define THEME_FONT 210
|
||||
|
||||
// Generic state constants
|
||||
#define TS_NORMAL 1
|
||||
#define TS_HOVER 2
|
||||
#define TS_ACTIVE 3
|
||||
#define TS_DISABLED 4
|
||||
#define TS_FOCUSED 5
|
||||
|
||||
// These constants are reversed for the trackbar (scale) thumb
|
||||
#define TKP_FOCUSED 4
|
||||
#define TKP_DISABLED 5
|
||||
|
||||
// Toolbarbutton constants
|
||||
#define TB_CHECKED 5
|
||||
#define TB_HOVER_CHECKED 6
|
||||
|
||||
// Button constants
|
||||
#define BP_BUTTON 1
|
||||
#define BP_RADIO 2
|
||||
#define BP_CHECKBOX 3
|
||||
#define BP_GROUPBOX 4
|
||||
|
||||
// Textfield constants
|
||||
/* This is the EP_EDITTEXT part */
|
||||
#define TFP_TEXTFIELD 1
|
||||
#define TFP_EDITBORDER_NOSCROLL 6
|
||||
#define TFS_READONLY 6
|
||||
|
||||
/* These are the state constants for the EDITBORDER parts */
|
||||
#define TFS_EDITBORDER_NORMAL 1
|
||||
#define TFS_EDITBORDER_HOVER 2
|
||||
#define TFS_EDITBORDER_FOCUSED 3
|
||||
#define TFS_EDITBORDER_DISABLED 4
|
||||
|
||||
// Treeview/listbox constants
|
||||
#define TREEVIEW_BODY 1
|
||||
|
||||
// Scrollbar constants
|
||||
#define SP_BUTTON 1
|
||||
#define SP_THUMBHOR 2
|
||||
#define SP_THUMBVERT 3
|
||||
#define SP_TRACKSTARTHOR 4
|
||||
#define SP_TRACKENDHOR 5
|
||||
#define SP_TRACKSTARTVERT 6
|
||||
#define SP_TRACKENDVERT 7
|
||||
#define SP_GRIPPERHOR 8
|
||||
#define SP_GRIPPERVERT 9
|
||||
|
||||
// Vista only; implict hover state.
|
||||
// BASE + 0 = UP, + 1 = DOWN, etc.
|
||||
#define SP_BUTTON_IMPLICIT_HOVER_BASE 17
|
||||
|
||||
// Scale constants
|
||||
#define TKP_TRACK 1
|
||||
#define TKP_TRACKVERT 2
|
||||
#define TKP_THUMB 3
|
||||
#define TKP_THUMBBOTTOM 4
|
||||
#define TKP_THUMBTOP 5
|
||||
#define TKP_THUMBVERT 6
|
||||
#define TKP_THUMBLEFT 7
|
||||
#define TKP_THUMBRIGHT 8
|
||||
|
||||
// Track state contstants
|
||||
#define TRS_NORMAL 1
|
||||
|
||||
// Track vertical state constants
|
||||
#define TRVS_NORMAL 1
|
||||
|
||||
// Spin constants
|
||||
#define SPNP_UP 1
|
||||
#define SPNP_DOWN 2
|
||||
|
||||
// Tab constants
|
||||
#define TABP_TAB 4
|
||||
#define TABP_TAB_SELECTED 5
|
||||
#define TABP_PANELS 9
|
||||
#define TABP_PANEL 10
|
||||
|
||||
// Tooltip constants
|
||||
#define TTP_STANDARD 1
|
||||
|
||||
// Dropdown constants
|
||||
#define CBP_DROPMARKER 1
|
||||
#define CBP_DROPBORDER 4
|
||||
/* This is actually the 'READONLY' style */
|
||||
#define CBP_DROPFRAME 5
|
||||
#define CBP_DROPMARKER_VISTA 6
|
||||
|
||||
// Menu Constants
|
||||
#define MENU_BARBACKGROUND 7
|
||||
#define MENU_BARITEM 8
|
||||
#define MENU_POPUPBACKGROUND 9
|
||||
#define MENU_POPUPBORDERS 10
|
||||
#define MENU_POPUPCHECK 11
|
||||
#define MENU_POPUPCHECKBACKGROUND 12
|
||||
#define MENU_POPUPGUTTER 13
|
||||
#define MENU_POPUPITEM 14
|
||||
#define MENU_POPUPSEPARATOR 15
|
||||
#define MENU_POPUPSUBMENU 16
|
||||
#define MENU_SYSTEMCLOSE 17
|
||||
#define MENU_SYSTEMMAXIMIZE 18
|
||||
#define MENU_SYSTEMMINIMIZE 19
|
||||
#define MENU_SYSTEMRESTORE 20
|
||||
|
||||
#define MB_ACTIVE 1
|
||||
#define MB_INACTIVE 2
|
||||
|
||||
#define MS_NORMAL 1
|
||||
#define MS_SELECTED 2
|
||||
#define MS_DEMOTED 3
|
||||
|
||||
#define MBI_NORMAL 1
|
||||
#define MBI_HOT 2
|
||||
#define MBI_PUSHED 3
|
||||
#define MBI_DISABLED 4
|
||||
#define MBI_DISABLEDHOT 5
|
||||
#define MBI_DISABLEDPUSHED 6
|
||||
|
||||
#define MC_CHECKMARKNORMAL 1
|
||||
#define MC_CHECKMARKDISABLED 2
|
||||
#define MC_BULLETNORMAL 3
|
||||
#define MC_BULLETDISABLED 4
|
||||
|
||||
#define MCB_DISABLED 1
|
||||
#define MCB_NORMAL 2
|
||||
#define MCB_BITMAP 3
|
||||
|
||||
#define MPI_NORMAL 1
|
||||
#define MPI_HOT 2
|
||||
#define MPI_DISABLED 3
|
||||
#define MPI_DISABLEDHOT 4
|
||||
|
||||
#define MSM_NORMAL 1
|
||||
#define MSM_DISABLED 2
|
||||
|
||||
// Rebar constants
|
||||
#define RP_BAND 3
|
||||
#define RP_BACKGROUND 6
|
||||
|
||||
// Constants only found in new (98+, 2K+, XP+, etc.) Windows.
|
||||
#ifdef DFCS_HOT
|
||||
#undef DFCS_HOT
|
||||
#endif
|
||||
#define DFCS_HOT 0x00001000
|
||||
|
||||
#ifdef COLOR_MENUHILIGHT
|
||||
#undef COLOR_MENUHILIGHT
|
||||
#endif
|
||||
#define COLOR_MENUHILIGHT 29
|
||||
|
||||
#ifdef SPI_GETFLATMENU
|
||||
#undef SPI_GETFLATMENU
|
||||
#endif
|
||||
#define SPI_GETFLATMENU 0x1022
|
||||
#ifndef SPI_GETMENUSHOWDELAY
|
||||
#define SPI_GETMENUSHOWDELAY 106
|
||||
#endif //SPI_GETMENUSHOWDELAY
|
||||
#ifndef WS_EX_LAYOUTRTL
|
||||
#define WS_EX_LAYOUTRTL 0x00400000L // Right to left mirroring
|
||||
#endif
|
||||
|
||||
|
||||
// Our extra constants for passing a little bit more info to the renderer.
|
||||
#define DFCS_RTL 0x00010000
|
||||
|
||||
// Toolbar separator dimension which can't be gotten from Windows
|
||||
#define TB_SEPARATOR_HEIGHT 2
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
namespace themeconst {
|
||||
|
||||
// Pulled from sdk/include/vsstyle.h
|
||||
enum {
|
||||
WP_CAPTION = 1,
|
||||
WP_SMALLCAPTION = 2,
|
||||
WP_MINCAPTION = 3,
|
||||
WP_SMALLMINCAPTION = 4,
|
||||
WP_MAXCAPTION = 5,
|
||||
WP_SMALLMAXCAPTION = 6,
|
||||
WP_FRAMELEFT = 7,
|
||||
WP_FRAMERIGHT = 8,
|
||||
WP_FRAMEBOTTOM = 9,
|
||||
WP_SMALLFRAMELEFT = 10,
|
||||
WP_SMALLFRAMERIGHT = 11,
|
||||
WP_SMALLFRAMEBOTTOM = 12,
|
||||
WP_SYSBUTTON = 13,
|
||||
WP_MDISYSBUTTON = 14,
|
||||
WP_MINBUTTON = 15,
|
||||
WP_MDIMINBUTTON = 16,
|
||||
WP_MAXBUTTON = 17,
|
||||
WP_CLOSEBUTTON = 18,
|
||||
WP_SMALLCLOSEBUTTON = 19,
|
||||
WP_MDICLOSEBUTTON = 20,
|
||||
WP_RESTOREBUTTON = 21,
|
||||
WP_MDIRESTOREBUTTON = 22,
|
||||
WP_HELPBUTTON = 23,
|
||||
WP_MDIHELPBUTTON = 24,
|
||||
WP_HORZSCROLL = 25,
|
||||
WP_HORZTHUMB = 26,
|
||||
WP_VERTSCROLL = 27,
|
||||
WP_VERTTHUMB = 28,
|
||||
WP_DIALOG = 29,
|
||||
WP_CAPTIONSIZINGTEMPLATE = 30,
|
||||
WP_SMALLCAPTIONSIZINGTEMPLATE = 31,
|
||||
WP_FRAMELEFTSIZINGTEMPLATE = 32,
|
||||
WP_SMALLFRAMELEFTSIZINGTEMPLATE = 33,
|
||||
WP_FRAMERIGHTSIZINGTEMPLATE = 34,
|
||||
WP_SMALLFRAMERIGHTSIZINGTEMPLATE = 35,
|
||||
WP_FRAMEBOTTOMSIZINGTEMPLATE = 36,
|
||||
WP_SMALLFRAMEBOTTOMSIZINGTEMPLATE = 37,
|
||||
WP_FRAME = 38
|
||||
};
|
||||
|
||||
enum FRAMESTATES {
|
||||
FS_ACTIVE = 1,
|
||||
FS_INACTIVE = 2
|
||||
};
|
||||
|
||||
enum {
|
||||
BS_NORMAL = 1,
|
||||
BS_HOT = 2,
|
||||
BS_PUSHED = 3,
|
||||
BS_DISABLED = 4,
|
||||
BS_INACTIVE = 5 /* undocumented, inactive caption button */
|
||||
};
|
||||
|
||||
}}} // mozilla::widget::themeconst
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue