summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/views/custom_frame_window.cc73
-rw-r--r--chrome/views/custom_frame_window.h1
-rw-r--r--chrome/views/hwnd_view_container.h4
3 files changed, 54 insertions, 24 deletions
diff --git a/chrome/views/custom_frame_window.cc b/chrome/views/custom_frame_window.cc
index 8198284..9372334 100644
--- a/chrome/views/custom_frame_window.cc
+++ b/chrome/views/custom_frame_window.cc
@@ -24,6 +24,47 @@
namespace ChromeViews {
+// A scoping class that removes the WS_VISIBLE style of a window.
+//
+// Why would we want such a thing? Well, it turns out Windows has some
+// "unorthodox" behavior when it comes to painting its non-client areas.
+// Sadly, the default implementation of some messages, e.g. WM_SETTEXT and
+// WM_ENTERMENULOOP actually paint all or parts of the native title bar of the
+// application. That's right, they just paint it. They don't go through
+// WM_NCPAINT or anything like that that we already override. What this means
+// is that we end up with occasional flicker of bits of the normal Windows
+// title bar whenever we do things like change the title text, or right click
+// on the caption. The solution turns out to be to handle these messages,
+// use this scoped object to remove the WS_VISIBLE style which prevents this
+// rendering from happening, call the default window procedure, then add the
+// WS_VISIBLE style back when this object goes out of scope.
+// I would love to hear Raymond Chen's explanation for all this. And maybe a
+// list of other messages that this applies to ;-)
+//
+// *** Sigh. ***
+class ScopedVisibilityRemover {
+ public:
+ explicit ScopedVisibilityRemover(HWND hwnd)
+ : hwnd_(hwnd),
+ window_style_(0) {
+ window_style_ = GetWindowLong(hwnd_, GWL_STYLE);
+ if (window_style_ & WS_VISIBLE)
+ SetWindowLong(hwnd_, GWL_STYLE, window_style_ & ~WS_VISIBLE);
+ }
+
+ ~ScopedVisibilityRemover() {
+ if (window_style_ & WS_VISIBLE)
+ SetWindowLong(hwnd_, GWL_STYLE, window_style_);
+ }
+
+ private:
+ // The window having its style changed.
+ HWND hwnd_;
+
+ // The original style of the window, including WS_VISIBLE if present.
+ DWORD window_style_;
+};
+
HCURSOR CustomFrameWindow::resize_cursors_[6];
// An enumeration of bitmap resources used by this window.
@@ -875,6 +916,11 @@ static void EnableMenuItem(HMENU menu, UINT command, bool enabled) {
EnableMenuItem(menu, command, flags);
}
+void CustomFrameWindow::OnEnterMenuLoop(bool is_track_popup_menu) {
+ ScopedVisibilityRemover remover(GetHWND());
+ DefWindowProc(GetHWND(), WM_ENTERMENULOOP, is_track_popup_menu, NULL);
+}
+
void CustomFrameWindow::OnInitMenu(HMENU menu) {
bool minimized = IsMinimized();
bool maximized = IsMaximized();
@@ -1125,30 +1171,9 @@ LRESULT CustomFrameWindow::OnSetCursor(HWND window, UINT hittest_code,
}
LRESULT CustomFrameWindow::OnSetText(const wchar_t* text) {
- // Sadly, the default implementation of WM_SETTEXT actually paints the native
- // title bar of the application. That's right, it just paints it. It doesn't
- // go through WM_NCPAINT or anything like that. What this means is that we
- // end up with occasional flicker of the title bar whenever we change the
- // title text. The solution is to handle WM_SETTEXT ourselves and remove the
- // window's WS_VISIBLE style before calling DefWindowProc directly.
- // Afterwards we add it back. Sigh.
- LONG window_style = GetWindowLong(GetHWND(), GWL_STYLE);
- bool was_visible = !!(window_style & WS_VISIBLE);
- if (was_visible) {
- window_style &= ~WS_VISIBLE;
- SetWindowLong(GetHWND(), GWL_STYLE, window_style);
- }
-
- LRESULT result = DefWindowProc(GetHWND(), WM_SETTEXT, NULL,
- reinterpret_cast<LPARAM>(text));
-
- // Add the WS_VISIBLE style back if needed and re-set the window style.
- if (was_visible) {
- window_style |= WS_VISIBLE;
- SetWindowLong(GetHWND(), GWL_STYLE, window_style);
- }
-
- return result;
+ ScopedVisibilityRemover remover(GetHWND());
+ return DefWindowProc(GetHWND(), WM_SETTEXT, NULL,
+ reinterpret_cast<LPARAM>(text));
}
void CustomFrameWindow::OnSize(UINT param, const CSize& size) {
diff --git a/chrome/views/custom_frame_window.h b/chrome/views/custom_frame_window.h
index 6b8238b..2682d17 100644
--- a/chrome/views/custom_frame_window.h
+++ b/chrome/views/custom_frame_window.h
@@ -48,6 +48,7 @@ class CustomFrameWindow : public Window {
virtual void DisableInactiveRendering(bool disable);
// Overridden from HWNDViewContainer:
+ virtual void OnEnterMenuLoop(bool is_track_popup_menu);
virtual void OnInitMenu(HMENU menu);
virtual void OnMouseLeave();
virtual LRESULT OnNCActivate(BOOL active);
diff --git a/chrome/views/hwnd_view_container.h b/chrome/views/hwnd_view_container.h
index 069cc87..cd87f68 100644
--- a/chrome/views/hwnd_view_container.h
+++ b/chrome/views/hwnd_view_container.h
@@ -191,6 +191,7 @@ class HWNDViewContainer : public ViewContainer,
MSG_WM_DESTROY(OnDestroy)
MSG_WM_ERASEBKGND(OnEraseBkgnd)
MSG_WM_ENDSESSION(OnEndSession)
+ MSG_WM_ENTERMENULOOP(OnEnterMenuLoop)
MSG_WM_EXITMENULOOP(OnExitMenuLoop)
MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo)
MSG_WM_HSCROLL(OnHScroll)
@@ -358,6 +359,9 @@ class HWNDViewContainer : public ViewContainer,
// leak a few things.
virtual void OnDestroy();
virtual void OnEndSession(BOOL ending, UINT logoff) { SetMsgHandled(FALSE); }
+ virtual void OnEnterMenuLoop(BOOL is_track_popup_menu) {
+ SetMsgHandled(FALSE);
+ }
virtual void OnExitMenuLoop(BOOL is_track_popup_menu) { SetMsgHandled(FALSE); }
virtual LRESULT OnEraseBkgnd(HDC dc);
virtual void OnGetMinMaxInfo(LPMINMAXINFO mm_info) { }