From 0a88931ae556ff0fab8f0eaf3b1f7c5ae7ea48cb Mon Sep 17 00:00:00 2001 From: "kmcclusk%netscape.com" Date: Tue, 4 Jun 2002 17:47:54 +0000 Subject: [PATCH] Dispatch (WIN32 only) and handle a new cross platform message NS_SYSCOLORCHANGE. bug 143174. r=rods sr=roc --- layout/base/nsPresContext.cpp | 22 ++++++++++ layout/base/nsPresContext.h | 5 +++ layout/base/nsPresShell.cpp | 19 ++++++++ layout/base/public/nsIPresContext.h | 5 +++ layout/base/public/nsPresContext.h | 5 +++ layout/base/src/nsPresContext.cpp | 22 ++++++++++ layout/base/src/nsPresContext.h | 1 + layout/html/base/src/nsPresShell.cpp | 19 ++++++++ view/src/nsViewManager.cpp | 14 +++++- widget/public/nsGUIEvent.h | 5 +++ widget/src/windows/nsToolkit.cpp | 15 +++++++ widget/src/windows/nsWindow.cpp | 66 ++++++++++++++++++++++++++++ widget/src/windows/nsWindow.h | 5 +++ 13 files changed, 201 insertions(+), 2 deletions(-) diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 17649cf388a7..ac79ee074ff7 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -1775,6 +1775,28 @@ nsPresContext::ThemeChanged() return mShell->ReconstructStyleData(PR_FALSE); } +NS_IMETHODIMP +nsPresContext::SysColorChanged() +{ + if (mLookAndFeel) { + // Don't use the cached values for the system colors + mLookAndFeel->LookAndFeelChanged(); + } + + // Reset default background and foreground colors for the document since + // they may be using system colors + GetDocumentColorPreferences(); + + // Clear out all of the style data since it may contain RGB values + // which originated from system colors. + if (mShell) { + // Clear out all our style data. + nsCOMPtr set; + mShell->GetStyleSet(getter_AddRefs(set)); + set->ClearStyleData(this, nsnull, nsnull); + } + return NS_OK; +} #ifdef MOZ_REFLOW_PERF NS_IMETHODIMP diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index f1f216bcc967..f4208d681a9c 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -535,6 +535,11 @@ public: */ NS_IMETHOD ThemeChanged() = 0; + /* + * Notify the pres context that a system color has changed + */ + NS_IMETHOD SysColorChanged() = 0; + #ifdef MOZ_REFLOW_PERF NS_IMETHOD CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame) = 0; NS_IMETHOD PaintCount(const char * aName, nsIRenderingContext* aRendingContext, nsIFrame * aFrame, PRUint32 aColor) = 0; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index a5c4a9bff7d0..55bf6c374e90 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -5922,6 +5922,25 @@ PresShell::HandleEvent(nsIView *aView, if (aEvent->message == NS_THEMECHANGED && mPresContext) return mPresContext->ThemeChanged(); + // Check for a system color change up front, since the frame type is irrelevenat + if ((aEvent->message == NS_SYSCOLORCHANGED) && mPresContext) { + nsIViewManager *vm; + if ((NS_SUCCEEDED(GetViewManager(&vm))) && vm) { + // Only dispatch system color change when the message originates from + // from the root views widget. This is necessary to prevent us from + // dispatching the SysColorChanged notification for each child window + // which may be redundant. + nsIView *view; + vm->GetRootView(view); + if (view == aView) { + aHandled = PR_TRUE; + *aEventStatus = nsEventStatus_eConsumeDoDefault; + return mPresContext->SysColorChanged(); + } + } + return NS_OK; + } + aView->GetClientData(clientData); frame = (nsIFrame *)clientData; diff --git a/layout/base/public/nsIPresContext.h b/layout/base/public/nsIPresContext.h index f1f216bcc967..f4208d681a9c 100644 --- a/layout/base/public/nsIPresContext.h +++ b/layout/base/public/nsIPresContext.h @@ -535,6 +535,11 @@ public: */ NS_IMETHOD ThemeChanged() = 0; + /* + * Notify the pres context that a system color has changed + */ + NS_IMETHOD SysColorChanged() = 0; + #ifdef MOZ_REFLOW_PERF NS_IMETHOD CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame) = 0; NS_IMETHOD PaintCount(const char * aName, nsIRenderingContext* aRendingContext, nsIFrame * aFrame, PRUint32 aColor) = 0; diff --git a/layout/base/public/nsPresContext.h b/layout/base/public/nsPresContext.h index f1f216bcc967..f4208d681a9c 100644 --- a/layout/base/public/nsPresContext.h +++ b/layout/base/public/nsPresContext.h @@ -535,6 +535,11 @@ public: */ NS_IMETHOD ThemeChanged() = 0; + /* + * Notify the pres context that a system color has changed + */ + NS_IMETHOD SysColorChanged() = 0; + #ifdef MOZ_REFLOW_PERF NS_IMETHOD CountReflows(const char * aName, PRUint32 aType, nsIFrame * aFrame) = 0; NS_IMETHOD PaintCount(const char * aName, nsIRenderingContext* aRendingContext, nsIFrame * aFrame, PRUint32 aColor) = 0; diff --git a/layout/base/src/nsPresContext.cpp b/layout/base/src/nsPresContext.cpp index 17649cf388a7..ac79ee074ff7 100644 --- a/layout/base/src/nsPresContext.cpp +++ b/layout/base/src/nsPresContext.cpp @@ -1775,6 +1775,28 @@ nsPresContext::ThemeChanged() return mShell->ReconstructStyleData(PR_FALSE); } +NS_IMETHODIMP +nsPresContext::SysColorChanged() +{ + if (mLookAndFeel) { + // Don't use the cached values for the system colors + mLookAndFeel->LookAndFeelChanged(); + } + + // Reset default background and foreground colors for the document since + // they may be using system colors + GetDocumentColorPreferences(); + + // Clear out all of the style data since it may contain RGB values + // which originated from system colors. + if (mShell) { + // Clear out all our style data. + nsCOMPtr set; + mShell->GetStyleSet(getter_AddRefs(set)); + set->ClearStyleData(this, nsnull, nsnull); + } + return NS_OK; +} #ifdef MOZ_REFLOW_PERF NS_IMETHODIMP diff --git a/layout/base/src/nsPresContext.h b/layout/base/src/nsPresContext.h index 92f6cce13fb4..391a9094587b 100644 --- a/layout/base/src/nsPresContext.h +++ b/layout/base/src/nsPresContext.h @@ -199,6 +199,7 @@ public: NS_IMETHOD GetTheme(nsITheme** aResult); NS_IMETHOD ThemeChanged(); + NS_IMETHOD SysColorChanged(); protected: nsPresContext(); diff --git a/layout/html/base/src/nsPresShell.cpp b/layout/html/base/src/nsPresShell.cpp index a5c4a9bff7d0..55bf6c374e90 100644 --- a/layout/html/base/src/nsPresShell.cpp +++ b/layout/html/base/src/nsPresShell.cpp @@ -5922,6 +5922,25 @@ PresShell::HandleEvent(nsIView *aView, if (aEvent->message == NS_THEMECHANGED && mPresContext) return mPresContext->ThemeChanged(); + // Check for a system color change up front, since the frame type is irrelevenat + if ((aEvent->message == NS_SYSCOLORCHANGED) && mPresContext) { + nsIViewManager *vm; + if ((NS_SUCCEEDED(GetViewManager(&vm))) && vm) { + // Only dispatch system color change when the message originates from + // from the root views widget. This is necessary to prevent us from + // dispatching the SysColorChanged notification for each child window + // which may be redundant. + nsIView *view; + vm->GetRootView(view); + if (view == aView) { + aHandled = PR_TRUE; + *aEventStatus = nsEventStatus_eConsumeDoDefault; + return mPresContext->SysColorChanged(); + } + } + return NS_OK; + } + aView->GetClientData(clientData); frame = (nsIFrame *)clientData; diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 508489dc01db..60a4d486b6e1 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -1798,7 +1798,17 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS } break; - + case NS_SYSCOLORCHANGED: + { + nsView *view = nsView::GetViewFor(aEvent->widget); + nsCOMPtr obs; + GetViewObserver(*getter_AddRefs(obs)); + if (obs) { + PRBool handled; + obs->HandleEvent(view, aEvent, aStatus, PR_TRUE, handled); + } + } + break; default: { @@ -2029,7 +2039,7 @@ nsEventStatus nsViewManager::HandleEvent(nsView* aView, nsGUIEvent* aEvent, PRBo } return status; } - + nsAutoVoidArray targetViews; nsAutoVoidArray heldRefCountsToOtherVMs; diff --git a/widget/public/nsGUIEvent.h b/widget/public/nsGUIEvent.h index 46e13eab3522..c333e8accaf8 100644 --- a/widget/public/nsGUIEvent.h +++ b/widget/public/nsGUIEvent.h @@ -449,6 +449,11 @@ enum nsDragDropEventStatus { // Indicates a theme change has occurred #define NS_THEMECHANGED (NS_WINDOW_START + 41) +// Indicates a System color has changed. It is the platform +// toolkits responsibility to invalidate the window to +// ensure that it is drawn using the current system colors. +#define NS_SYSCOLORCHANGED (NS_WINDOW_START + 42) + // Indicates a script error has occurred #define NS_SCRIPT_ERROR (NS_WINDOW_START + 50) diff --git a/widget/src/windows/nsToolkit.cpp b/widget/src/windows/nsToolkit.cpp index c73a0e7a8367..b55a3ef2831b 100644 --- a/widget/src/windows/nsToolkit.cpp +++ b/widget/src/windows/nsToolkit.cpp @@ -370,6 +370,21 @@ LRESULT CALLBACK nsToolkit::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, MethodInfo *info = (MethodInfo *)lParam; return info->Invoke(); } + + case WM_SYSCOLORCHANGE: + { + // WM_SYSCOLORCHANGE messages are only dispatched to top + // level windows but NS_SYSCOLORCHANGE messages must be dispatched + // to all windows including child windows. We dispatch these messages + // from the nsToolkit because if we are running embedded we may not + // have a top-level nsIWidget window. + + // On WIN32 all windows are automatically invalidated after the + // WM_SYSCOLORCHANGE is dispatched so the window is drawn using + // the current system colors. + nsWindow::GlobalMsgWindowProc(hWnd, msg, wParam, lParam); + } + } #ifdef MOZ_AIMM diff --git a/widget/src/windows/nsWindow.cpp b/widget/src/windows/nsWindow.cpp index 5bd81d22b6d8..c282d5e381de 100644 --- a/widget/src/windows/nsWindow.cpp +++ b/widget/src/windows/nsWindow.cpp @@ -644,6 +644,63 @@ private: static nsAttentionTimerMonitor *gAttentionTimerMonitor = 0; +// Code to dispatch WM_SYSCOLORCHANGE message to all child windows. +// WM_SYSCOLORCHANGE is only sent to top-level windows, but the +// cross platform API requires that NS_SYSCOLORCHANGE message be sent to +// all child windows as well. When running in an embedded application +// we may not receive a WM_SYSCOLORCHANGE message because the top +// level window is owned by the embeddor. Note: this code can be used to +// dispatch other global messages (i.e messages that must be sent to all +// nsIWidget instances. + +// Enumerate all child windows sending aMsg to each of them + +BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg) +{ + LONG proc = ::GetWindowLong(aWnd, GWL_WNDPROC); + if (proc == (LONG)&nsWindow::WindowProc) { + // its one of our windows so go ahead and send a message to it + WNDPROC winProc = (WNDPROC)GetWindowLong(aWnd, GWL_WNDPROC); + ::CallWindowProc(winProc, aWnd, aMsg, 0, 0); + } + // Send message to children of this window + ::EnumChildWindows(aWnd, nsWindow::BroadcastMsgToChildren, aMsg); + return TRUE; +} + +// Enumerate all top level windows specifying that the children of each +// top level window should be enumerated. Do *not* send the message to +// each top level window since it is assumed that the toolkit will send +// aMsg to them directly. + +BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg) +{ + // Iterate each of aTopWindows child windows sending the aMsg + // to each of them. + EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg); + return TRUE; +} + +// This method is called from nsToolkit::WindowProc to forward global +// messages which need to be dispatched to all child windows. + +void nsWindow::GlobalMsgWindowProc(HWND hWnd, UINT msg, + WPARAM wParam, LPARAM lParam) + +{ + switch (msg) { + case WM_SYSCOLORCHANGE: + // System color changes are posted to top-level windows only. + // The NS_SYSCOLORCHANGE must be dispatched to all child + // windows as well. + ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, msg); + break; + } +} + +// End of the methods to dispatch global messages + + PRBool gIsDestroyingAny = PR_FALSE; //------------------------------------------------------------------------- @@ -3424,6 +3481,15 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT case WM_DISPLAYCHANGE: DispatchStandardEvent(NS_DISPLAYCHANGED); break; + + case WM_SYSCOLORCHANGE: + // Note: This is sent for child windows as well as top-level windows. + // The Win32 toolkit normally only sends these events to top-level windows. + // But we cycle through all of the childwindows and send it to them as well + // so all presentations get notified properly. + // See nsWindow::GlobalMsgWindowProc. + DispatchStandardEvent(NS_SYSCOLORCHANGED); + break; case WM_NOTIFY: // TAB change diff --git a/widget/src/windows/nsWindow.h b/widget/src/windows/nsWindow.h index d0442a9bea7e..54f00ec625fa 100644 --- a/widget/src/windows/nsWindow.h +++ b/widget/src/windows/nsWindow.h @@ -561,6 +561,11 @@ protected: IAccessible* mRootAccessible; static BOOL gIsAccessibilityOn; #endif + + static BOOL CALLBACK BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg); + static BOOL CALLBACK BroadcastMsg(HWND aTopWindow, LPARAM aMsg); +public: + static void GlobalMsgWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); }; //