summaryrefslogtreecommitdiffstats
path: root/views/widget
diff options
context:
space:
mode:
Diffstat (limited to 'views/widget')
-rw-r--r--views/widget/accelerator_handler.cc46
-rw-r--r--views/widget/accelerator_handler.h30
-rw-r--r--views/widget/aero_tooltip_manager.cc128
-rw-r--r--views/widget/aero_tooltip_manager.h57
-rw-r--r--views/widget/root_view.cc1001
-rw-r--r--views/widget/root_view.h363
-rw-r--r--views/widget/root_view_drop_target.cc118
-rw-r--r--views/widget/root_view_drop_target.h75
-rw-r--r--views/widget/root_view_gtk.cc28
-rw-r--r--views/widget/root_view_win.cc70
-rw-r--r--views/widget/tooltip_manager.cc447
-rw-r--r--views/widget/tooltip_manager.h168
-rw-r--r--views/widget/widget.h81
-rw-r--r--views/widget/widget_gtk.cc386
-rw-r--r--views/widget/widget_gtk.h125
-rw-r--r--views/widget/widget_win.cc999
-rw-r--r--views/widget/widget_win.h636
17 files changed, 4758 insertions, 0 deletions
diff --git a/views/widget/accelerator_handler.cc b/views/widget/accelerator_handler.cc
new file mode 100644
index 0000000..386357f
--- /dev/null
+++ b/views/widget/accelerator_handler.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/accelerator_handler.h"
+
+#include "views/focus/focus_manager.h"
+
+namespace views {
+
+AcceleratorHandler::AcceleratorHandler() {
+}
+
+bool AcceleratorHandler::Dispatch(const MSG& msg) {
+ bool process_message = true;
+
+ if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) {
+ FocusManager* focus_manager = FocusManager::GetFocusManager(msg.hwnd);
+ if (focus_manager) {
+ // FocusManager::OnKeyDown and OnKeyUp return false if this message has
+ // been consumed and should not be propagated further.
+ switch (msg.message) {
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ process_message = focus_manager->OnKeyDown(msg.hwnd, msg.message,
+ msg.wParam, msg.lParam);
+ break;
+
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ process_message = focus_manager->OnKeyUp(msg.hwnd, msg.message,
+ msg.wParam, msg.lParam);
+ break;
+ }
+ }
+ }
+
+ if (process_message) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ return true;
+}
+
+} // namespace views
diff --git a/views/widget/accelerator_handler.h b/views/widget/accelerator_handler.h
new file mode 100644
index 0000000..5ee896c
--- /dev/null
+++ b/views/widget/accelerator_handler.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_ACCELERATOR_HANDLER_H_
+#define VIEWS_WIDGET_ACCELERATOR_HANDLER_H_
+
+#include "base/message_loop.h"
+
+namespace views {
+
+// This class delegates WM_KEYDOWN and WM_SYSKEYDOWN messages to
+// the associated FocusManager class for the window that is receiving
+// these messages for accelerator processing. The BrowserProcess object
+// holds a singleton instance of this class which can be used by other
+// custom message loop dispatcher objects to implement default accelerator
+// handling.
+class AcceleratorHandler : public MessageLoopForUI::Dispatcher {
+ public:
+ AcceleratorHandler();
+ // Dispatcher method. This returns true if an accelerator was
+ // processed by the focus manager
+ virtual bool Dispatch(const MSG& msg);
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(AcceleratorHandler);
+};
+
+} // namespace views
+
+#endif // VIEWS_WIDGET_ACCELERATOR_HANDLER_H_
diff --git a/views/widget/aero_tooltip_manager.cc b/views/widget/aero_tooltip_manager.cc
new file mode 100644
index 0000000..ca58c24
--- /dev/null
+++ b/views/widget/aero_tooltip_manager.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/aero_tooltip_manager.h"
+
+#include <windows.h>
+#include <atlbase.h>
+#include <atlapp.h> // for GET_X/Y_LPARAM
+#include <commctrl.h>
+#include <shlobj.h>
+
+#include "app/l10n_util_win.h"
+#include "base/message_loop.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager, public:
+
+AeroTooltipManager::AeroTooltipManager(Widget* widget, HWND parent)
+ : TooltipManager(widget, parent),
+ initial_delay_(0) {
+}
+
+AeroTooltipManager::~AeroTooltipManager() {
+ if (initial_timer_)
+ initial_timer_->Disown();
+}
+
+void AeroTooltipManager::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
+ if (initial_timer_)
+ initial_timer_->Disown();
+
+ if (u_msg == WM_MOUSEMOVE || u_msg == WM_NCMOUSEMOVE) {
+ int x = GET_X_LPARAM(l_param);
+ int y = GET_Y_LPARAM(l_param);
+ if (last_mouse_x_ != x || last_mouse_y_ != y) {
+ last_mouse_x_ = x;
+ last_mouse_y_ = y;
+ HideKeyboardTooltip();
+ UpdateTooltip(x, y);
+ }
+
+ // Delay opening of the tooltip just in case the user moves their
+ // mouse to another control. We defer this from Init because we get
+ // zero if we query it too soon.
+ if (!initial_delay_) {
+ initial_delay_ = static_cast<int>(
+ ::SendMessage(tooltip_hwnd_, TTM_GETDELAYTIME, TTDT_INITIAL, 0));
+ }
+ initial_timer_ = new InitialTimer(this, initial_delay_);
+ } else {
+ // Hide the tooltip and cancel any timers.
+ ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ ::SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, false, (LPARAM)&toolinfo_);
+ return;
+ }
+}
+
+void AeroTooltipManager::OnMouseLeave() {
+ last_mouse_x_ = last_mouse_y_ = -1;
+ UpdateTooltip();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager, private:
+
+void AeroTooltipManager::Init() {
+ // Create the tooltip control.
+ tooltip_hwnd_ = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
+ parent_, NULL, NULL, NULL);
+
+ l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
+
+ // Add one tool that is used for all tooltips.
+ toolinfo_.cbSize = sizeof(toolinfo_);
+
+ // We use tracking tooltips on Vista to allow us to manually control the
+ // visibility of the tooltip.
+ toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
+ toolinfo_.hwnd = parent_;
+ toolinfo_.uId = (UINT_PTR)parent_;
+
+ // Setting this tells windows to call parent_ back (using a WM_NOTIFY
+ // message) for the actual tooltip contents.
+ toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
+ SetRectEmpty(&toolinfo_.rect);
+ ::SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
+}
+
+void AeroTooltipManager::OnTimer() {
+ initial_timer_ = NULL;
+
+ POINT pt;
+ pt.x = last_mouse_x_;
+ pt.y = last_mouse_y_;
+ ::ClientToScreen(parent_, &pt);
+
+ // Set the position and visibility.
+ if (!tooltip_showing_) {
+ ::SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
+ ::SendMessage(tooltip_hwnd_, TTM_TRACKPOSITION, 0, MAKELPARAM(pt.x, pt.y));
+ ::SendMessage(tooltip_hwnd_, TTM_TRACKACTIVATE, true, (LPARAM)&toolinfo_);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager::InitialTimer
+
+AeroTooltipManager::InitialTimer::InitialTimer(AeroTooltipManager* manager,
+ int time) : manager_(manager) {
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
+ this, &InitialTimer::Execute), time);
+}
+
+void AeroTooltipManager::InitialTimer::Disown() {
+ manager_ = NULL;
+}
+
+void AeroTooltipManager::InitialTimer::Execute() {
+ if (manager_)
+ manager_->OnTimer();
+}
+
+} // namespace views
diff --git a/views/widget/aero_tooltip_manager.h b/views/widget/aero_tooltip_manager.h
new file mode 100644
index 0000000..fe5856d
--- /dev/null
+++ b/views/widget/aero_tooltip_manager.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
+#define VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
+
+#include "base/ref_counted.h"
+#include "base/task.h"
+#include "views/widget/tooltip_manager.h"
+
+namespace views {
+
+///////////////////////////////////////////////////////////////////////////////
+// AeroTooltipManager
+//
+// Default Windows tooltips are broken when using our custom window frame
+// - as soon as the tooltip receives a WM_MOUSEMOVE event, it starts spewing
+// NCHITTEST messages at its parent window (us). These messages have random
+// x/y coordinates and can't be ignored, as the DwmDefWindowProc uses
+// NCHITTEST messages to determine how to highlight the caption buttons
+// (the buttons then flicker as the hit tests sent by the user's mouse
+// trigger different effects to those sent by the tooltip).
+//
+// So instead, we have to partially implement tooltips ourselves using
+// TTF_TRACKed tooltips.
+//
+// TODO(glen): Resolve this with Microsoft.
+class AeroTooltipManager : public TooltipManager {
+ public:
+ AeroTooltipManager(Widget* widget, HWND parent);
+ virtual ~AeroTooltipManager();
+
+ virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
+ virtual void OnMouseLeave();
+
+ private:
+ void Init();
+ void OnTimer();
+
+ class InitialTimer : public base::RefCounted<InitialTimer> {
+ public:
+ InitialTimer(AeroTooltipManager* manager, int time);
+ void Disown();
+ void Execute();
+
+ private:
+ AeroTooltipManager* manager_;
+ };
+
+ int initial_delay_;
+ scoped_refptr<InitialTimer> initial_timer_;
+};
+
+} // namespace views
+
+#endif // #ifndef VIEWS_WIDGET_AERO_TOOLTIP_MANAGER_H_
diff --git a/views/widget/root_view.cc b/views/widget/root_view.cc
new file mode 100644
index 0000000..fd9f1c0
--- /dev/null
+++ b/views/widget/root_view.cc
@@ -0,0 +1,1001 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/root_view.h"
+
+#include <algorithm>
+
+#include "app/drag_drop_types.h"
+#include "app/gfx/chrome_canvas.h"
+#if defined(OS_WIN)
+#include "base/base_drag_source.h"
+#endif
+#include "base/logging.h"
+#include "base/message_loop.h"
+#if defined(OS_WIN)
+#include "views/focus/view_storage.h"
+#include "views/widget/root_view_drop_target.h"
+#endif
+#include "views/widget/widget.h"
+#include "views/window/window.h"
+
+namespace views {
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// A Task to trigger non urgent painting.
+//
+/////////////////////////////////////////////////////////////////////////////
+class PaintTask : public Task {
+ public:
+ explicit PaintTask(RootView* target) : root_view_(target) {
+ }
+
+ ~PaintTask() {}
+
+ void Cancel() {
+ root_view_ = NULL;
+ }
+
+ void Run() {
+ if (root_view_)
+ root_view_->PaintNow();
+ }
+ private:
+ // The target root view.
+ RootView* root_view_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PaintTask);
+};
+
+const char RootView::kViewClassName[] = "views/RootView";
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - constructors, destructors, initialization
+//
+/////////////////////////////////////////////////////////////////////////////
+
+RootView::RootView(Widget* widget)
+ : mouse_pressed_handler_(NULL),
+ mouse_move_handler_(NULL),
+ last_click_handler_(NULL),
+ widget_(widget),
+ invalid_rect_urgent_(false),
+ pending_paint_task_(NULL),
+ paint_task_needed_(false),
+ explicit_mouse_handler_(false),
+#if defined(OS_WIN)
+ previous_cursor_(NULL),
+#endif
+ default_keyboard_handler_(NULL),
+ focus_listener_(NULL),
+ focus_on_mouse_pressed_(false),
+ ignore_set_focus_calls_(false),
+ focus_traversable_parent_(NULL),
+ focus_traversable_parent_view_(NULL),
+ drag_view_(NULL)
+#ifndef NDEBUG
+ ,
+ is_processing_paint_(false)
+#endif
+{
+}
+
+RootView::~RootView() {
+ // If we have children remove them explicitly so to make sure a remove
+ // notification is sent for each one of them.
+ if (!child_views_.empty())
+ RemoveAllChildViews(true);
+
+ if (pending_paint_task_)
+ pending_paint_task_->Cancel(); // Ensure we're not called any more.
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - layout, painting
+//
+/////////////////////////////////////////////////////////////////////////////
+
+void RootView::SchedulePaint(const gfx::Rect& r, bool urgent) {
+ // If there is an existing invalid rect, add the union of the scheduled
+ // rect with the invalid rect. This could be optimized further if
+ // necessary.
+ if (invalid_rect_.IsEmpty())
+ invalid_rect_ = r;
+ else
+ invalid_rect_ = invalid_rect_.Union(r);
+
+ if (urgent || invalid_rect_urgent_) {
+ invalid_rect_urgent_ = true;
+ } else {
+ if (!pending_paint_task_) {
+ pending_paint_task_ = new PaintTask(this);
+ MessageLoop::current()->PostTask(FROM_HERE, pending_paint_task_);
+ }
+ paint_task_needed_ = true;
+ }
+}
+
+void RootView::SchedulePaint() {
+ View::SchedulePaint();
+}
+
+void RootView::SchedulePaint(int x, int y, int w, int h) {
+ View::SchedulePaint();
+}
+
+#ifndef NDEBUG
+// Sets the value of RootView's |is_processing_paint_| member to true as long
+// as ProcessPaint is being called. Sets it to |false| when it returns.
+class ScopedProcessingPaint {
+ public:
+ explicit ScopedProcessingPaint(bool* is_processing_paint)
+ : is_processing_paint_(is_processing_paint) {
+ *is_processing_paint_ = true;
+ }
+
+ ~ScopedProcessingPaint() {
+ *is_processing_paint_ = false;
+ }
+ private:
+ bool* is_processing_paint_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ScopedProcessingPaint);
+};
+#endif
+
+void RootView::ProcessPaint(ChromeCanvas* canvas) {
+#ifndef NDEBUG
+ ScopedProcessingPaint processing_paint(&is_processing_paint_);
+#endif
+
+ // Clip the invalid rect to our bounds. If a view is in a scrollview
+ // it could be a lot larger
+ invalid_rect_ = GetScheduledPaintRectConstrainedToSize();
+
+ if (invalid_rect_.IsEmpty())
+ return;
+
+ // Clear the background.
+ canvas->drawColor(SK_ColorBLACK, SkPorterDuff::kClear_Mode);
+
+ // Save the current transforms.
+ canvas->save();
+
+ // Set the clip rect according to the invalid rect.
+ int clip_x = invalid_rect_.x() + x();
+ int clip_y = invalid_rect_.y() + y();
+ canvas->ClipRectInt(clip_x, clip_y, invalid_rect_.width(),
+ invalid_rect_.height());
+
+ // Paint the tree
+ View::ProcessPaint(canvas);
+
+ // Restore the previous transform
+ canvas->restore();
+
+ ClearPaintRect();
+}
+
+void RootView::PaintNow() {
+ if (pending_paint_task_) {
+ pending_paint_task_->Cancel();
+ pending_paint_task_ = NULL;
+ }
+ if (!paint_task_needed_)
+ return;
+ Widget* widget = GetWidget();
+ if (widget)
+ widget->PaintNow(invalid_rect_);
+}
+
+bool RootView::NeedsPainting(bool urgent) {
+ bool has_invalid_rect = !invalid_rect_.IsEmpty();
+ if (urgent) {
+ if (invalid_rect_urgent_)
+ return has_invalid_rect;
+ else
+ return false;
+ } else {
+ return has_invalid_rect;
+ }
+}
+
+const gfx::Rect& RootView::GetScheduledPaintRect() {
+ return invalid_rect_;
+}
+
+gfx::Rect RootView::GetScheduledPaintRectConstrainedToSize() {
+ if (invalid_rect_.IsEmpty())
+ return invalid_rect_;
+
+ return invalid_rect_.Intersect(GetLocalBounds(true));
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - tree
+//
+/////////////////////////////////////////////////////////////////////////////
+
+Widget* RootView::GetWidget() const {
+ return widget_;
+}
+
+void RootView::ThemeChanged() {
+ View::ThemeChanged();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - event dispatch and propagation
+//
+/////////////////////////////////////////////////////////////////////////////
+
+void RootView::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
+ if (!is_add) {
+ if (!explicit_mouse_handler_ && mouse_pressed_handler_ == child) {
+ mouse_pressed_handler_ = NULL;
+ }
+
+#if defined(OS_WIN)
+ if (drop_target_.get())
+ drop_target_->ResetTargetViewIfEquals(child);
+#else
+ NOTIMPLEMENTED();
+#endif
+
+ if (mouse_move_handler_ == child) {
+ mouse_move_handler_ = NULL;
+ }
+
+ if (GetFocusedView() == child) {
+ FocusView(NULL);
+ }
+
+ if (child == drag_view_)
+ drag_view_ = NULL;
+
+ if (default_keyboard_handler_ == child) {
+ default_keyboard_handler_ = NULL;
+ }
+
+ // For a given widget hierarchy, focus is tracked by a FocusManager attached
+ // to our nearest enclosing Window. <-- Important Assumption!
+ // We may not have access to our window if this function is called as a
+ // result of teardown during the deletion of the RootView and its hierarchy,
+ // so we don't bother notifying the FocusManager in that case because it
+ // will have already been destroyed (the Widget that contains us is
+ // NCDESTROY'ed which in turn destroys the focus manager _before_ the
+ // RootView is deleted.)
+#if defined(OS_WIN)
+ Window* window = GetWindow();
+ if (window) {
+ FocusManager* focus_manager =
+ FocusManager::GetFocusManager(window->GetNativeWindow());
+ focus_manager->ViewRemoved(parent, child);
+ }
+ ViewStorage::GetSharedInstance()->ViewRemoved(parent, child);
+#endif
+ }
+}
+
+void RootView::SetFocusOnMousePressed(bool f) {
+ focus_on_mouse_pressed_ = f;
+}
+
+bool RootView::OnMousePressed(const MouseEvent& e) {
+ // This function does not normally handle non-client messages except for
+ // non-client double-clicks. Actually, all double-clicks are special as the
+ // are formed from a single-click followed by a double-click event. When the
+ // double-click event lands on a different view than its single-click part,
+ // we transform it into a single-click which prevents odd things.
+ if ((e.GetFlags() & MouseEvent::EF_IS_NON_CLIENT) &&
+ !(e.GetFlags() & MouseEvent::EF_IS_DOUBLE_CLICK)) {
+ last_click_handler_ = NULL;
+ return false;
+ }
+
+ UpdateCursor(e);
+ SetMouseLocationAndFlags(e);
+
+ // If mouse_pressed_handler_ is non null, we are currently processing
+ // a pressed -> drag -> released session. In that case we send the
+ // event to mouse_pressed_handler_
+ if (mouse_pressed_handler_) {
+ MouseEvent mouse_pressed_event(e, this, mouse_pressed_handler_);
+ drag_info.Reset();
+ mouse_pressed_handler_->ProcessMousePressed(mouse_pressed_event,
+ &drag_info);
+ return true;
+ }
+ DCHECK(!explicit_mouse_handler_);
+
+ bool hit_disabled_view = false;
+ // Walk up the tree until we find a view that wants the mouse event.
+ for (mouse_pressed_handler_ = GetViewForPoint(e.location());
+ mouse_pressed_handler_ && (mouse_pressed_handler_ != this);
+ mouse_pressed_handler_ = mouse_pressed_handler_->GetParent()) {
+ if (!mouse_pressed_handler_->IsEnabled()) {
+ // Disabled views should eat events instead of propagating them upwards.
+ hit_disabled_view = true;
+ break;
+ }
+
+ // See if this view wants to handle the mouse press.
+ MouseEvent mouse_pressed_event(e, this, mouse_pressed_handler_);
+
+ // Remove the double-click flag if the handler is different than the
+ // one which got the first click part of the double-click.
+ if (mouse_pressed_handler_ != last_click_handler_)
+ mouse_pressed_event.set_flags(e.GetFlags() &
+ ~MouseEvent::EF_IS_DOUBLE_CLICK);
+
+ drag_info.Reset();
+ bool handled = mouse_pressed_handler_->ProcessMousePressed(
+ mouse_pressed_event, &drag_info);
+
+ // The view could have removed itself from the tree when handling
+ // OnMousePressed(). In this case, the removal notification will have
+ // reset mouse_pressed_handler_ to NULL out from under us. Detect this
+ // case and stop. (See comments in view.h.)
+ //
+ // NOTE: Don't return true here, because we don't want the frame to
+ // forward future events to us when there's no handler.
+ if (!mouse_pressed_handler_)
+ break;
+
+ // If the view handled the event, leave mouse_pressed_handler_ set and
+ // return true, which will cause subsequent drag/release events to get
+ // forwarded to that view.
+ if (handled) {
+ last_click_handler_ = mouse_pressed_handler_;
+ return true;
+ }
+ }
+
+ // Reset mouse_pressed_handler_ to indicate that no processing is occurring.
+ mouse_pressed_handler_ = NULL;
+
+ if (focus_on_mouse_pressed_) {
+#if defined(OS_WIN)
+ HWND hwnd = GetWidget()->GetNativeView();
+ if (::GetFocus() != hwnd) {
+ ::SetFocus(hwnd);
+ }
+#else
+ NOTIMPLEMENTED();
+#endif
+ }
+
+ // In the event that a double-click is not handled after traversing the
+ // entire hierarchy (even as a single-click when sent to a different view),
+ // it must be marked as handled to avoid anything happening from default
+ // processing if it the first click-part was handled by us.
+ if (last_click_handler_ && e.GetFlags() & MouseEvent::EF_IS_DOUBLE_CLICK)
+ hit_disabled_view = true;
+
+ last_click_handler_ = NULL;
+ return hit_disabled_view;
+}
+
+bool RootView::ConvertPointToMouseHandler(const gfx::Point& l,
+ gfx::Point* p) {
+ //
+ // If the mouse_handler was set explicitly, we need to keep
+ // sending events even if it was reparented in a different
+ // window. (a non explicit mouse handler is automatically
+ // cleared when the control is removed from the hierarchy)
+ if (explicit_mouse_handler_) {
+ if (mouse_pressed_handler_->GetWidget()) {
+ *p = l;
+ ConvertPointToScreen(this, p);
+ ConvertPointToView(NULL, mouse_pressed_handler_, p);
+ } else {
+ // If the mouse_pressed_handler_ is not connected, we send the
+ // event in screen coordinate system
+ *p = l;
+ ConvertPointToScreen(this, p);
+ return true;
+ }
+ } else {
+ *p = l;
+ ConvertPointToView(this, mouse_pressed_handler_, p);
+ }
+ return true;
+}
+
+bool RootView::OnMouseDragged(const MouseEvent& e) {
+ UpdateCursor(e);
+
+ if (mouse_pressed_handler_) {
+ SetMouseLocationAndFlags(e);
+
+ gfx::Point p;
+ ConvertPointToMouseHandler(e.location(), &p);
+ MouseEvent mouse_event(e.GetType(), p.x(), p.y(), e.GetFlags());
+ return mouse_pressed_handler_->ProcessMouseDragged(mouse_event, &drag_info);
+ }
+ return false;
+}
+
+void RootView::OnMouseReleased(const MouseEvent& e, bool canceled) {
+ UpdateCursor(e);
+
+ if (mouse_pressed_handler_) {
+ gfx::Point p;
+ ConvertPointToMouseHandler(e.location(), &p);
+ MouseEvent mouse_released(e.GetType(), p.x(), p.y(), e.GetFlags());
+ // We allow the view to delete us from ProcessMouseReleased. As such,
+ // configure state such that we're done first, then call View.
+ View* mouse_pressed_handler = mouse_pressed_handler_;
+ mouse_pressed_handler_ = NULL;
+ explicit_mouse_handler_ = false;
+ mouse_pressed_handler->ProcessMouseReleased(mouse_released, canceled);
+ // WARNING: we may have been deleted.
+ }
+}
+
+void RootView::OnMouseMoved(const MouseEvent& e) {
+ View* v = GetViewForPoint(e.location());
+ // Find the first enabled view.
+ while (v && !v->IsEnabled())
+ v = v->GetParent();
+ if (v && v != this) {
+ if (v != mouse_move_handler_) {
+ if (mouse_move_handler_ != NULL) {
+ MouseEvent exited_event(Event::ET_MOUSE_EXITED, 0, 0, 0);
+ mouse_move_handler_->OnMouseExited(exited_event);
+ }
+
+ mouse_move_handler_ = v;
+
+ MouseEvent entered_event(Event::ET_MOUSE_ENTERED,
+ this,
+ mouse_move_handler_,
+ e.location(),
+ 0);
+ mouse_move_handler_->OnMouseEntered(entered_event);
+ }
+ MouseEvent moved_event(Event::ET_MOUSE_MOVED,
+ this,
+ mouse_move_handler_,
+ e.location(),
+ 0);
+ mouse_move_handler_->OnMouseMoved(moved_event);
+
+#if defined(OS_WIN)
+ HCURSOR cursor = mouse_move_handler_->GetCursorForPoint(
+ moved_event.GetType(), moved_event.x(), moved_event.y());
+ if (cursor) {
+ previous_cursor_ = ::SetCursor(cursor);
+ } else if (previous_cursor_) {
+ ::SetCursor(previous_cursor_);
+ previous_cursor_ = NULL;
+ }
+#else
+ NOTIMPLEMENTED();
+#endif
+ } else if (mouse_move_handler_ != NULL) {
+ MouseEvent exited_event(Event::ET_MOUSE_EXITED, 0, 0, 0);
+ mouse_move_handler_->OnMouseExited(exited_event);
+#if defined(OS_WIN)
+ if (previous_cursor_) {
+ ::SetCursor(previous_cursor_);
+ previous_cursor_ = NULL;
+ }
+#else
+ NOTIMPLEMENTED();
+#endif
+ }
+}
+
+void RootView::ProcessOnMouseExited() {
+ if (mouse_move_handler_ != NULL) {
+ MouseEvent exited_event(Event::ET_MOUSE_EXITED, 0, 0, 0);
+ mouse_move_handler_->OnMouseExited(exited_event);
+ mouse_move_handler_ = NULL;
+ }
+}
+
+void RootView::SetMouseHandler(View *new_mh) {
+ // If we're clearing the mouse handler, clear explicit_mouse_handler as well.
+ explicit_mouse_handler_ = (new_mh != NULL);
+ mouse_pressed_handler_ = new_mh;
+}
+
+void RootView::OnWidgetCreated() {
+#if defined(OS_WIN)
+ DCHECK(!drop_target_.get());
+ drop_target_ = new RootViewDropTarget(this);
+#else
+ // TODO(port): Port RootViewDropTarget and this goes away.
+ NOTIMPLEMENTED();
+#endif
+}
+
+void RootView::OnWidgetDestroyed() {
+#if defined(OS_WIN)
+ if (drop_target_.get()) {
+ RevokeDragDrop(GetWidget()->GetNativeView());
+ drop_target_ = NULL;
+ }
+#else
+ // TODO(port): Port RootViewDropTarget and this goes away.
+ NOTIMPLEMENTED();
+#endif
+ widget_ = NULL;
+}
+
+void RootView::ProcessMouseDragCanceled() {
+ if (mouse_pressed_handler_) {
+ // Synthesize a release event.
+ MouseEvent release_event(Event::ET_MOUSE_RELEASED, last_mouse_event_x_,
+ last_mouse_event_y_, last_mouse_event_flags_);
+ OnMouseReleased(release_event, true);
+ }
+}
+
+void RootView::SetFocusListener(FocusListener* listener) {
+ focus_listener_ = listener;
+}
+
+void RootView::FocusView(View* view) {
+ if (view != GetFocusedView()) {
+#if defined(OS_WIN)
+ FocusManager* focus_manager = GetFocusManager();
+ DCHECK(focus_manager) << "No Focus Manager for Window " <<
+ (GetWidget() ? GetWidget()->GetNativeView() : 0);
+ if (!focus_manager)
+ return;
+
+ View* prev_focused_view = focus_manager->GetFocusedView();
+ focus_manager->SetFocusedView(view);
+
+ if (focus_listener_)
+ focus_listener_->FocusChanged(prev_focused_view, view);
+#else
+ // TODO(port): Port the focus manager and this goes away.
+ NOTIMPLEMENTED();
+#endif
+ }
+}
+
+View* RootView::GetFocusedView() {
+ FocusManager* focus_manager = GetFocusManager();
+ if (!focus_manager) {
+ // We may not have a FocusManager when the window that contains us is being
+ // deleted. Sadly we cannot wait for the window to be destroyed before we
+ // remove the FocusManager (see xp_frame.cc for more info).
+ return NULL;
+ }
+
+ // Make sure the focused view belongs to this RootView's view hierarchy.
+ View* view = focus_manager->GetFocusedView();
+ if (view && (view->GetRootView() == this))
+ return view;
+ return NULL;
+}
+
+View* RootView::FindNextFocusableView(View* starting_view,
+ bool reverse,
+ Direction direction,
+ bool dont_loop,
+ FocusTraversable** focus_traversable,
+ View** focus_traversable_view) {
+ *focus_traversable = NULL;
+ *focus_traversable_view = NULL;
+
+ if (GetChildViewCount() == 0) {
+ NOTREACHED();
+ // Nothing to focus on here.
+ return NULL;
+ }
+
+ bool skip_starting_view = true;
+ if (!starting_view) {
+ // Default to the first/last child
+ starting_view = reverse ? GetChildViewAt(GetChildViewCount() - 1) :
+ GetChildViewAt(0) ;
+ // If there was no starting view, then the one we select is a potential
+ // focus candidate.
+ skip_starting_view = false;
+ } else {
+ // The starting view should be part of this RootView.
+ DCHECK(IsParentOf(starting_view));
+ }
+
+ View* v = NULL;
+ if (!reverse) {
+ v = FindNextFocusableViewImpl(starting_view, skip_starting_view,
+ true,
+ (direction == DOWN) ? true : false,
+ starting_view->GetGroup());
+ } else {
+ // If the starting view is focusable, we don't want to go down, as we are
+ // traversing the view hierarchy tree bottom-up.
+ bool can_go_down = (direction == DOWN) && !starting_view->IsFocusable();
+ v = FindPreviousFocusableViewImpl(starting_view, true,
+ true,
+ can_go_down,
+ starting_view->GetGroup());
+ }
+ if (v) {
+ if (v->IsFocusable())
+ return v;
+ *focus_traversable = v->GetFocusTraversable();
+ DCHECK(*focus_traversable);
+ *focus_traversable_view = v;
+ return NULL;
+ }
+ // Nothing found.
+ return NULL;
+}
+
+// Strategy for finding the next focusable view:
+// - keep going down the first child, stop when you find a focusable view or
+// a focus traversable view (in that case return it) or when you reach a view
+// with no children.
+// - go to the right sibling and start the search from there (by invoking
+// FindNextFocusableViewImpl on that view).
+// - if the view has no right sibling, go up the parents until you find a parent
+// with a right sibling and start the search from there.
+View* RootView::FindNextFocusableViewImpl(View* starting_view,
+ bool skip_starting_view,
+ bool can_go_up,
+ bool can_go_down,
+ int skip_group_id) {
+ if (!skip_starting_view) {
+ if (IsViewFocusableCandidate(starting_view, skip_group_id))
+ return FindSelectedViewForGroup(starting_view);
+ if (starting_view->GetFocusTraversable())
+ return starting_view;
+ }
+
+ // First let's try the left child.
+ if (can_go_down) {
+ View* v = NULL;
+ if (starting_view->GetChildViewCount() > 0) {
+ // We are only interested in non floating-views, as attached floating
+ // views order is variable (depending on mouse moves).
+ for (int i = 0; i < starting_view->GetChildViewCount(); i++) {
+ View* child = starting_view->GetChildViewAt(i);
+ if (!child->IsFloatingView()) {
+ v = FindNextFocusableViewImpl(child, false, false, true,
+ skip_group_id);
+ break;
+ }
+ }
+ }
+ if (v == NULL) {
+ // Try the floating views.
+ int id = 0;
+ if (starting_view->EnumerateFloatingViews(View::FIRST, 0, &id)) {
+ View* child = starting_view->RetrieveFloatingViewForID(id);
+ DCHECK(child);
+ v = FindNextFocusableViewImpl(child, false, false, true, skip_group_id);
+ }
+ }
+ if (v)
+ return v;
+ }
+
+ // Then try the right sibling.
+ View* sibling = NULL;
+ if (starting_view->IsFloatingView()) {
+ int id = 0;
+ if (starting_view->GetParent()->EnumerateFloatingViews(
+ View::NEXT, starting_view->GetFloatingViewID(), &id)) {
+ sibling = starting_view->GetParent()->RetrieveFloatingViewForID(id);
+ DCHECK(sibling);
+ }
+ } else {
+ sibling = starting_view->GetNextFocusableView();
+ if (!sibling) {
+ // Let's try floating views.
+ int id = 0;
+ if (starting_view->GetParent()->EnumerateFloatingViews(View::FIRST,
+ 0, &id)) {
+ sibling = starting_view->GetParent()->RetrieveFloatingViewForID(id);
+ DCHECK(sibling);
+ }
+ }
+ }
+ if (sibling) {
+ View* v =
+ FindNextFocusableViewImpl(sibling, false, false, true, skip_group_id);
+ if (v)
+ return v;
+ }
+
+ // Then go up to the parent sibling.
+ if (can_go_up) {
+ View* parent = starting_view->GetParent();
+ while (parent) {
+ int id = 0;
+ if (parent->IsFloatingView() &&
+ parent->GetParent()->EnumerateFloatingViews(
+ View::NEXT, parent->GetFloatingViewID(), &id)) {
+ sibling = parent->GetParent()->RetrieveFloatingViewForID(id);
+ DCHECK(sibling);
+ } else {
+ sibling = parent->GetNextFocusableView();
+ }
+ if (sibling) {
+ return FindNextFocusableViewImpl(sibling,
+ false, true, true,
+ skip_group_id);
+ }
+ parent = parent->GetParent();
+ }
+ }
+
+ // We found nothing.
+ return NULL;
+}
+
+// Strategy for finding the previous focusable view:
+// - keep going down on the right until you reach a view with no children, if it
+// it is a good candidate return it.
+// - start the search on the left sibling.
+// - if there are no left sibling, start the search on the parent (without going
+// down).
+View* RootView::FindPreviousFocusableViewImpl(View* starting_view,
+ bool skip_starting_view,
+ bool can_go_up,
+ bool can_go_down,
+ int skip_group_id) {
+ // Let's go down and right as much as we can.
+ if (can_go_down) {
+ View* v = NULL;
+ if (starting_view->GetChildViewCount() -
+ starting_view->GetFloatingViewCount() > 0) {
+ View* view =
+ starting_view->GetChildViewAt(starting_view->GetChildViewCount() - 1);
+ v = FindPreviousFocusableViewImpl(view, false, false, true,
+ skip_group_id);
+ } else {
+ // Let's try floating views.
+ int id = 0;
+ if (starting_view->EnumerateFloatingViews(View::LAST, 0, &id)) {
+ View* child = starting_view->RetrieveFloatingViewForID(id);
+ DCHECK(child);
+ v = FindNextFocusableViewImpl(child, false, false, true, skip_group_id);
+ }
+ }
+ if (v)
+ return v;
+ }
+
+ if (!skip_starting_view) {
+ if (IsViewFocusableCandidate(starting_view, skip_group_id))
+ return FindSelectedViewForGroup(starting_view);
+ if (starting_view->GetFocusTraversable())
+ return starting_view;
+ }
+
+ // Then try the left sibling.
+ View* sibling = NULL;
+ if (starting_view->IsFloatingView()) {
+ int id = 0;
+ if (starting_view->GetParent()->EnumerateFloatingViews(
+ View::PREVIOUS, starting_view->GetFloatingViewID(), &id)) {
+ sibling = starting_view->GetParent()->RetrieveFloatingViewForID(id);
+ DCHECK(sibling);
+ }
+ if (!sibling) {
+ // No more floating views, try regular views, starting at the last one.
+ View* parent = starting_view->GetParent();
+ for (int i = parent->GetChildViewCount() - 1; i >= 0; i--) {
+ View* v = parent->GetChildViewAt(i);
+ if (!v->IsFloatingView()) {
+ sibling = v;
+ break;
+ }
+ }
+ }
+ } else {
+ sibling = starting_view->GetPreviousFocusableView();
+ }
+ if (sibling) {
+ return FindPreviousFocusableViewImpl(sibling,
+ false, true, true,
+ skip_group_id);
+ }
+
+ // Then go up the parent.
+ if (can_go_up) {
+ View* parent = starting_view->GetParent();
+ if (parent)
+ return FindPreviousFocusableViewImpl(parent,
+ false, true, false,
+ skip_group_id);
+ }
+
+ // We found nothing.
+ return NULL;
+}
+
+FocusTraversable* RootView::GetFocusTraversableParent() {
+ return focus_traversable_parent_;
+}
+
+void RootView::SetFocusTraversableParent(FocusTraversable* focus_traversable) {
+ DCHECK(focus_traversable != this);
+ focus_traversable_parent_ = focus_traversable;
+}
+
+View* RootView::GetFocusTraversableParentView() {
+ return focus_traversable_parent_view_;
+}
+
+void RootView::SetFocusTraversableParentView(View* view) {
+ focus_traversable_parent_view_ = view;
+}
+
+// static
+View* RootView::FindSelectedViewForGroup(View* view) {
+ if (view->IsGroupFocusTraversable() ||
+ view->GetGroup() == -1) // No group for that view.
+ return view;
+
+ View* selected_view = view->GetSelectedViewForGroup(view->GetGroup());
+ if (selected_view)
+ return selected_view;
+
+ // No view selected for that group, default to the specified view.
+ return view;
+}
+
+// static
+bool RootView::IsViewFocusableCandidate(View* v, int skip_group_id) {
+ return v->IsFocusable() &&
+ (v->IsGroupFocusTraversable() || skip_group_id == -1 ||
+ v->GetGroup() != skip_group_id);
+}
+
+bool RootView::ProcessKeyEvent(const KeyEvent& event) {
+ bool consumed = false;
+
+ View* v = GetFocusedView();
+#if defined(OS_WIN)
+ // Special case to handle right-click context menus triggered by the
+ // keyboard.
+ if (v && v->IsEnabled() && ((event.GetCharacter() == VK_APPS) ||
+ (event.GetCharacter() == VK_F10 && event.IsShiftDown()))) {
+ gfx::Point screen_loc = v->GetKeyboardContextMenuLocation();
+ v->ShowContextMenu(screen_loc.x(), screen_loc.y(), false);
+ return true;
+ }
+#else
+ // TODO(port): The above block needs the VK_* refactored out.
+ NOTIMPLEMENTED();
+#endif
+
+ for (; v && v != this && !consumed; v = v->GetParent()) {
+ consumed = (event.GetType() == Event::ET_KEY_PRESSED) ?
+ v->OnKeyPressed(event) : v->OnKeyReleased(event);
+ }
+
+ if (!consumed && default_keyboard_handler_) {
+ consumed = (event.GetType() == Event::ET_KEY_PRESSED) ?
+ default_keyboard_handler_->OnKeyPressed(event) :
+ default_keyboard_handler_->OnKeyReleased(event);
+ }
+
+ return consumed;
+}
+
+bool RootView::ProcessMouseWheelEvent(const MouseWheelEvent& e) {
+ View* v;
+ bool consumed = false;
+ if (GetFocusedView()) {
+ for (v = GetFocusedView();
+ v && v != this && !consumed; v = v->GetParent()) {
+ consumed = v->OnMouseWheel(e);
+ }
+ }
+
+ if (!consumed && default_keyboard_handler_) {
+ consumed = default_keyboard_handler_->OnMouseWheel(e);
+ }
+ return consumed;
+}
+
+void RootView::SetDefaultKeyboardHandler(View* v) {
+ default_keyboard_handler_ = v;
+}
+
+bool RootView::IsVisibleInRootView() const {
+ return IsVisible();
+}
+
+void RootView::ViewBoundsChanged(View* view, bool size_changed,
+ bool position_changed) {
+ DCHECK(view && (size_changed || position_changed));
+ if (!view->descendants_to_notify_.get())
+ return;
+
+ for (std::vector<View*>::iterator i = view->descendants_to_notify_->begin();
+ i != view->descendants_to_notify_->end(); ++i) {
+ (*i)->VisibleBoundsInRootChanged();
+ }
+}
+
+void RootView::RegisterViewForVisibleBoundsNotification(View* view) {
+ DCHECK(view);
+ if (view->registered_for_visible_bounds_notification_)
+ return;
+ view->registered_for_visible_bounds_notification_ = true;
+ View* ancestor = view->GetParent();
+ while (ancestor) {
+ ancestor->AddDescendantToNotify(view);
+ ancestor = ancestor->GetParent();
+ }
+}
+
+void RootView::UnregisterViewForVisibleBoundsNotification(View* view) {
+ DCHECK(view);
+ if (!view->registered_for_visible_bounds_notification_)
+ return;
+ view->registered_for_visible_bounds_notification_ = false;
+ View* ancestor = view->GetParent();
+ while (ancestor) {
+ ancestor->RemoveDescendantToNotify(view);
+ ancestor = ancestor->GetParent();
+ }
+}
+
+void RootView::SetMouseLocationAndFlags(const MouseEvent& e) {
+ last_mouse_event_flags_ = e.GetFlags();
+ last_mouse_event_x_ = e.x();
+ last_mouse_event_y_ = e.y();
+}
+
+std::string RootView::GetClassName() const {
+ return kViewClassName;
+}
+
+void RootView::ClearPaintRect() {
+ invalid_rect_.SetRect(0, 0, 0, 0);
+
+ // This painting has been done. Reset the urgent flag.
+ invalid_rect_urgent_ = false;
+
+ // If a pending_paint_task_ does Run(), we don't need to do anything.
+ paint_task_needed_ = false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView - accessibility
+//
+/////////////////////////////////////////////////////////////////////////////
+
+bool RootView::GetAccessibleRole(AccessibilityTypes::Role* role) {
+ DCHECK(role);
+
+ *role = AccessibilityTypes::ROLE_APPLICATION;
+ return true;
+}
+
+bool RootView::GetAccessibleName(std::wstring* name) {
+ if (!accessible_name_.empty()) {
+ *name = accessible_name_;
+ return true;
+ }
+ return false;
+}
+
+void RootView::SetAccessibleName(const std::wstring& name) {
+ accessible_name_.assign(name);
+}
+
+View* RootView::GetDragView() {
+ return drag_view_;
+}
+
+} // namespace views
diff --git a/views/widget/root_view.h b/views/widget/root_view.h
new file mode 100644
index 0000000..d775ac1
--- /dev/null
+++ b/views/widget/root_view.h
@@ -0,0 +1,363 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_ROOT_VIEW_H_
+#define VIEWS_WIDGET_ROOT_VIEW_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_LINUX)
+#include <gtk/gtk.h>
+#endif
+
+#if defined(OS_WIN)
+#include "base/ref_counted.h"
+#endif
+
+#include "views/focus/focus_manager.h"
+#include "views/view.h"
+
+namespace views {
+
+class PaintTask;
+class RootViewDropTarget;
+class Widget;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// FocusListener Interface
+//
+////////////////////////////////////////////////////////////////////////////////
+class FocusListener {
+ public:
+ virtual void FocusChanged(View* lost_focus, View* got_focus) = 0;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RootView class
+//
+// The RootView is the root of a View hierarchy. A RootView is always the
+// first and only child of a Widget.
+//
+// The RootView manages the View hierarchy's interface with the Widget
+// and also maintains the current invalid rect - the region that needs
+// repainting.
+//
+/////////////////////////////////////////////////////////////////////////////
+class RootView : public View,
+ public FocusTraversable {
+ public:
+ static const char kViewClassName[];
+
+ explicit RootView(Widget* widget);
+
+ virtual ~RootView();
+
+ // Layout and Painting functions
+
+ // Overridden from View to implement paint scheduling.
+ virtual void SchedulePaint(const gfx::Rect& r, bool urgent);
+
+ // Convenience to schedule the whole view
+ virtual void SchedulePaint();
+
+ // Convenience to schedule a paint given some ints
+ virtual void SchedulePaint(int x, int y, int w, int h);
+
+ // Paint this RootView and its child Views.
+ virtual void ProcessPaint(ChromeCanvas* canvas);
+
+ // If the invalid rect is non-empty and there is a pending paint the RootView
+ // is painted immediately. This is internally invoked as the result of
+ // invoking SchedulePaint.
+ virtual void PaintNow();
+
+ // Whether or not this View needs repainting. If |urgent| is true, this method
+ // returns whether this root view needs to paint as soon as possible.
+ virtual bool NeedsPainting(bool urgent);
+
+ // Invoked by the Widget to discover what rectangle should be painted.
+ const gfx::Rect& GetScheduledPaintRect();
+
+ // Returns the region scheduled to paint clipped to the RootViews bounds.
+ gfx::Rect GetScheduledPaintRectConstrainedToSize();
+
+ // Tree functions
+
+ // Get the Widget that hosts this View.
+ virtual Widget* GetWidget() const;
+
+ // Public API for broadcasting theme change notifications to this View
+ // hierarchy.
+ virtual void ThemeChanged();
+
+ // The following event methods are overridden to propagate event to the
+ // control tree
+ virtual bool OnMousePressed(const MouseEvent& e);
+ virtual bool OnMouseDragged(const MouseEvent& e);
+ virtual void OnMouseReleased(const MouseEvent& e, bool canceled);
+ virtual void OnMouseMoved(const MouseEvent& e);
+ virtual void SetMouseHandler(View* new_mouse_handler);
+
+ // Invoked when the Widget has been fully initialized.
+ // At the time the constructor is invoked the Widget may not be completely
+ // initialized, when this method is invoked, it is.
+ void OnWidgetCreated();
+
+ // Invoked prior to the Widget being destroyed.
+ void OnWidgetDestroyed();
+
+ // Invoked By the Widget if the mouse drag is interrupted by
+ // the system. Invokes OnMouseReleased with a value of true for canceled.
+ void ProcessMouseDragCanceled();
+
+ // Invoked by the Widget instance when the mouse moves outside of the Widget
+ // bounds.
+ virtual void ProcessOnMouseExited();
+
+ // Make the provided view focused. Also make sure that our Widget is focused.
+ void FocusView(View* view);
+
+ // Check whether the provided view is in the focus path. The focus path is the
+ // path between the focused view (included) to the root view.
+ bool IsInFocusPath(View* view);
+
+ // Returns the View in this RootView hierarchy that has the focus, or NULL if
+ // no View currently has the focus.
+ View* GetFocusedView();
+
+ // Process a key event. Send the event to the focused view and up the focus
+ // path, and finally to the default keyboard handler, until someone consumes
+ // it. Returns whether anyone consumed the event.
+ bool ProcessKeyEvent(const KeyEvent& event);
+
+ // Set the default keyboard handler. The default keyboard handler is
+ // a view that will get an opportunity to process key events when all
+ // views in the focus path did not process an event.
+ //
+ // Note: this is a single view at this point. We may want to make
+ // this a list if needed.
+ void SetDefaultKeyboardHandler(View* v);
+
+ // Set whether this root view should focus the corresponding hwnd
+ // when an unprocessed mouse event occurs.
+ void SetFocusOnMousePressed(bool f);
+
+ // Process a mousewheel event. Return true if the event was processed
+ // and false otherwise.
+ // MouseWheel events are sent on the focus path.
+ virtual bool ProcessMouseWheelEvent(const MouseWheelEvent& e);
+
+ // Overridden to handle special root view case.
+ virtual bool IsVisibleInRootView() const;
+
+ // Sets a listener that receives focus changes events.
+ void SetFocusListener(FocusListener* listener);
+
+ // FocusTraversable implementation.
+ virtual View* FindNextFocusableView(View* starting_view,
+ bool reverse,
+ Direction direction,
+ bool dont_loop,
+ FocusTraversable** focus_traversable,
+ View** focus_traversable_view);
+ virtual FocusTraversable* GetFocusTraversableParent();
+ virtual View* GetFocusTraversableParentView();
+
+ // Used to set the FocusTraversable parent after the view has been created
+ // (typically when the hierarchy changes and this RootView is added/removed).
+ virtual void SetFocusTraversableParent(FocusTraversable* focus_traversable);
+
+ // Used to set the View parent after the view has been created.
+ virtual void SetFocusTraversableParentView(View* view);
+
+ // Returns the name of this class: views/RootView
+ virtual std::string GetClassName() const;
+
+ // Clears the region that is schedule to be painted. You nearly never need
+ // to invoke this. This is primarily intended for Widgets.
+ void ClearPaintRect();
+
+#if defined(OS_WIN)
+ // Invoked from the Widget to service a WM_PAINT call.
+ void OnPaint(HWND hwnd);
+#elif defined(OS_LINUX)
+ void OnPaint(GdkEventExpose* event);
+#endif
+
+ // Accessibility accessors/mutators, overridden from View.
+ virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual bool GetAccessibleName(std::wstring* name);
+ virtual void SetAccessibleName(const std::wstring& name);
+
+ protected:
+
+ // Overridden to properly reset our event propagation member
+ // variables when a child is removed
+ virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child);
+
+#ifndef NDEBUG
+ virtual bool IsProcessingPaint() const { return is_processing_paint_; }
+#endif
+
+ private:
+ friend class View;
+ friend class PaintTask;
+
+ RootView();
+ DISALLOW_EVIL_CONSTRUCTORS(RootView);
+
+ // Convert a point to our current mouse handler. Returns false if the
+ // mouse handler is not connected to a Widget. In that case, the
+ // conversion cannot take place and *p is unchanged
+ bool ConvertPointToMouseHandler(const gfx::Point& l, gfx::Point *p);
+
+ // Update the cursor given a mouse event. This is called by non mouse_move
+ // event handlers to honor the cursor desired by views located under the
+ // cursor during drag operations.
+ void UpdateCursor(const MouseEvent& e);
+
+ // Notification that size and/or position of a view has changed. This
+ // notifies the appropriate views.
+ void ViewBoundsChanged(View* view, bool size_changed, bool position_changed);
+
+ // Registers a view for notification when the visible bounds relative to the
+ // root of a view changes.
+ void RegisterViewForVisibleBoundsNotification(View* view);
+ void UnregisterViewForVisibleBoundsNotification(View* view);
+
+ // Returns the next focusable view or view containing a FocusTraversable (NULL
+ // if none was found), starting at the starting_view.
+ // skip_starting_view, can_go_up and can_go_down controls the traversal of
+ // the views hierarchy.
+ // skip_group_id specifies a group_id, -1 means no group. All views from a
+ // group are traversed in one pass.
+ View* FindNextFocusableViewImpl(View* starting_view,
+ bool skip_starting_view,
+ bool can_go_up,
+ bool can_go_down,
+ int skip_group_id);
+
+ // Same as FindNextFocusableViewImpl but returns the previous focusable view.
+ View* FindPreviousFocusableViewImpl(View* starting_view,
+ bool skip_starting_view,
+ bool can_go_up,
+ bool can_go_down,
+ int skip_group_id);
+
+ // Convenience method that returns true if a view is focusable and does not
+ // belong to the specified group.
+ bool IsViewFocusableCandidate(View* v, int skip_group_id);
+
+ // Returns the view selected for the group of the selected view. If the view
+ // does not belong to a group or if no view is selected in the group, the
+ // specified view is returned.
+ static View* FindSelectedViewForGroup(View* view);
+
+ // Updates the last_mouse_* fields from e.
+ void SetMouseLocationAndFlags(const MouseEvent& e);
+
+#if defined(OS_WIN)
+ // Starts a drag operation for the specified view. This blocks until done.
+ // If the view has not been deleted during the drag, OnDragDone is invoked
+ // on the view.
+ void StartDragForViewFromMouseEvent(View* view,
+ IDataObject* data,
+ int operation);
+#endif
+
+ // If a view is dragging, this returns it. Otherwise returns NULL.
+ View* GetDragView();
+
+ // The view currently handing down - drag - up
+ View* mouse_pressed_handler_;
+
+ // The view currently handling enter / exit
+ View* mouse_move_handler_;
+
+ // The last view to handle a mouse click, so that we can determine if
+ // a double-click lands on the same view as its single-click part.
+ View* last_click_handler_;
+
+ // The host Widget
+ Widget* widget_;
+
+ // The rectangle that should be painted
+ gfx::Rect invalid_rect_;
+
+ // Whether the current invalid rect should be painted urgently.
+ bool invalid_rect_urgent_;
+
+ // The task that we are using to trigger some non urgent painting or NULL
+ // if no painting has been scheduled yet.
+ PaintTask* pending_paint_task_;
+
+ // Indicate if, when the pending_paint_task_ is run, actual painting is still
+ // required.
+ bool paint_task_needed_;
+
+ // true if mouse_handler_ has been explicitly set
+ bool explicit_mouse_handler_;
+
+#if defined(OS_WIN)
+ // Previous cursor
+ HCURSOR previous_cursor_;
+#endif
+
+ // Default keyboard handler
+ View* default_keyboard_handler_;
+
+ // The listener that gets focus change notifications.
+ FocusListener* focus_listener_;
+
+ // Whether this root view should make our hwnd focused
+ // when an unprocessed mouse press event occurs
+ bool focus_on_mouse_pressed_;
+
+ // Flag used to ignore focus events when we focus the native window associated
+ // with a view.
+ bool ignore_set_focus_calls_;
+
+ // Whether this root view belongs to the current active window.
+ // bool activated_;
+
+ // Last position/flag of a mouse press/drag. Used if capture stops and we need
+ // to synthesize a release.
+ int last_mouse_event_flags_;
+ int last_mouse_event_x_;
+ int last_mouse_event_y_;
+
+ // The parent FocusTraversable, used for focus traversal.
+ FocusTraversable* focus_traversable_parent_;
+
+ // The View that contains this RootView. This is used when we have RootView
+ // wrapped inside native components, and is used for the focus traversal.
+ View* focus_traversable_parent_view_;
+
+#if defined(OS_WIN)
+ // Handles dnd for us.
+ scoped_refptr<RootViewDropTarget> drop_target_;
+#endif
+
+ // Storage of strings needed for accessibility.
+ std::wstring accessible_name_;
+
+ // Tracks drag state for a view.
+ View::DragInfo drag_info;
+
+ // Valid for the lifetime of StartDragForViewFromMouseEvent, indicates the
+ // view the drag started from.
+ View* drag_view_;
+
+#ifndef NDEBUG
+ // True if we're currently processing paint.
+ bool is_processing_paint_;
+#endif
+};
+
+} // namespace views
+
+#endif // VIEWS_WIDGET_ROOT_VIEW_H_
diff --git a/views/widget/root_view_drop_target.cc b/views/widget/root_view_drop_target.cc
new file mode 100644
index 0000000..9c1f087
--- /dev/null
+++ b/views/widget/root_view_drop_target.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/root_view_drop_target.h"
+
+#include "app/drag_drop_types.h"
+#include "base/gfx/point.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+RootViewDropTarget::RootViewDropTarget(RootView* root_view)
+ : BaseDropTarget(root_view->GetWidget()->GetNativeView()),
+ root_view_(root_view),
+ target_view_(NULL),
+ deepest_view_(NULL) {
+}
+
+RootViewDropTarget::~RootViewDropTarget() {
+}
+
+void RootViewDropTarget::ResetTargetViewIfEquals(View* view) {
+ if (target_view_ == view)
+ target_view_ = NULL;
+ if (deepest_view_ == view)
+ deepest_view_ = NULL;
+}
+
+DWORD RootViewDropTarget::OnDragOver(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect) {
+ const OSExchangeData data(data_object);
+ gfx::Point root_view_location(cursor_position.x, cursor_position.y);
+ View::ConvertPointToView(NULL, root_view_, &root_view_location);
+ View* view = CalculateTargetView(root_view_location, data);
+
+ if (view != target_view_) {
+ // Target changed notify old drag exited, then new drag entered.
+ if (target_view_)
+ target_view_->OnDragExited();
+ target_view_ = view;
+ if (target_view_) {
+ gfx::Point target_view_location(root_view_location);
+ View::ConvertPointToView(root_view_, target_view_, &target_view_location);
+ DropTargetEvent enter_event(data,
+ target_view_location.x(),
+ target_view_location.y(),
+ DragDropTypes::DropEffectToDragOperation(effect));
+ target_view_->OnDragEntered(enter_event);
+ }
+ }
+
+ if (target_view_) {
+ gfx::Point target_view_location(root_view_location);
+ View::ConvertPointToView(root_view_, target_view_, &target_view_location);
+ DropTargetEvent enter_event(data,
+ target_view_location.x(),
+ target_view_location.y(),
+ DragDropTypes::DropEffectToDragOperation(effect));
+ int result_operation = target_view_->OnDragUpdated(enter_event);
+ return DragDropTypes::DragOperationToDropEffect(result_operation);
+ } else {
+ return DROPEFFECT_NONE;
+ }
+}
+
+void RootViewDropTarget::OnDragLeave(IDataObject* data_object) {
+ if (target_view_)
+ target_view_->OnDragExited();
+ deepest_view_ = target_view_ = NULL;
+}
+
+DWORD RootViewDropTarget::OnDrop(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect) {
+ const OSExchangeData data(data_object);
+ DWORD drop_effect = OnDragOver(data_object, key_state, cursor_position,
+ effect);
+ View* drop_view = target_view_;
+ deepest_view_ = target_view_ = NULL;
+ if (drop_effect != DROPEFFECT_NONE) {
+ gfx::Point view_location(cursor_position.x, cursor_position.y);
+ View::ConvertPointToView(NULL, drop_view, &view_location);
+ DropTargetEvent drop_event(data, view_location.x(), view_location.y(),
+ DragDropTypes::DropEffectToDragOperation(effect));
+ return DragDropTypes::DragOperationToDropEffect(
+ drop_view->OnPerformDrop(drop_event));
+ } else {
+ if (drop_view)
+ drop_view->OnDragExited();
+ return DROPEFFECT_NONE;
+ }
+}
+
+View* RootViewDropTarget::CalculateTargetView(
+ const gfx::Point& root_view_location,
+ const OSExchangeData& data) {
+ View* view = root_view_->GetViewForPoint(root_view_location);
+ if (view == deepest_view_) {
+ // The view the mouse is over hasn't changed; reuse the target.
+ return target_view_;
+ }
+ // View under mouse changed, which means a new view may want the drop.
+ // Walk the tree, stopping at target_view_ as we know it'll accept the
+ // drop.
+ deepest_view_ = view;
+ while (view && view != target_view_ &&
+ (!view->IsEnabled() || !view->CanDrop(data))) {
+ view = view->GetParent();
+ }
+ return view;
+}
+
+} // namespace views
diff --git a/views/widget/root_view_drop_target.h b/views/widget/root_view_drop_target.h
new file mode 100644
index 0000000..a3c3afd
--- /dev/null
+++ b/views/widget/root_view_drop_target.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_ROOT_VIEW_DROP_TARGET_H_
+#define VIEWS_WIDGET_ROOT_VIEW_DROP_TARGET_H_
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlmisc.h>
+
+#include "app/os_exchange_data.h"
+#include "base/base_drop_target.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace views {
+
+class RootView;
+class View;
+
+// RootViewDropTarget takes care of managing drag and drop for the RootView and
+// converts Windows OLE drop messages into Views drop messages.
+//
+// RootViewDropTarget is responsible for determining the appropriate View to
+// use during a drag and drop session, and forwarding events to it.
+class RootViewDropTarget : public BaseDropTarget {
+ public:
+ explicit RootViewDropTarget(RootView* root_view);
+ virtual ~RootViewDropTarget();
+
+ // If a drag and drop is underway and view is the current drop target, the
+ // drop target is set to null.
+ // This is invoked when a View is removed from the RootView to make sure
+ // we don't target a view that was removed during dnd.
+ void ResetTargetViewIfEquals(View* view);
+
+ protected:
+ virtual DWORD OnDragOver(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect);
+
+ virtual void OnDragLeave(IDataObject* data_object);
+
+ virtual DWORD OnDrop(IDataObject* data_object,
+ DWORD key_state,
+ POINT cursor_position,
+ DWORD effect);
+
+ private:
+ // Calculates the target view for a drop given the specified location in
+ // the coordinate system of the rootview. This tries to avoid continually
+ // querying CanDrop by returning target_view_ if the mouse is still over
+ // target_view_.
+ View* CalculateTargetView(const gfx::Point& root_view_location,
+ const OSExchangeData& data);
+
+ // RootView we were created for.
+ RootView* root_view_;
+
+ // View we're targeting events at.
+ View* target_view_;
+
+ // The deepest view under the current drop coordinate.
+ View* deepest_view_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RootViewDropTarget);
+};
+
+} // namespace views
+
+#endif // VIEWS_WIDGET_ROOT_VIEW_DROP_TARGET_H_
diff --git a/views/widget/root_view_gtk.cc b/views/widget/root_view_gtk.cc
new file mode 100644
index 0000000..428c695
--- /dev/null
+++ b/views/widget/root_view_gtk.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/root_view.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "base/logging.h"
+#include "skia/include/SkColor.h"
+
+namespace views {
+
+void RootView::UpdateCursor(const MouseEvent& e) {
+ NOTIMPLEMENTED();
+}
+
+void RootView::OnPaint(GdkEventExpose* event) {
+ ChromeCanvasPaint canvas(event);
+
+ if (!canvas.isEmpty()) {
+ SchedulePaint(gfx::Rect(canvas.rectangle()), false);
+ if (NeedsPainting(false)) {
+ ProcessPaint(&canvas);
+ }
+ }
+}
+
+}
diff --git a/views/widget/root_view_win.cc b/views/widget/root_view_win.cc
new file mode 100644
index 0000000..ac4a50d
--- /dev/null
+++ b/views/widget/root_view_win.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/root_view.h"
+
+#include "app/drag_drop_types.h"
+#include "app/gfx/chrome_canvas.h"
+#include "base/base_drag_source.h"
+#include "base/logging.h"
+#include "views/widget/root_view_drop_target.h"
+
+namespace views {
+
+void RootView::UpdateCursor(const MouseEvent& e) {
+ View *v = GetViewForPoint(e.location());
+
+ if (v && v != this) {
+ gfx::Point l(e.location());
+ View::ConvertPointToView(this, v, &l);
+ HCURSOR cursor = v->GetCursorForPoint(e.GetType(), l.x(), l.y());
+ if (cursor) {
+ ::SetCursor(cursor);
+ return;
+ }
+ }
+ if (previous_cursor_) {
+ SetCursor(previous_cursor_);
+ }
+}
+
+void RootView::OnPaint(HWND hwnd) {
+ gfx::Rect original_dirty_region = GetScheduledPaintRectConstrainedToSize();
+ if (!original_dirty_region.IsEmpty()) {
+ // Invoke InvalidateRect so that the dirty region of the window includes the
+ // region we need to paint. If we didn't do this and the region didn't
+ // include the dirty region, ProcessPaint would incorrectly mark everything
+ // as clean. This can happen if a WM_PAINT is generated by the system before
+ // the InvokeLater schedule by RootView is processed.
+ RECT win_version = original_dirty_region.ToRECT();
+ InvalidateRect(hwnd, &win_version, FALSE);
+ }
+ ChromeCanvasPaint canvas(hwnd);
+ if (!canvas.isEmpty()) {
+ const PAINTSTRUCT& ps = canvas.paintStruct();
+ SchedulePaint(gfx::Rect(ps.rcPaint), false);
+ if (NeedsPainting(false))
+ ProcessPaint(&canvas);
+ }
+}
+
+void RootView::StartDragForViewFromMouseEvent(
+ View* view,
+ IDataObject* data,
+ int operation) {
+ drag_view_ = view;
+ scoped_refptr<BaseDragSource> drag_source(new BaseDragSource);
+ DWORD effects;
+ DoDragDrop(data, drag_source,
+ DragDropTypes::DragOperationToDropEffect(operation), &effects);
+ // If the view is removed during the drag operation, drag_view_ is set to
+ // NULL.
+ if (drag_view_ == view) {
+ View* drag_view = drag_view_;
+ drag_view_ = NULL;
+ drag_view->OnDragDone();
+ }
+}
+
+}
diff --git a/views/widget/tooltip_manager.cc b/views/widget/tooltip_manager.cc
new file mode 100644
index 0000000..18faf4a
--- /dev/null
+++ b/views/widget/tooltip_manager.cc
@@ -0,0 +1,447 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/tooltip_manager.h"
+
+#include <limits>
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_win.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "chrome/common/gfx/text_elider.h"
+#include "chrome/common/win_util.h"
+#include "views/view.h"
+#include "views/widget/root_view.h"
+#include "views/widget/widget.h"
+
+namespace views {
+
+//static
+int TooltipManager::tooltip_height_ = 0;
+
+// Default timeout for the tooltip displayed using keyboard.
+// Timeout is mentioned in milliseconds.
+static const int kDefaultTimeout = 4000;
+
+// Maximum number of lines we allow in the tooltip.
+static const int kMaxLines = 6;
+
+// Maximum number of characters we allow in a tooltip.
+static const int kMaxTooltipLength = 1024;
+
+// Breaks |text| along line boundaries, placing each line of text into lines.
+static void SplitTooltipString(const std::wstring& text,
+ std::vector<std::wstring>* lines) {
+ size_t index = 0;
+ size_t next_index;
+ while ((next_index = text.find(TooltipManager::GetLineSeparator(), index))
+ != std::wstring::npos && lines->size() < kMaxLines) {
+ lines->push_back(text.substr(index, next_index - index));
+ index = next_index + TooltipManager::GetLineSeparator().size();
+ }
+ if (next_index != text.size() && lines->size() < kMaxLines)
+ lines->push_back(text.substr(index, text.size() - index));
+}
+
+// static
+int TooltipManager::GetTooltipHeight() {
+ DCHECK(tooltip_height_ > 0);
+ return tooltip_height_;
+}
+
+static ChromeFont DetermineDefaultFont() {
+ HWND window = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, 0 , 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ HFONT hfont = reinterpret_cast<HFONT>(SendMessage(window, WM_GETFONT, 0, 0));
+ ChromeFont font = hfont ? ChromeFont::CreateFont(hfont) : ChromeFont();
+ DestroyWindow(window);
+ return font;
+}
+
+// static
+ChromeFont TooltipManager::GetDefaultFont() {
+ static ChromeFont* font = NULL;
+ if (!font)
+ font = new ChromeFont(DetermineDefaultFont());
+ return *font;
+}
+
+// static
+const std::wstring& TooltipManager::GetLineSeparator() {
+ static const std::wstring* separator = NULL;
+ if (!separator)
+ separator = new std::wstring(L"\r\n");
+ return *separator;
+}
+
+TooltipManager::TooltipManager(Widget* widget, HWND parent)
+ : widget_(widget),
+ parent_(parent),
+ last_mouse_x_(-1),
+ last_mouse_y_(-1),
+ tooltip_showing_(false),
+ last_tooltip_view_(NULL),
+ last_view_out_of_sync_(false),
+ tooltip_width_(0),
+ keyboard_tooltip_hwnd_(NULL),
+#pragma warning(suppress: 4355)
+ keyboard_tooltip_factory_(this) {
+ DCHECK(widget && parent);
+ Init();
+}
+
+TooltipManager::~TooltipManager() {
+ if (tooltip_hwnd_)
+ DestroyWindow(tooltip_hwnd_);
+ if (keyboard_tooltip_hwnd_)
+ DestroyWindow(keyboard_tooltip_hwnd_);
+}
+
+void TooltipManager::Init() {
+ // Create the tooltip control.
+ tooltip_hwnd_ = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0,
+ parent_, NULL, NULL, NULL);
+
+ l10n_util::AdjustUIFontForWindow(tooltip_hwnd_);
+
+ // This effectively turns off clipping of tooltips. We need this otherwise
+ // multi-line text (\r\n) won't work right. The size doesn't really matter
+ // (just as long as its bigger than the monitor's width) as we clip to the
+ // screen size before rendering.
+ SendMessage(tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
+ std::numeric_limits<short>::max());
+
+ // Add one tool that is used for all tooltips.
+ toolinfo_.cbSize = sizeof(toolinfo_);
+ toolinfo_.uFlags = TTF_TRANSPARENT | TTF_IDISHWND;
+ toolinfo_.hwnd = parent_;
+ toolinfo_.uId = reinterpret_cast<UINT_PTR>(parent_);
+ // Setting this tells windows to call parent_ back (using a WM_NOTIFY
+ // message) for the actual tooltip contents.
+ toolinfo_.lpszText = LPSTR_TEXTCALLBACK;
+ SetRectEmpty(&toolinfo_.rect);
+ SendMessage(tooltip_hwnd_, TTM_ADDTOOL, 0, (LPARAM)&toolinfo_);
+}
+
+void TooltipManager::UpdateTooltip() {
+ // Set last_view_out_of_sync_ to indicate the view is currently out of sync.
+ // This doesn't update the view under the mouse immediately as it may cause
+ // timing problems.
+ last_view_out_of_sync_ = true;
+ last_tooltip_view_ = NULL;
+ // Hide the tooltip.
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+}
+
+void TooltipManager::TooltipTextChanged(View* view) {
+ if (view == last_tooltip_view_)
+ UpdateTooltip(last_mouse_x_, last_mouse_y_);
+}
+
+LRESULT TooltipManager::OnNotify(int w_param, NMHDR* l_param, bool* handled) {
+ *handled = false;
+ if (l_param->hwndFrom == tooltip_hwnd_ && keyboard_tooltip_hwnd_ == NULL) {
+ switch (l_param->code) {
+ case TTN_GETDISPINFO: {
+ if (last_view_out_of_sync_) {
+ // View under the mouse is out of sync, determine it now.
+ RootView* root_view = widget_->GetRootView();
+ last_tooltip_view_ = root_view->GetViewForPoint(
+ gfx::Point(last_mouse_x_, last_mouse_y_));
+ last_view_out_of_sync_ = false;
+ }
+ // Tooltip control is asking for the tooltip to display.
+ NMTTDISPINFOW* tooltip_info =
+ reinterpret_cast<NMTTDISPINFOW*>(l_param);
+ // Initialize the string, if we have a valid tooltip the string will
+ // get reset below.
+ tooltip_info->szText[0] = TEXT('\0');
+ tooltip_text_.clear();
+ tooltip_info->lpszText = NULL;
+ clipped_text_.clear();
+ if (last_tooltip_view_ != NULL) {
+ tooltip_text_.clear();
+ // Mouse is over a View, ask the View for it's tooltip.
+ gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
+ View::ConvertPointToView(widget_->GetRootView(),
+ last_tooltip_view_, &view_loc);
+ if (last_tooltip_view_->GetTooltipText(view_loc.x(), view_loc.y(),
+ &tooltip_text_) &&
+ !tooltip_text_.empty()) {
+ // View has a valid tip, copy it into TOOLTIPINFO.
+ clipped_text_ = tooltip_text_;
+ TrimTooltipToFit(&clipped_text_, &tooltip_width_, &line_count_,
+ last_mouse_x_, last_mouse_y_, tooltip_hwnd_);
+ // Adjust the clipped tooltip text for locale direction.
+ l10n_util::AdjustStringForLocaleDirection(clipped_text_,
+ &clipped_text_);
+ tooltip_info->lpszText = const_cast<WCHAR*>(clipped_text_.c_str());
+ } else {
+ tooltip_text_.clear();
+ }
+ }
+ *handled = true;
+ return 0;
+ }
+ case TTN_POP:
+ tooltip_showing_ = false;
+ *handled = true;
+ return 0;
+ case TTN_SHOW: {
+ *handled = true;
+ tooltip_showing_ = true;
+ // The tooltip is about to show, allow the view to position it
+ gfx::Point text_origin;
+ if (tooltip_height_ == 0)
+ tooltip_height_ = CalcTooltipHeight();
+ gfx::Point view_loc(last_mouse_x_, last_mouse_y_);
+ View::ConvertPointToView(widget_->GetRootView(),
+ last_tooltip_view_, &view_loc);
+ if (last_tooltip_view_->GetTooltipTextOrigin(
+ view_loc.x(), view_loc.y(), &text_origin) &&
+ SetTooltipPosition(text_origin.x(), text_origin.y())) {
+ // Return true, otherwise the rectangle we specified is ignored.
+ return TRUE;
+ }
+ return 0;
+ }
+ default:
+ // Fall through.
+ break;
+ }
+ }
+ return 0;
+}
+
+bool TooltipManager::SetTooltipPosition(int text_x, int text_y) {
+ // NOTE: this really only tests that the y location fits on screen, but that
+ // is good enough for our usage.
+
+ // Calculate the bounds the tooltip will get.
+ gfx::Point view_loc;
+ View::ConvertPointToScreen(last_tooltip_view_, &view_loc);
+ RECT bounds = { view_loc.x() + text_x,
+ view_loc.y() + text_y,
+ view_loc.x() + text_x + tooltip_width_,
+ view_loc.y() + line_count_ * GetTooltipHeight() };
+ SendMessage(tooltip_hwnd_, TTM_ADJUSTRECT, TRUE, (LPARAM)&bounds);
+
+ // Make sure the rectangle completely fits on the current monitor. If it
+ // doesn't, return false so that windows positions the tooltip at the
+ // default location.
+ gfx::Rect monitor_bounds =
+ win_util::GetMonitorBoundsForRect(gfx::Rect(bounds.left,bounds.right,
+ 0, 0));
+ if (!monitor_bounds.Contains(gfx::Rect(bounds))) {
+ return false;
+ }
+
+ ::SetWindowPos(tooltip_hwnd_, NULL, bounds.left, bounds.top, 0, 0,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+ return true;
+}
+
+int TooltipManager::CalcTooltipHeight() {
+ // Ask the tooltip for it's font.
+ int height;
+ HFONT hfont = reinterpret_cast<HFONT>(
+ SendMessage(tooltip_hwnd_, WM_GETFONT, 0, 0));
+ if (hfont != NULL) {
+ HDC dc = GetDC(tooltip_hwnd_);
+ HFONT previous_font = static_cast<HFONT>(SelectObject(dc, hfont));
+ int last_map_mode = SetMapMode(dc, MM_TEXT);
+ TEXTMETRIC font_metrics;
+ GetTextMetrics(dc, &font_metrics);
+ height = font_metrics.tmHeight;
+ // To avoid the DC referencing font_handle_, select the previous font.
+ SelectObject(dc, previous_font);
+ SetMapMode(dc, last_map_mode);
+ ReleaseDC(NULL, dc);
+ } else {
+ // Tooltip is using the system font. Use ChromeFont, which should pick
+ // up the system font.
+ height = ChromeFont().height();
+ }
+ // Get the margins from the tooltip
+ RECT tooltip_margin;
+ SendMessage(tooltip_hwnd_, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
+ return height + tooltip_margin.top + tooltip_margin.bottom;
+}
+
+void TooltipManager::TrimTooltipToFit(std::wstring* text,
+ int* max_width,
+ int* line_count,
+ int position_x,
+ int position_y,
+ HWND window) {
+ *max_width = 0;
+ *line_count = 0;
+
+ // Clamp the tooltip length to kMaxTooltipLength so that we don't
+ // accidentally DOS the user with a mega tooltip (since Windows doesn't seem
+ // to do this itself).
+ if (text->length() > kMaxTooltipLength)
+ *text = text->substr(0, kMaxTooltipLength);
+
+ // Determine the available width for the tooltip.
+ gfx::Point screen_loc(position_x, position_y);
+ View::ConvertPointToScreen(widget_->GetRootView(), &screen_loc);
+ gfx::Rect monitor_bounds =
+ win_util::GetMonitorBoundsForRect(gfx::Rect(screen_loc.x(),
+ screen_loc.y(),
+ 0, 0));
+ RECT tooltip_margin;
+ SendMessage(window, TTM_GETMARGIN, 0, (LPARAM)&tooltip_margin);
+ const int available_width = monitor_bounds.width() - tooltip_margin.left -
+ tooltip_margin.right;
+ if (available_width <= 0)
+ return;
+
+ // Split the string.
+ std::vector<std::wstring> lines;
+ SplitTooltipString(*text, &lines);
+ *line_count = static_cast<int>(lines.size());
+
+ // Format each line to fit.
+ ChromeFont font = GetDefaultFont();
+ std::wstring result;
+ for (std::vector<std::wstring>::iterator i = lines.begin(); i != lines.end();
+ ++i) {
+ std::wstring elided_text = gfx::ElideText(*i, font, available_width);
+ *max_width = std::max(*max_width, font.GetStringWidth(elided_text));
+ if (i == lines.begin() && i + 1 == lines.end()) {
+ *text = elided_text;
+ return;
+ }
+ if (!result.empty())
+ result.append(GetLineSeparator());
+ result.append(elided_text);
+ }
+ *text = result;
+}
+
+void TooltipManager::UpdateTooltip(int x, int y) {
+ RootView* root_view = widget_->GetRootView();
+ View* view = root_view->GetViewForPoint(gfx::Point(x, y));
+ if (view != last_tooltip_view_) {
+ // NOTE: This *must* be sent regardless of the visibility of the tooltip.
+ // It triggers Windows to ask for the tooltip again.
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ last_tooltip_view_ = view;
+ } else if (last_tooltip_view_ != NULL) {
+ // Tooltip is showing, and mouse is over the same view. See if the tooltip
+ // text has changed.
+ gfx::Point view_point(x, y);
+ View::ConvertPointToView(root_view, last_tooltip_view_, &view_point);
+ std::wstring new_tooltip_text;
+ if (last_tooltip_view_->GetTooltipText(view_point.x(), view_point.y(),
+ &new_tooltip_text) &&
+ new_tooltip_text != tooltip_text_) {
+ // The text has changed, hide the popup.
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ if (!new_tooltip_text.empty() && tooltip_showing_) {
+ // New text is valid, show the popup.
+ SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
+ }
+ }
+ }
+}
+
+void TooltipManager::OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param) {
+ int x = GET_X_LPARAM(l_param);
+ int y = GET_Y_LPARAM(l_param);
+
+ if (u_msg >= WM_NCMOUSEMOVE && u_msg <= WM_NCXBUTTONDBLCLK) {
+ // NC message coordinates are in screen coordinates.
+ gfx::Rect frame_bounds;
+ widget_->GetBounds(&frame_bounds, true);
+ x -= frame_bounds.x();
+ y -= frame_bounds.y();
+ }
+
+ if (u_msg != WM_MOUSEMOVE || last_mouse_x_ != x || last_mouse_y_ != y) {
+ last_mouse_x_ = x;
+ last_mouse_y_ = y;
+ HideKeyboardTooltip();
+ UpdateTooltip(x, y);
+ }
+ // Forward the message onto the tooltip.
+ MSG msg;
+ msg.hwnd = parent_;
+ msg.message = u_msg;
+ msg.wParam = w_param;
+ msg.lParam = l_param;
+ SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, 0, (LPARAM)&msg);
+}
+
+void TooltipManager::ShowKeyboardTooltip(View* focused_view) {
+ if (tooltip_showing_) {
+ SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ tooltip_text_.clear();
+ }
+ HideKeyboardTooltip();
+ std::wstring tooltip_text;
+ if (!focused_view->GetTooltipText(0, 0, &tooltip_text))
+ return;
+ gfx::Rect focused_bounds = focused_view->bounds();
+ gfx::Point screen_point;
+ focused_view->ConvertPointToScreen(focused_view, &screen_point);
+ gfx::Point relative_point_coordinates;
+ focused_view->ConvertPointToWidget(focused_view, &relative_point_coordinates);
+ keyboard_tooltip_hwnd_ = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ SendMessage(keyboard_tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0,
+ std::numeric_limits<short>::max());
+ int tooltip_width;
+ int line_count;
+ TrimTooltipToFit(&tooltip_text, &tooltip_width, &line_count,
+ relative_point_coordinates.x(),
+ relative_point_coordinates.y(), keyboard_tooltip_hwnd_);
+ TOOLINFO keyboard_toolinfo;
+ memset(&keyboard_toolinfo, 0, sizeof(keyboard_toolinfo));
+ keyboard_toolinfo.cbSize = sizeof(keyboard_toolinfo);
+ keyboard_toolinfo.hwnd = parent_;
+ keyboard_toolinfo.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_IDISHWND ;
+ keyboard_toolinfo.lpszText = const_cast<WCHAR*>(tooltip_text.c_str());
+ SendMessage(keyboard_tooltip_hwnd_, TTM_ADDTOOL, 0,
+ reinterpret_cast<LPARAM>(&keyboard_toolinfo));
+ SendMessage(keyboard_tooltip_hwnd_, TTM_TRACKACTIVATE, TRUE,
+ reinterpret_cast<LPARAM>(&keyboard_toolinfo));
+ if (!tooltip_height_)
+ tooltip_height_ = CalcTooltipHeight();
+ RECT rect_bounds = {screen_point.x(),
+ screen_point.y() + focused_bounds.height(),
+ screen_point.x() + tooltip_width,
+ screen_point.y() + focused_bounds.height() +
+ line_count * tooltip_height_ };
+ gfx::Rect monitor_bounds =
+ win_util::GetMonitorBoundsForRect(gfx::Rect(rect_bounds));
+ rect_bounds = gfx::Rect(rect_bounds).AdjustToFit(monitor_bounds).ToRECT();
+ ::SetWindowPos(keyboard_tooltip_hwnd_, NULL, rect_bounds.left,
+ rect_bounds.top, 0, 0,
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ keyboard_tooltip_factory_.NewRunnableMethod(
+ &TooltipManager::DestroyKeyboardTooltipWindow, keyboard_tooltip_hwnd_),
+ kDefaultTimeout);
+}
+
+void TooltipManager::HideKeyboardTooltip() {
+ if (keyboard_tooltip_hwnd_ != NULL) {
+ SendMessage(keyboard_tooltip_hwnd_, WM_CLOSE, 0, 0);
+ keyboard_tooltip_hwnd_ = NULL;
+ }
+}
+
+void TooltipManager::DestroyKeyboardTooltipWindow(HWND window_to_destroy) {
+ if (keyboard_tooltip_hwnd_ == window_to_destroy)
+ HideKeyboardTooltip();
+}
+
+} // namespace views
diff --git a/views/widget/tooltip_manager.h b/views/widget/tooltip_manager.h
new file mode 100644
index 0000000..3d5620d
--- /dev/null
+++ b/views/widget/tooltip_manager.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_TOOLTIP_MANAGER_H_
+#define VIEWS_WIDGET_TOOLTIP_MANAGER_H_
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <string>
+#include "base/basictypes.h"
+#include "base/task.h"
+
+class ChromeFont;
+
+namespace views {
+
+class View;
+class Widget;
+
+// TooltipManager takes care of the wiring to support tooltips for Views.
+// This class is intended to be used by Widgets. To use this, you must
+// do the following:
+// Add the following to your MSG_MAP:
+//
+// MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+// MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange)
+// MSG_WM_NOTIFY(OnNotify)
+//
+// With the following implementations:
+// LRESULT XXX::OnMouseRange(UINT u_msg, WPARAM w_param, LPARAM l_param,
+// BOOL& handled) {
+// tooltip_manager_->OnMouse(u_msg, w_param, l_param);
+// handled = FALSE;
+// return 0;
+// }
+//
+// LRESULT XXX::OnNotify(int w_param, NMHDR* l_param) {
+// bool handled;
+// LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
+// SetMsgHandled(handled);
+// return result;
+// }
+//
+// And of course you'll need to create the TooltipManager!
+//
+// Lastly, you'll need to override GetTooltipManager.
+//
+// See XPFrame for an example of this in action.
+class TooltipManager {
+ public:
+ // Returns the height of tooltips. This should only be invoked from within
+ // GetTooltipTextOrigin.
+ static int GetTooltipHeight();
+
+ // Returns the default font used by tooltips.
+ static ChromeFont GetDefaultFont();
+
+ // Returns the separator for lines of text in a tooltip.
+ static const std::wstring& GetLineSeparator();
+
+ // Creates a TooltipManager for the specified Widget and parent window.
+ TooltipManager(Widget* widget, HWND parent);
+ virtual ~TooltipManager();
+
+ // Notification that the view hierarchy has changed in some way.
+ void UpdateTooltip();
+
+ // Invoked when the tooltip text changes for the specified views.
+ void TooltipTextChanged(View* view);
+
+ // Invoked when toolbar icon gets focus.
+ void ShowKeyboardTooltip(View* view);
+
+ // Invoked when toolbar loses focus.
+ void HideKeyboardTooltip();
+
+ // Message handlers. These forward to the tooltip control.
+ virtual void OnMouse(UINT u_msg, WPARAM w_param, LPARAM l_param);
+ LRESULT OnNotify(int w_param, NMHDR* l_param, bool* handled);
+ // Not used directly by TooltipManager, but provided for AeroTooltipManager.
+ virtual void OnMouseLeave() {}
+
+ protected:
+ virtual void Init();
+
+ // Updates the tooltip for the specified location.
+ void UpdateTooltip(int x, int y);
+
+ // Parent window the tooltip is added to.
+ HWND parent_;
+
+ // Tooltip control window.
+ HWND tooltip_hwnd_;
+
+ // Tooltip information.
+ TOOLINFO toolinfo_;
+
+ // Last location of the mouse. This is in the coordinates of the rootview.
+ int last_mouse_x_;
+ int last_mouse_y_;
+
+ // Whether or not the tooltip is showing.
+ bool tooltip_showing_;
+
+ private:
+ // Sets the tooltip position based on the x/y position of the text. If the
+ // tooltip fits, true is returned.
+ bool SetTooltipPosition(int text_x, int text_y);
+
+ // Calculates the preferred height for tooltips. This always returns a
+ // positive value.
+ int CalcTooltipHeight();
+
+ // Trims the tooltip to fit, setting text to the clipped result, width to the
+ // width (in pixels) of the clipped text and line_count to the number of lines
+ // of text in the tooltip.
+ void TrimTooltipToFit(std::wstring* text,
+ int* width,
+ int* line_count,
+ int position_x,
+ int position_y,
+ HWND window);
+
+ // Invoked when the timer elapses and tooltip has to be destroyed.
+ void DestroyKeyboardTooltipWindow(HWND window_to_destroy);
+
+ // Hosting Widget.
+ Widget* widget_;
+
+ // The View the mouse is under. This is null if the mouse isn't under a
+ // View.
+ View* last_tooltip_view_;
+
+ // Whether or not the view under the mouse needs to be refreshed. If this
+ // is true, when the tooltip is asked for the view under the mouse is
+ // refreshed.
+ bool last_view_out_of_sync_;
+
+ // Text for tooltip from the view.
+ std::wstring tooltip_text_;
+
+ // The clipped tooltip.
+ std::wstring clipped_text_;
+
+ // Number of lines in the tooltip.
+ int line_count_;
+
+ // Width of the last tooltip.
+ int tooltip_width_;
+
+ // Height for a tooltip; lazily calculated.
+ static int tooltip_height_;
+
+ // control window for tooltip displayed using keyboard.
+ HWND keyboard_tooltip_hwnd_;
+
+ // Used to register DestroyTooltipWindow function with PostDelayedTask
+ // function.
+ ScopedRunnableMethodFactory<TooltipManager> keyboard_tooltip_factory_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TooltipManager);
+};
+
+} // namespace views
+
+#endif // VIEWS_WIDGET_TOOLTIP_MANAGER_H_
diff --git a/views/widget/widget.h b/views/widget/widget.h
new file mode 100644
index 0000000..8dd3f2e
--- /dev/null
+++ b/views/widget/widget.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_WIDGET_H_
+#define VIEWS_WIDGET_WIDGET_H_
+
+#include "base/gfx/native_widget_types.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace views {
+
+class Accelerator;
+class RootView;
+class TooltipManager;
+class Window;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Widget interface
+//
+// Widget is an abstract class that defines the API that should be implemented
+// by a native window in order to host a view hierarchy.
+//
+// Widget wraps a hierarchy of View objects (see view.h) that implement
+// painting and flexible layout within the bounds of the Widget's window.
+//
+// The Widget is responsible for handling various system events and forwarding
+// them to the appropriate view.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+class Widget {
+ public:
+ virtual ~Widget() { }
+
+ // Returns the bounds of this Widget in the screen coordinate system.
+ // If the receiving Widget is a frame which is larger than its client area,
+ // this method returns the client area if including_frame is false and the
+ // frame bounds otherwise. If the receiving Widget is not a frame,
+ // including_frame is ignored.
+ virtual void GetBounds(gfx::Rect* out, bool including_frame) const = 0;
+
+ // Returns the gfx::NativeView associated with this Widget.
+ virtual gfx::NativeView GetNativeView() const = 0;
+
+ // Forces a paint of a specified rectangle immediately.
+ virtual void PaintNow(const gfx::Rect& update_rect) = 0;
+
+ // Returns the RootView contained by this Widget.
+ virtual RootView* GetRootView() = 0;
+
+ // Returns whether the Widget is visible to the user.
+ virtual bool IsVisible() const = 0;
+
+ // Returns whether the Widget is the currently active window.
+ virtual bool IsActive() const = 0;
+
+ // Returns the TooltipManager for this Widget. If this Widget does not support
+ // tooltips, NULL is returned.
+ virtual TooltipManager* GetTooltipManager() {
+ return NULL;
+ }
+
+ // Returns the accelerator given a command id. Returns false if there is
+ // no accelerator associated with a given id, which is a common condition.
+ virtual bool GetAccelerator(int cmd_id,
+ Accelerator* accelerator) = 0;
+
+ // Returns the Window containing this Widget, or NULL if not contained in a
+ // window.
+ virtual Window* GetWindow() { return NULL; }
+ virtual const Window* GetWindow() const { return NULL; }
+};
+
+} // namespace views
+
+#endif // VIEWS_WIDGET_WIDGET_H_
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
new file mode 100644
index 0000000..25869f6
--- /dev/null
+++ b/views/widget/widget_gtk.cc
@@ -0,0 +1,386 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/widget_gtk.h"
+
+#include "views/fill_layout.h"
+#include "views/widget/root_view.h"
+
+namespace views {
+
+WidgetGtk::WidgetGtk()
+ : widget_(NULL),
+ is_mouse_down_(false),
+ last_mouse_event_was_move_(false) {
+}
+
+WidgetGtk::~WidgetGtk() {
+ gtk_widget_unref(widget_);
+
+ // MessageLoopForUI::current()->RemoveObserver(this);
+}
+
+void WidgetGtk::Init(const gfx::Rect& bounds,
+ bool has_own_focus_manager) {
+
+ // Force creation of the RootView if it hasn't been created yet.
+ GetRootView();
+
+ // Make container here.
+ widget_ = gtk_drawing_area_new();
+ gtk_drawing_area_size(GTK_DRAWING_AREA(widget_), 100, 100);
+ gtk_widget_show(widget_);
+
+ // Make sure we receive our motion events.
+ gtk_widget_set_events(widget_,
+ gtk_widget_get_events(widget_) |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK);
+
+ root_view_->OnWidgetCreated();
+
+ // TODO(port): if(has_own_focus_manager) block
+
+ SetViewForNative(widget_, this);
+ SetRootViewForWidget(widget_, root_view_.get());
+
+ // MessageLoopForUI::current()->AddObserver(this);
+
+ g_signal_connect_after(G_OBJECT(widget_), "size_allocate",
+ G_CALLBACK(CallSizeAllocate), NULL);
+ g_signal_connect(G_OBJECT(widget_), "expose_event",
+ G_CALLBACK(CallPaint), NULL);
+ g_signal_connect(G_OBJECT(widget_), "enter_notify_event",
+ G_CALLBACK(CallEnterNotify), NULL);
+ g_signal_connect(G_OBJECT(widget_), "leave_notify_event",
+ G_CALLBACK(CallLeaveNotify), NULL);
+ g_signal_connect(G_OBJECT(widget_), "motion_notify_event",
+ G_CALLBACK(CallMotionNotify), NULL);
+ g_signal_connect(G_OBJECT(widget_), "button_press_event",
+ G_CALLBACK(CallButtonPress), NULL);
+ g_signal_connect(G_OBJECT(widget_), "button_release_event",
+ G_CALLBACK(CallButtonRelease), NULL);
+ g_signal_connect(G_OBJECT(widget_), "focus_in_event",
+ G_CALLBACK(CallFocusIn), NULL);
+ g_signal_connect(G_OBJECT(widget_), "focus_out_event",
+ G_CALLBACK(CallFocusOut), NULL);
+ g_signal_connect(G_OBJECT(widget_), "key_press_event",
+ G_CALLBACK(CallKeyPress), NULL);
+ g_signal_connect(G_OBJECT(widget_), "key_release_event",
+ G_CALLBACK(CallKeyRelease), NULL);
+ g_signal_connect(G_OBJECT(widget_), "scroll_event",
+ G_CALLBACK(CallScroll), NULL);
+ g_signal_connect(G_OBJECT(widget_), "visibility_notify_event",
+ G_CALLBACK(CallVisibilityNotify), NULL);
+
+ // TODO(erg): Ignore these signals for now because they're such a drag.
+ //
+ // g_signal_connect(G_OBJECT(widget_), "drag_motion",
+ // G_CALLBACK(drag_motion_event_cb), NULL);
+ // g_signal_connect(G_OBJECT(widget_), "drag_leave",
+ // G_CALLBACK(drag_leave_event_cb), NULL);
+ // g_signal_connect(G_OBJECT(widget_), "drag_drop",
+ // G_CALLBACK(drag_drop_event_cb), NULL);
+ // g_signal_connect(G_OBJECT(widget_), "drag_data_received",
+ // G_CALLBACK(drag_data_received_event_cb), NULL);
+}
+
+void WidgetGtk::SetContentsView(View* view) {
+ DCHECK(view && widget_) << "Can't be called until after the HWND is created!";
+ // The ContentsView must be set up _after_ the window is created so that its
+ // Widget pointer is valid.
+ root_view_->SetLayoutManager(new FillLayout);
+ if (root_view_->GetChildViewCount() != 0)
+ root_view_->RemoveAllChildViews(true);
+ root_view_->AddChildView(view);
+
+ // TODO(erg): Terrible hack to work around lack of real sizing mechanics for
+ // now.
+ root_view_->SetBounds(0, 0, 100, 100);
+ root_view_->Layout();
+ root_view_->SchedulePaint();
+ NOTIMPLEMENTED();
+}
+
+void WidgetGtk::GetBounds(gfx::Rect* out, bool including_frame) const {
+ if (including_frame) {
+ NOTIMPLEMENTED();
+ *out = gfx::Rect();
+ return;
+ }
+
+ // TODO(erg): Not sure how to implement this. gtk_widget_size_request()
+ // returns a widget's requested size--not it's actual size. The system of
+ // containers and such do auto sizing tricks to make everything work within
+ // the constraints and requested sizes...
+ NOTIMPLEMENTED();
+}
+
+gfx::NativeView WidgetGtk::GetNativeView() const {
+ return widget_;
+}
+
+void WidgetGtk::PaintNow(const gfx::Rect& update_rect) {
+ // TODO(erg): This is woefully incomplete and is a straw man implementation.
+ gtk_widget_queue_draw_area(widget_, update_rect.x(), update_rect.y(),
+ update_rect.width(), update_rect.height());
+}
+
+RootView* WidgetGtk::GetRootView() {
+ if (!root_view_.get()) {
+ // First time the root view is being asked for, create it now.
+ root_view_.reset(CreateRootView());
+ }
+ return root_view_.get();
+}
+
+bool WidgetGtk::IsVisible() const {
+ return GTK_WIDGET_VISIBLE(widget_);
+}
+
+bool WidgetGtk::IsActive() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+TooltipManager* WidgetGtk::GetTooltipManager() {
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+bool WidgetGtk::GetAccelerator(int cmd_id, Accelerator* accelerator) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+gboolean WidgetGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event) {
+ gfx::Point screen_loc(event->x_root, event->y_root);
+ if (last_mouse_event_was_move_ && last_mouse_move_x_ == screen_loc.x() &&
+ last_mouse_move_y_ == screen_loc.y()) {
+ // Don't generate a mouse event for the same location as the last.
+ return false;
+ }
+ last_mouse_move_x_ = screen_loc.x();
+ last_mouse_move_y_ = screen_loc.y();
+ last_mouse_event_was_move_ = true;
+ MouseEvent mouse_move(Event::ET_MOUSE_MOVED,
+ event->x,
+ event->y,
+ Event::GetFlagsFromGdkState(event->state));
+ root_view_->OnMouseMoved(mouse_move);
+ return true;
+}
+
+gboolean WidgetGtk::OnButtonPress(GtkWidget* widget, GdkEventButton* event) {
+ return ProcessMousePressed(event);
+}
+
+gboolean WidgetGtk::OnButtonRelease(GtkWidget* widget, GdkEventButton* event) {
+ ProcessMouseReleased(event);
+ return true;
+}
+
+gboolean WidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) {
+ root_view_->OnPaint(event);
+ return true;
+}
+
+gboolean WidgetGtk::OnEnterNotify(GtkWidget* widget, GdkEventCrossing* event) {
+ // TODO(port): We may not actually need this message; it looks like
+ // OnNotificationNotify() takes care of this case...
+ return false;
+}
+
+gboolean WidgetGtk::OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event) {
+ last_mouse_event_was_move_ = false;
+ root_view_->ProcessOnMouseExited();
+ return true;
+}
+
+gboolean WidgetGtk::OnKeyPress(GtkWidget* widget, GdkEventKey* event) {
+ KeyEvent key_event(event);
+ return root_view_->ProcessKeyEvent(key_event);
+}
+
+gboolean WidgetGtk::OnKeyRelease(GtkWidget* widget, GdkEventKey* event) {
+ KeyEvent key_event(event);
+ return root_view_->ProcessKeyEvent(key_event);
+}
+
+RootView* WidgetGtk::CreateRootView() {
+ return new RootView(this);
+}
+
+bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) {
+ last_mouse_event_was_move_ = false;
+ MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED,
+ event->x, event->y,
+// (dbl_click ? MouseEvent::EF_IS_DOUBLE_CLICK : 0) |
+ Event::GetFlagsFromGdkState(event->state));
+ if (root_view_->OnMousePressed(mouse_pressed)) {
+ is_mouse_down_ = true;
+ // TODO(port): Enable this once I figure out what capture is.
+ // if (!has_capture_) {
+ // SetCapture();
+ // has_capture_ = true;
+ // current_action_ = FA_FORWARDING;
+ // }
+ return true;
+ }
+
+ return false;
+}
+
+void WidgetGtk::ProcessMouseReleased(GdkEventButton* event) {
+ last_mouse_event_was_move_ = false;
+ MouseEvent mouse_up(Event::ET_MOUSE_RELEASED,
+ event->x, event->y,
+ Event::GetFlagsFromGdkState(event->state));
+ // Release the capture first, that way we don't get confused if
+ // OnMouseReleased blocks.
+ //
+ // TODO(port): Enable this once I figure out what capture is.
+ // if (has_capture_ && ReleaseCaptureOnMouseReleased()) {
+ // has_capture_ = false;
+ // current_action_ = FA_NONE;
+ // ReleaseCapture();
+ // }
+ is_mouse_down_ = false;
+ root_view_->OnMouseReleased(mouse_up, false);
+}
+
+// static
+WidgetGtk* WidgetGtk::GetViewForNative(GtkWidget* widget) {
+ gpointer user_data = g_object_get_data(G_OBJECT(widget), "chrome-views");
+ return static_cast<WidgetGtk*>(user_data);
+}
+
+// static
+void WidgetGtk::SetViewForNative(GtkWidget* widget, WidgetGtk* view) {
+ g_object_set_data(G_OBJECT(widget), "chrome-views", view);
+}
+
+// static
+RootView* WidgetGtk::GetRootViewForWidget(GtkWidget* widget) {
+ gpointer user_data = g_object_get_data(G_OBJECT(widget), "root-view");
+ return static_cast<RootView*>(user_data);
+}
+
+// static
+void WidgetGtk::SetRootViewForWidget(GtkWidget* widget, RootView* root_view) {
+ g_object_set_data(G_OBJECT(widget), "root-view", root_view);
+}
+
+// static
+void WidgetGtk::CallSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return;
+
+ widget_gtk->OnSizeAllocate(widget, allocation);
+}
+
+gboolean WidgetGtk::CallPaint(GtkWidget* widget, GdkEventExpose* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnPaint(widget, event);
+}
+
+gboolean WidgetGtk::CallEnterNotify(GtkWidget* widget, GdkEventCrossing* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnEnterNotify(widget, event);
+}
+
+gboolean WidgetGtk::CallLeaveNotify(GtkWidget* widget, GdkEventCrossing* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnLeaveNotify(widget, event);
+}
+
+gboolean WidgetGtk::CallMotionNotify(GtkWidget* widget, GdkEventMotion* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnMotionNotify(widget, event);
+}
+
+gboolean WidgetGtk::CallButtonPress(GtkWidget* widget, GdkEventButton* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnButtonPress(widget, event);
+}
+
+gboolean WidgetGtk::CallButtonRelease(GtkWidget* widget, GdkEventButton* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnButtonRelease(widget, event);
+}
+
+gboolean WidgetGtk::CallFocusIn(GtkWidget* widget, GdkEventFocus* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnFocusIn(widget, event);
+}
+
+gboolean WidgetGtk::CallFocusOut(GtkWidget* widget, GdkEventFocus* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnFocusOut(widget, event);
+}
+
+gboolean WidgetGtk::CallKeyPress(GtkWidget* widget, GdkEventKey* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnKeyPress(widget, event);
+}
+
+gboolean WidgetGtk::CallKeyRelease(GtkWidget* widget, GdkEventKey* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnKeyRelease(widget, event);
+}
+
+gboolean WidgetGtk::CallScroll(GtkWidget* widget, GdkEventScroll* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnScroll(widget, event);
+}
+
+gboolean WidgetGtk::CallVisibilityNotify(GtkWidget* widget,
+ GdkEventVisibility* event) {
+ WidgetGtk* widget_gtk = GetViewForNative(widget);
+ if (!widget_gtk)
+ return false;
+
+ return widget_gtk->OnVisibilityNotify(widget, event);
+}
+
+}
diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h
new file mode 100644
index 0000000..4bbc0dd
--- /dev/null
+++ b/views/widget/widget_gtk.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_WIDGET_GTK_H_
+#define VIEWS_WIDGET_WIDGET_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include "base/message_loop.h"
+#include "views/widget/widget.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace views {
+
+class View;
+
+class WidgetGtk : public Widget {
+ public:
+ static WidgetGtk* Construct() {
+ // This isn't used, but exists to force WidgetGtk to be instantiable.
+ return new WidgetGtk;
+ }
+
+ WidgetGtk();
+ virtual ~WidgetGtk();
+
+ // Initializes this widget and returns the gtk drawing area for the caller to
+ // add to its hierarchy. (We can't pass in the parent to this method because
+ // there are no standard adding semantics in gtk...)
+ void Init(const gfx::Rect& bounds, bool has_own_focus_manager);
+
+ virtual void SetContentsView(View* view);
+
+ // Overridden from Widget:
+ virtual void GetBounds(gfx::Rect* out, bool including_frame) const;
+ virtual gfx::NativeView GetNativeView() const;
+ virtual void PaintNow(const gfx::Rect& update_rect);
+ virtual RootView* GetRootView();
+ virtual bool IsVisible() const;
+ virtual bool IsActive() const;
+ virtual TooltipManager* GetTooltipManager();
+ virtual bool GetAccelerator(int cmd_id, Accelerator* accelerator);
+
+ protected:
+ virtual void OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) {}
+ virtual gboolean OnPaint(GtkWidget* widget, GdkEventExpose* event);
+ virtual gboolean OnEnterNotify(GtkWidget* widget, GdkEventCrossing* event);
+ virtual gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event);
+ virtual gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event);
+ virtual gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event);
+ virtual gboolean OnButtonRelease(GtkWidget* widget, GdkEventButton* event);
+ virtual gboolean OnFocusIn(GtkWidget* widget, GdkEventFocus* event) {
+ return false;
+ }
+ virtual gboolean OnFocusOut(GtkWidget* widget, GdkEventFocus* event) {
+ return false;
+ }
+ virtual gboolean OnKeyPress(GtkWidget* widget, GdkEventKey* event);
+ virtual gboolean OnKeyRelease(GtkWidget* widget, GdkEventKey* event);
+ virtual gboolean OnScroll(GtkWidget* widget, GdkEventScroll* event) {
+ return false;
+ }
+ virtual gboolean OnVisibilityNotify(GtkWidget* widget,
+ GdkEventVisibility* event) {
+ return false;
+ }
+
+ private:
+ virtual RootView* CreateRootView();
+
+ // Process a mouse click
+ bool ProcessMousePressed(GdkEventButton* event);
+ void ProcessMouseReleased(GdkEventButton* event);
+
+ // Sets and retrieves the WidgetGtk in the userdata section of the widget.
+ static WidgetGtk* GetViewForNative(GtkWidget* widget);
+ static void SetViewForNative(GtkWidget* widget, WidgetGtk* view);
+
+ static RootView* GetRootViewForWidget(GtkWidget* widget);
+ static void SetRootViewForWidget(GtkWidget* widget, RootView* root_view);
+
+ // A set of static signal handlers that bridge
+ static void CallSizeAllocate(GtkWidget* widget, GtkAllocation* allocation);
+ static gboolean CallPaint(GtkWidget* widget, GdkEventExpose* event);
+ static gboolean CallEnterNotify(GtkWidget* widget, GdkEventCrossing* event);
+ static gboolean CallLeaveNotify(GtkWidget* widget, GdkEventCrossing* event);
+ static gboolean CallMotionNotify(GtkWidget* widget, GdkEventMotion* event);
+ static gboolean CallButtonPress(GtkWidget* widget, GdkEventButton* event);
+ static gboolean CallButtonRelease(GtkWidget* widget, GdkEventButton* event);
+ static gboolean CallFocusIn(GtkWidget* widget, GdkEventFocus* event);
+ static gboolean CallFocusOut(GtkWidget* widget, GdkEventFocus* event);
+ static gboolean CallKeyPress(GtkWidget* widget, GdkEventKey* event);
+ static gboolean CallKeyRelease(GtkWidget* widget, GdkEventKey* event);
+ static gboolean CallScroll(GtkWidget* widget, GdkEventScroll* event);
+ static gboolean CallVisibilityNotify(GtkWidget* widget,
+ GdkEventVisibility* event);
+
+ // Our native view.
+ GtkWidget* widget_;
+
+ // The root of the View hierarchy attached to this window.
+ scoped_ptr<RootView> root_view_;
+
+ // If true, the mouse is currently down.
+ bool is_mouse_down_;
+
+ // The following are used to detect duplicate mouse move events and not
+ // deliver them. Displaying a window may result in the system generating
+ // duplicate move events even though the mouse hasn't moved.
+
+ // If true, the last event was a mouse move event.
+ bool last_mouse_event_was_move_;
+
+ // Coordinates of the last mouse move event, in screen coordinates.
+ int last_mouse_move_x_;
+ int last_mouse_move_y_;
+};
+
+} // namespace views
+
+#endif // VIEWS_WIDGET_WIDGET_GTK_H_
diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc
new file mode 100644
index 0000000..2bc9b0c
--- /dev/null
+++ b/views/widget/widget_win.cc
@@ -0,0 +1,999 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/widget/widget_win.h"
+
+#include "app/gfx/chrome_canvas.h"
+#include "base/gfx/native_theme.h"
+#include "base/string_util.h"
+#include "base/win_util.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/common/win_util.h"
+#include "views/accessibility/view_accessibility.h"
+#include "views/controls/native_control_win.h"
+#include "views/fill_layout.h"
+#include "views/focus/focus_util_win.h"
+#include "views/widget/aero_tooltip_manager.h"
+#include "views/widget/root_view.h"
+#include "views/window/window_win.h"
+
+namespace views {
+
+static const DWORD kWindowDefaultChildStyle =
+ WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+static const DWORD kWindowDefaultStyle = WS_OVERLAPPEDWINDOW;
+static const DWORD kWindowDefaultExStyle = 0;
+
+// Property used to link the HWND to its RootView.
+static const wchar_t* const kRootViewWindowProperty = L"__ROOT_VIEW__";
+
+bool SetRootViewForHWND(HWND hwnd, RootView* root_view) {
+ return ::SetProp(hwnd, kRootViewWindowProperty, root_view) ? true : false;
+}
+
+RootView* GetRootViewForHWND(HWND hwnd) {
+ return reinterpret_cast<RootView*>(::GetProp(hwnd, kRootViewWindowProperty));
+}
+
+NativeControlWin* GetNativeControlWinForHWND(HWND hwnd) {
+ return reinterpret_cast<NativeControlWin*>(
+ ::GetProp(hwnd, NativeControlWin::kNativeControlWinKey));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Window class tracking.
+
+// static
+const wchar_t* const WidgetWin::kBaseClassName =
+ L"Chrome_WidgetWin_";
+
+// Window class information used for registering unique windows.
+struct ClassInfo {
+ UINT style;
+ HBRUSH background;
+
+ explicit ClassInfo(int style)
+ : style(style),
+ background(NULL) {}
+
+ // Compares two ClassInfos. Returns true if all members match.
+ bool Equals(const ClassInfo& other) const {
+ return (other.style == style && other.background == background);
+ }
+};
+
+class ClassRegistrar {
+ public:
+ ~ClassRegistrar() {
+ for (RegisteredClasses::iterator i = registered_classes_.begin();
+ i != registered_classes_.end(); ++i) {
+ UnregisterClass(i->name.c_str(), NULL);
+ }
+ }
+
+ // Puts the name for the class matching |class_info| in |class_name|, creating
+ // a new name if the class is not yet known.
+ // Returns true if this class was already known, false otherwise.
+ bool RetrieveClassName(const ClassInfo& class_info, std::wstring* name) {
+ for (RegisteredClasses::const_iterator i = registered_classes_.begin();
+ i != registered_classes_.end(); ++i) {
+ if (class_info.Equals(i->info)) {
+ name->assign(i->name);
+ return true;
+ }
+ }
+
+ name->assign(std::wstring(WidgetWin::kBaseClassName) +
+ IntToWString(registered_count_++));
+ return false;
+ }
+
+ void RegisterClass(const ClassInfo& class_info,
+ const std::wstring& name,
+ ATOM atom) {
+ registered_classes_.push_back(RegisteredClass(class_info, name, atom));
+ }
+
+ private:
+ // Represents a registered window class.
+ struct RegisteredClass {
+ RegisteredClass(const ClassInfo& info,
+ const std::wstring& name,
+ ATOM atom)
+ : info(info),
+ name(name),
+ atom(atom) {
+ }
+
+ // Info used to create the class.
+ ClassInfo info;
+
+ // The name given to the window.
+ std::wstring name;
+
+ // The ATOM returned from creating the window.
+ ATOM atom;
+ };
+
+ ClassRegistrar() : registered_count_(0) { }
+ friend struct DefaultSingletonTraits<ClassRegistrar>;
+
+ typedef std::list<RegisteredClass> RegisteredClasses;
+ RegisteredClasses registered_classes_;
+
+ // Counter of how many classes have ben registered so far.
+ int registered_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClassRegistrar);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// WidgetWin, public
+
+WidgetWin::WidgetWin()
+ : close_widget_factory_(this),
+ active_mouse_tracking_flags_(0),
+ has_capture_(false),
+ current_action_(FA_NONE),
+ window_style_(0),
+ window_ex_style_(kWindowDefaultExStyle),
+ use_layered_buffer_(true),
+ layered_alpha_(255),
+ delete_on_destroy_(true),
+ can_update_layered_window_(true),
+ last_mouse_event_was_move_(false),
+ is_mouse_down_(false),
+ is_window_(false),
+ class_style_(CS_DBLCLKS),
+ hwnd_(NULL) {
+}
+
+WidgetWin::~WidgetWin() {
+ MessageLoopForUI::current()->RemoveObserver(this);
+}
+
+void WidgetWin::Init(HWND parent, const gfx::Rect& bounds,
+ bool has_own_focus_manager) {
+ if (window_style_ == 0)
+ window_style_ = parent ? kWindowDefaultChildStyle : kWindowDefaultStyle;
+
+ // See if the style has been overridden.
+ opaque_ = !(window_ex_style_ & WS_EX_TRANSPARENT);
+ use_layered_buffer_ = (use_layered_buffer_ &&
+ !!(window_ex_style_ & WS_EX_LAYERED));
+
+ // Force creation of the RootView if it hasn't been created yet.
+ GetRootView();
+
+ // Ensures the parent we have been passed is valid, otherwise CreateWindowEx
+ // will fail.
+ if (parent && !::IsWindow(parent)) {
+ NOTREACHED() << "invalid parent window specified.";
+ parent = NULL;
+ }
+
+ hwnd_ = CreateWindowEx(window_ex_style_, GetWindowClassName().c_str(), L"",
+ window_style_, bounds.x(), bounds.y(), bounds.width(),
+ bounds.height(), parent, NULL, NULL, this);
+ DCHECK(hwnd_);
+ TRACK_HWND_CREATION(hwnd_);
+ SetWindowSupportsRerouteMouseWheel(hwnd_);
+
+ // The window procedure should have set the data for us.
+ DCHECK(win_util::GetWindowUserData(hwnd_) == this);
+
+ root_view_->OnWidgetCreated();
+
+ if (has_own_focus_manager) {
+ FocusManager::CreateFocusManager(hwnd_, GetRootView());
+ } else {
+ // Subclass the window so we get the tab key messages when a view with no
+ // associated native window is focused.
+ FocusManager::InstallFocusSubclass(hwnd_, NULL);
+ }
+
+ // Sets the RootView as a property, so the automation can introspect windows.
+ SetRootViewForHWND(hwnd_, root_view_.get());
+
+ MessageLoopForUI::current()->AddObserver(this);
+
+ // Windows special DWM window frame requires a special tooltip manager so
+ // that window controls in Chrome windows don't flicker when you move your
+ // mouse over them. See comment in aero_tooltip_manager.h.
+ if (win_util::ShouldUseVistaFrame()) {
+ tooltip_manager_.reset(new AeroTooltipManager(this, GetNativeView()));
+ } else {
+ tooltip_manager_.reset(new TooltipManager(this, GetNativeView()));
+ }
+
+ // This message initializes the window so that focus border are shown for
+ // windows.
+ ::SendMessage(GetNativeView(),
+ WM_CHANGEUISTATE,
+ MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS),
+ 0);
+
+ // Bug 964884: detach the IME attached to this window.
+ // We should attach IMEs only when we need to input CJK strings.
+ ::ImmAssociateContextEx(GetNativeView(), NULL, 0);
+}
+
+void WidgetWin::SetContentsView(View* view) {
+ DCHECK(view && hwnd_) << "Can't be called until after the HWND is created!";
+ // The ContentsView must be set up _after_ the window is created so that its
+ // Widget pointer is valid.
+ root_view_->SetLayoutManager(new FillLayout);
+ if (root_view_->GetChildViewCount() != 0)
+ root_view_->RemoveAllChildViews(true);
+ root_view_->AddChildView(view);
+
+ // Manually size the window here to ensure the root view is laid out.
+ RECT wr;
+ GetWindowRect(&wr);
+ ChangeSize(0, CSize(wr.right - wr.left, wr.bottom - wr.top));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Widget implementation:
+
+void WidgetWin::GetBounds(gfx::Rect* out, bool including_frame) const {
+ CRect crect;
+ if (including_frame) {
+ GetWindowRect(&crect);
+ *out = gfx::Rect(crect);
+ return;
+ }
+
+ GetClientRect(&crect);
+ POINT p = {0, 0};
+ ::ClientToScreen(hwnd_, &p);
+ out->SetRect(crect.left + p.x, crect.top + p.y,
+ crect.Width(), crect.Height());
+}
+
+gfx::NativeView WidgetWin::GetNativeView() const {
+ return hwnd_;
+}
+
+void WidgetWin::PaintNow(const gfx::Rect& update_rect) {
+ if (use_layered_buffer_) {
+ PaintLayeredWindow();
+ } else if (root_view_->NeedsPainting(false) && IsWindow()) {
+ if (!opaque_ && GetParent()) {
+ // We're transparent. Need to force painting to occur from our parent.
+ CRect parent_update_rect = update_rect.ToRECT();
+ POINT location_in_parent = { 0, 0 };
+ ClientToScreen(hwnd_, &location_in_parent);
+ ::ScreenToClient(GetParent(), &location_in_parent);
+ parent_update_rect.OffsetRect(location_in_parent);
+ ::RedrawWindow(GetParent(), parent_update_rect, NULL,
+ RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
+ } else {
+ RECT native_update_rect = update_rect.ToRECT();
+ RedrawWindow(hwnd_, &native_update_rect, NULL,
+ RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
+ }
+ // As we were created with a style of WS_CLIPCHILDREN redraw requests may
+ // result in an empty paint rect in WM_PAINT (this'll happen if a
+ // child HWND completely contains the update _rect). In such a scenario
+ // RootView would never get a ProcessPaint and always think it needs to
+ // be painted (leading to a steady stream of RedrawWindow requests on every
+ // event). For this reason we tell RootView it doesn't need to paint
+ // here.
+ root_view_->ClearPaintRect();
+ }
+}
+
+RootView* WidgetWin::GetRootView() {
+ if (!root_view_.get()) {
+ // First time the root view is being asked for, create it now.
+ root_view_.reset(CreateRootView());
+ }
+ return root_view_.get();
+}
+
+bool WidgetWin::IsVisible() const {
+ return !!::IsWindowVisible(GetNativeView());
+}
+
+bool WidgetWin::IsActive() const {
+ return win_util::IsWindowActive(GetNativeView());
+}
+
+TooltipManager* WidgetWin::GetTooltipManager() {
+ return tooltip_manager_.get();
+}
+
+Window* WidgetWin::GetWindow() {
+ return GetWindowImpl(hwnd_);
+}
+
+const Window* WidgetWin::GetWindow() const {
+ return GetWindowImpl(hwnd_);
+}
+
+void WidgetWin::SetLayeredAlpha(BYTE layered_alpha) {
+ layered_alpha_ = layered_alpha;
+
+// if (hwnd_)
+// UpdateWindowFromContents(contents_->getTopPlatformDevice().getBitmapDC());
+}
+
+void WidgetWin::SetUseLayeredBuffer(bool use_layered_buffer) {
+ if (use_layered_buffer_ == use_layered_buffer)
+ return;
+
+ use_layered_buffer_ = use_layered_buffer;
+ if (!hwnd_)
+ return;
+
+ if (use_layered_buffer_) {
+ // Force creation of the buffer at the right size.
+ RECT wr;
+ GetWindowRect(&wr);
+ ChangeSize(0, CSize(wr.right - wr.left, wr.bottom - wr.top));
+ } else {
+ contents_.reset(NULL);
+ }
+}
+
+static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM l_param) {
+ RootView* root_view =
+ reinterpret_cast<RootView*>(GetProp(hwnd, kRootViewWindowProperty));
+ if (root_view) {
+ *reinterpret_cast<RootView**>(l_param) = root_view;
+ return FALSE; // Stop enumerating.
+ }
+ return TRUE; // Keep enumerating.
+}
+
+// static
+RootView* WidgetWin::FindRootView(HWND hwnd) {
+ RootView* root_view =
+ reinterpret_cast<RootView*>(GetProp(hwnd, kRootViewWindowProperty));
+ if (root_view)
+ return root_view;
+
+ // Enumerate all children and check if they have a RootView.
+ EnumChildWindows(hwnd, EnumChildProc, reinterpret_cast<LPARAM>(&root_view));
+
+ return root_view;
+}
+
+void WidgetWin::Close() {
+ if (!IsWindow())
+ return; // No need to do anything.
+
+ // Let's hide ourselves right away.
+ Hide();
+ if (close_widget_factory_.empty()) {
+ // And we delay the close so that if we are called from an ATL callback,
+ // we don't destroy the window before the callback returned (as the caller
+ // may delete ourselves on destroy and the ATL callback would still
+ // dereference us when the callback returns).
+ MessageLoop::current()->PostTask(FROM_HERE,
+ close_widget_factory_.NewRunnableMethod(
+ &WidgetWin::CloseNow));
+ }
+}
+
+void WidgetWin::Hide() {
+ if (IsWindow()) {
+ // NOTE: Be careful not to activate any windows here (for example, calling
+ // ShowWindow(SW_HIDE) will automatically activate another window). This
+ // code can be called while a window is being deactivated, and activating
+ // another window will screw up the activation that is already in progress.
+ SetWindowPos(NULL, 0, 0, 0, 0,
+ SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
+ SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
+ }
+}
+
+void WidgetWin::Show() {
+ if (IsWindow())
+ ShowWindow(SW_SHOWNOACTIVATE);
+}
+
+void WidgetWin::CloseNow() {
+ // We may already have been destroyed if the selection resulted in a tab
+ // switch which will have reactivated the browser window and closed us, so
+ // we need to check to see if we're still a window before trying to destroy
+ // ourself.
+ if (IsWindow())
+ DestroyWindow();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MessageLoop::Observer
+
+void WidgetWin::WillProcessMessage(const MSG& msg) {
+}
+
+void WidgetWin::DidProcessMessage(const MSG& msg) {
+ if (root_view_->NeedsPainting(true)) {
+ PaintNow(root_view_->GetScheduledPaintRect());
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// FocusTraversable
+
+View* WidgetWin::FindNextFocusableView(
+ View* starting_view, bool reverse, Direction direction, bool dont_loop,
+ FocusTraversable** focus_traversable, View** focus_traversable_view) {
+ return root_view_->FindNextFocusableView(starting_view,
+ reverse,
+ direction,
+ dont_loop,
+ focus_traversable,
+ focus_traversable_view);
+}
+
+FocusTraversable* WidgetWin::GetFocusTraversableParent() {
+ // We are a proxy to the root view, so we should be bypassed when traversing
+ // up and as a result this should not be called.
+ NOTREACHED();
+ return NULL;
+}
+
+void WidgetWin::SetFocusTraversableParent(FocusTraversable* parent) {
+ root_view_->SetFocusTraversableParent(parent);
+}
+
+View* WidgetWin::GetFocusTraversableParentView() {
+ // We are a proxy to the root view, so we should be bypassed when traversing
+ // up and as a result this should not be called.
+ NOTREACHED();
+ return NULL;
+}
+
+void WidgetWin::SetFocusTraversableParentView(View* parent_view) {
+ root_view_->SetFocusTraversableParentView(parent_view);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Message handlers
+
+void WidgetWin::OnCaptureChanged(HWND hwnd) {
+ if (has_capture_) {
+ if (is_mouse_down_)
+ root_view_->ProcessMouseDragCanceled();
+ is_mouse_down_ = false;
+ has_capture_ = false;
+ }
+}
+
+void WidgetWin::OnClose() {
+ Close();
+}
+
+void WidgetWin::OnDestroy() {
+ root_view_->OnWidgetDestroyed();
+
+ RemoveProp(hwnd_, kRootViewWindowProperty);
+}
+
+LRESULT WidgetWin::OnEraseBkgnd(HDC dc) {
+ // This is needed for magical win32 flicker ju-ju
+ return 1;
+}
+
+LRESULT WidgetWin::OnGetObject(UINT uMsg, WPARAM w_param, LPARAM l_param) {
+ LRESULT reference_result = static_cast<LRESULT>(0L);
+
+ // Accessibility readers will send an OBJID_CLIENT message
+ if (OBJID_CLIENT == l_param) {
+ // If our MSAA root is already created, reuse that pointer. Otherwise,
+ // create a new one.
+ if (!accessibility_root_) {
+ CComObject<ViewAccessibility>* instance = NULL;
+
+ HRESULT hr = CComObject<ViewAccessibility>::CreateInstance(&instance);
+ DCHECK(SUCCEEDED(hr));
+
+ if (!instance) {
+ // Return with failure.
+ return static_cast<LRESULT>(0L);
+ }
+
+ CComPtr<IAccessible> accessibility_instance(instance);
+
+ if (!SUCCEEDED(instance->Initialize(root_view_.get()))) {
+ // Return with failure.
+ return static_cast<LRESULT>(0L);
+ }
+
+ // All is well, assign the temp instance to the class smart pointer
+ accessibility_root_.Attach(accessibility_instance.Detach());
+
+ if (!accessibility_root_) {
+ // Return with failure.
+ return static_cast<LRESULT>(0L);
+ }
+
+ // Notify that an instance of IAccessible was allocated for m_hWnd
+ ::NotifyWinEvent(EVENT_OBJECT_CREATE, GetNativeView(), OBJID_CLIENT,
+ CHILDID_SELF);
+ }
+
+ // Create a reference to ViewAccessibility that MSAA will marshall
+ // to the client.
+ reference_result = LresultFromObject(IID_IAccessible, w_param,
+ static_cast<IAccessible*>(accessibility_root_));
+ }
+ return reference_result;
+}
+
+void WidgetWin::OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags) {
+ KeyEvent event(Event::ET_KEY_PRESSED, c, rep_cnt, flags);
+ SetMsgHandled(root_view_->ProcessKeyEvent(event));
+}
+
+void WidgetWin::OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags) {
+ KeyEvent event(Event::ET_KEY_RELEASED, c, rep_cnt, flags);
+ SetMsgHandled(root_view_->ProcessKeyEvent(event));
+}
+
+void WidgetWin::OnLButtonDown(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_LBUTTON, false, false);
+}
+
+void WidgetWin::OnLButtonUp(UINT flags, const CPoint& point) {
+ ProcessMouseReleased(point, flags | MK_LBUTTON);
+}
+
+void WidgetWin::OnLButtonDblClk(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_LBUTTON, true, false);
+}
+
+void WidgetWin::OnMButtonDown(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_MBUTTON, false, false);
+}
+
+void WidgetWin::OnMButtonUp(UINT flags, const CPoint& point) {
+ ProcessMouseReleased(point, flags | MK_MBUTTON);
+}
+
+void WidgetWin::OnMButtonDblClk(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_MBUTTON, true, false);
+}
+
+LRESULT WidgetWin::OnMouseActivate(HWND window, UINT hittest_code,
+ UINT message) {
+ SetMsgHandled(FALSE);
+ return MA_ACTIVATE;
+}
+
+void WidgetWin::OnMouseMove(UINT flags, const CPoint& point) {
+ ProcessMouseMoved(point, flags, false);
+}
+
+LRESULT WidgetWin::OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param) {
+ tooltip_manager_->OnMouseLeave();
+ ProcessMouseExited();
+ return 0;
+}
+
+LRESULT WidgetWin::OnMouseWheel(UINT message, WPARAM w_param, LPARAM l_param) {
+ // Reroute the mouse-wheel to the window under the mouse pointer if
+ // applicable.
+ if (message == WM_MOUSEWHEEL &&
+ views::RerouteMouseWheel(hwnd_, w_param, l_param)) {
+ return 0;
+ }
+
+ int flags = GET_KEYSTATE_WPARAM(w_param);
+ short distance = GET_WHEEL_DELTA_WPARAM(w_param);
+ int x = GET_X_LPARAM(l_param);
+ int y = GET_Y_LPARAM(l_param);
+ MouseWheelEvent e(distance, x, y, Event::ConvertWindowsFlags(flags));
+ return root_view_->ProcessMouseWheelEvent(e) ? 0 : 1;
+}
+
+LRESULT WidgetWin::OnMouseRange(UINT msg, WPARAM w_param, LPARAM l_param) {
+ tooltip_manager_->OnMouse(msg, w_param, l_param);
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void WidgetWin::OnNCLButtonDblClk(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_LBUTTON, true, true));
+}
+
+void WidgetWin::OnNCLButtonDown(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_LBUTTON, false, true));
+}
+
+void WidgetWin::OnNCLButtonUp(UINT flags, const CPoint& point) {
+ SetMsgHandled(FALSE);
+}
+
+void WidgetWin::OnNCMButtonDblClk(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_MBUTTON, true, true));
+}
+
+void WidgetWin::OnNCMButtonDown(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_MBUTTON, false, true));
+}
+
+void WidgetWin::OnNCMButtonUp(UINT flags, const CPoint& point) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnNCMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param) {
+ ProcessMouseExited();
+ return 0;
+}
+
+LRESULT WidgetWin::OnNCMouseMove(UINT flags, const CPoint& point) {
+ // NC points are in screen coordinates.
+ CPoint temp = point;
+ MapWindowPoints(HWND_DESKTOP, GetNativeView(), &temp, 1);
+ ProcessMouseMoved(temp, 0, true);
+
+ // We need to process this message to stop Windows from drawing the window
+ // controls as the mouse moves over the title bar area when the window is
+ // maximized.
+ return 0;
+}
+
+void WidgetWin::OnNCRButtonDblClk(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_RBUTTON, true, true));
+}
+
+void WidgetWin::OnNCRButtonDown(UINT flags, const CPoint& point) {
+ SetMsgHandled(ProcessMousePressed(point, flags | MK_RBUTTON, false, true));
+}
+
+void WidgetWin::OnNCRButtonUp(UINT flags, const CPoint& point) {
+ SetMsgHandled(FALSE);
+}
+
+LRESULT WidgetWin::OnNotify(int w_param, NMHDR* l_param) {
+ // We can be sent this message before the tooltip manager is created, if a
+ // subclass overrides OnCreate and creates some kind of Windows control there
+ // that sends WM_NOTIFY messages.
+ if (tooltip_manager_.get()) {
+ bool handled;
+ LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
+ SetMsgHandled(handled);
+ return result;
+ }
+ SetMsgHandled(FALSE);
+ return 0;
+}
+
+void WidgetWin::OnPaint(HDC dc) {
+ root_view_->OnPaint(GetNativeView());
+}
+
+void WidgetWin::OnRButtonDown(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_RBUTTON, false, false);
+}
+
+void WidgetWin::OnRButtonUp(UINT flags, const CPoint& point) {
+ ProcessMouseReleased(point, flags | MK_RBUTTON);
+}
+
+void WidgetWin::OnRButtonDblClk(UINT flags, const CPoint& point) {
+ ProcessMousePressed(point, flags | MK_RBUTTON, true, false);
+}
+
+void WidgetWin::OnSize(UINT param, const CSize& size) {
+ ChangeSize(param, size);
+}
+
+void WidgetWin::OnThemeChanged() {
+ // Notify NativeTheme.
+ gfx::NativeTheme::instance()->CloseHandles();
+}
+
+void WidgetWin::OnFinalMessage(HWND window) {
+ if (delete_on_destroy_)
+ delete this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WidgetWin, protected:
+
+void WidgetWin::TrackMouseEvents(DWORD mouse_tracking_flags) {
+ // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE
+ // when the user moves the mouse outside this HWND's bounds.
+ if (active_mouse_tracking_flags_ == 0 || mouse_tracking_flags & TME_CANCEL) {
+ if (mouse_tracking_flags & TME_CANCEL) {
+ // We're about to cancel active mouse tracking, so empty out the stored
+ // state.
+ active_mouse_tracking_flags_ = 0;
+ } else {
+ active_mouse_tracking_flags_ = mouse_tracking_flags;
+ }
+
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = mouse_tracking_flags;
+ tme.hwndTrack = GetNativeView();
+ tme.dwHoverTime = 0;
+ TrackMouseEvent(&tme);
+ } else if (mouse_tracking_flags != active_mouse_tracking_flags_) {
+ TrackMouseEvents(active_mouse_tracking_flags_ | TME_CANCEL);
+ TrackMouseEvents(mouse_tracking_flags);
+ }
+}
+
+bool WidgetWin::ProcessMousePressed(const CPoint& point,
+ UINT flags,
+ bool dbl_click,
+ bool non_client) {
+ last_mouse_event_was_move_ = false;
+ // Windows gives screen coordinates for nonclient events, while the RootView
+ // expects window coordinates; convert if necessary.
+ gfx::Point converted_point(point);
+ if (non_client)
+ View::ConvertPointToView(NULL, root_view_.get(), &converted_point);
+ MouseEvent mouse_pressed(Event::ET_MOUSE_PRESSED,
+ converted_point.x(),
+ converted_point.y(),
+ (dbl_click ? MouseEvent::EF_IS_DOUBLE_CLICK : 0) |
+ (non_client ? MouseEvent::EF_IS_NON_CLIENT : 0) |
+ Event::ConvertWindowsFlags(flags));
+ if (root_view_->OnMousePressed(mouse_pressed)) {
+ is_mouse_down_ = true;
+ if (!has_capture_) {
+ SetCapture();
+ has_capture_ = true;
+ current_action_ = FA_FORWARDING;
+ }
+ return true;
+ }
+ return false;
+}
+
+void WidgetWin::ProcessMouseDragged(const CPoint& point, UINT flags) {
+ last_mouse_event_was_move_ = false;
+ MouseEvent mouse_drag(Event::ET_MOUSE_DRAGGED,
+ point.x,
+ point.y,
+ Event::ConvertWindowsFlags(flags));
+ root_view_->OnMouseDragged(mouse_drag);
+}
+
+void WidgetWin::ProcessMouseReleased(const CPoint& point, UINT flags) {
+ last_mouse_event_was_move_ = false;
+ MouseEvent mouse_up(Event::ET_MOUSE_RELEASED,
+ point.x,
+ point.y,
+ Event::ConvertWindowsFlags(flags));
+ // Release the capture first, that way we don't get confused if
+ // OnMouseReleased blocks.
+ if (has_capture_ && ReleaseCaptureOnMouseReleased()) {
+ has_capture_ = false;
+ current_action_ = FA_NONE;
+ ReleaseCapture();
+ }
+ is_mouse_down_ = false;
+ root_view_->OnMouseReleased(mouse_up, false);
+}
+
+void WidgetWin::ProcessMouseMoved(const CPoint &point, UINT flags,
+ bool is_nonclient) {
+ // Windows only fires WM_MOUSELEAVE events if the application begins
+ // "tracking" mouse events for a given HWND during WM_MOUSEMOVE events.
+ // We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE.
+ if (!has_capture_)
+ TrackMouseEvents(is_nonclient ? TME_NONCLIENT | TME_LEAVE : TME_LEAVE);
+ if (has_capture_ && is_mouse_down_) {
+ ProcessMouseDragged(point, flags);
+ } else {
+ gfx::Point screen_loc(point);
+ View::ConvertPointToScreen(root_view_.get(), &screen_loc);
+ if (last_mouse_event_was_move_ && last_mouse_move_x_ == screen_loc.x() &&
+ last_mouse_move_y_ == screen_loc.y()) {
+ // Don't generate a mouse event for the same location as the last.
+ return;
+ }
+ last_mouse_move_x_ = screen_loc.x();
+ last_mouse_move_y_ = screen_loc.y();
+ last_mouse_event_was_move_ = true;
+ MouseEvent mouse_move(Event::ET_MOUSE_MOVED,
+ point.x,
+ point.y,
+ Event::ConvertWindowsFlags(flags));
+ root_view_->OnMouseMoved(mouse_move);
+ }
+}
+
+void WidgetWin::ProcessMouseExited() {
+ last_mouse_event_was_move_ = false;
+ root_view_->ProcessOnMouseExited();
+ // Reset our tracking flag so that future mouse movement over this WidgetWin
+ // results in a new tracking session.
+ active_mouse_tracking_flags_ = 0;
+}
+
+void WidgetWin::ChangeSize(UINT size_param, const CSize& size) {
+ CRect rect;
+ if (use_layered_buffer_) {
+ GetWindowRect(&rect);
+ SizeContents(rect);
+ } else {
+ GetClientRect(&rect);
+ }
+
+ // Resizing changes the size of the view hierarchy and thus forces a
+ // complete relayout.
+ root_view_->SetBounds(0, 0, rect.Width(), rect.Height());
+ root_view_->Layout();
+ root_view_->SchedulePaint();
+
+ if (use_layered_buffer_)
+ PaintNow(gfx::Rect(rect));
+}
+
+RootView* WidgetWin::CreateRootView() {
+ return new RootView(this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// WidgetWin, private:
+
+// static
+Window* WidgetWin::GetWindowImpl(HWND hwnd) {
+ // NOTE: we can't use GetAncestor here as constrained windows are a Window,
+ // but not a top level window.
+ HWND parent = hwnd;
+ while (parent) {
+ WidgetWin* widget =
+ reinterpret_cast<WidgetWin*>(win_util::GetWindowUserData(parent));
+ if (widget && widget->is_window_)
+ return static_cast<WindowWin*>(widget);
+ parent = ::GetParent(parent);
+ }
+ return NULL;
+}
+
+void WidgetWin::SizeContents(const CRect& window_rect) {
+ contents_.reset(new ChromeCanvas(window_rect.Width(),
+ window_rect.Height(),
+ false));
+}
+
+void WidgetWin::PaintLayeredWindow() {
+ // Painting monkeys with our cliprect, so we need to save it so that the
+ // call to UpdateLayeredWindow updates the entire window, not just the
+ // cliprect.
+ contents_->save(SkCanvas::kClip_SaveFlag);
+ gfx::Rect dirty_rect = root_view_->GetScheduledPaintRect();
+ contents_->ClipRectInt(dirty_rect.x(), dirty_rect.y(), dirty_rect.width(),
+ dirty_rect.height());
+ root_view_->ProcessPaint(contents_.get());
+ contents_->restore();
+
+ UpdateWindowFromContents(contents_->getTopPlatformDevice().getBitmapDC());
+}
+
+void WidgetWin::UpdateWindowFromContents(HDC dib_dc) {
+ DCHECK(use_layered_buffer_);
+ if (can_update_layered_window_) {
+ CRect wr;
+ GetWindowRect(&wr);
+ CSize size(wr.right - wr.left, wr.bottom - wr.top);
+ CPoint zero_origin(0, 0);
+ CPoint window_position = wr.TopLeft();
+
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA};
+ ::UpdateLayeredWindow(
+ hwnd_, NULL, &window_position, &size, dib_dc, &zero_origin,
+ RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
+ }
+}
+
+std::wstring WidgetWin::GetWindowClassName() {
+ ClassInfo class_info(initial_class_style());
+ std::wstring name;
+ if (Singleton<ClassRegistrar>()->RetrieveClassName(class_info, &name))
+ return name;
+
+ // No class found, need to register one.
+ WNDCLASSEX class_ex;
+ class_ex.cbSize = sizeof(WNDCLASSEX);
+ class_ex.style = class_info.style;
+ class_ex.lpfnWndProc = &WidgetWin::WndProc;
+ class_ex.cbClsExtra = 0;
+ class_ex.cbWndExtra = 0;
+ class_ex.hInstance = NULL;
+ class_ex.hIcon = LoadIcon(GetModuleHandle(L"chrome.dll"),
+ MAKEINTRESOURCE(IDR_MAINFRAME));
+ class_ex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ class_ex.hbrBackground = reinterpret_cast<HBRUSH>(class_info.background + 1);
+ class_ex.lpszMenuName = NULL;
+ class_ex.lpszClassName = name.c_str();
+ class_ex.hIconSm = class_ex.hIcon;
+ ATOM atom = RegisterClassEx(&class_ex);
+ DCHECK(atom);
+
+ Singleton<ClassRegistrar>()->RegisterClass(class_info, name, atom);
+
+ return name;
+}
+
+// Get the source HWND of the specified message. Depending on the message, the
+// source HWND is encoded in either the WPARAM or the LPARAM value.
+HWND GetControlHWNDForMessage(UINT message, WPARAM w_param, LPARAM l_param) {
+ // Each of the following messages can be sent by a child HWND and must be
+ // forwarded to its associated NativeControlWin for handling.
+ switch (message) {
+ case WM_NOTIFY:
+ return reinterpret_cast<NMHDR*>(l_param)->hwndFrom;
+ case WM_COMMAND:
+ return reinterpret_cast<HWND>(l_param);
+ case WM_CONTEXTMENU:
+ return reinterpret_cast<HWND>(w_param);
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORSTATIC:
+ return reinterpret_cast<HWND>(l_param);
+ }
+ return NULL;
+}
+
+// Some messages may be sent to us by a child HWND managed by
+// NativeControlWin. If this is the case, this function will forward those
+// messages on to the object associated with the source HWND and return true,
+// in which case the window procedure must not do any further processing of
+// the message. If there is no associated NativeControlWin, the return value
+// will be false and the WndProc can continue processing the message normally.
+// |l_result| contains the result of the message processing by the control and
+// must be returned by the WndProc if the return value is true.
+bool ProcessNativeControlMessage(UINT message,
+ WPARAM w_param,
+ LPARAM l_param,
+ LRESULT* l_result) {
+ *l_result = 0;
+
+ HWND control_hwnd = GetControlHWNDForMessage(message, w_param, l_param);
+ if (IsWindow(control_hwnd)) {
+ NativeControlWin* wrapper = GetNativeControlWinForHWND(control_hwnd);
+ if (wrapper)
+ return wrapper->ProcessMessage(message, w_param, l_param, l_result);
+ }
+
+ return false;
+}
+
+// static
+LRESULT CALLBACK WidgetWin::WndProc(HWND window, UINT message,
+ WPARAM w_param, LPARAM l_param) {
+ if (message == WM_NCCREATE) {
+ CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(l_param);
+ WidgetWin* widget = reinterpret_cast<WidgetWin*>(cs->lpCreateParams);
+ DCHECK(widget);
+ win_util::SetWindowUserData(window, widget);
+ widget->hwnd_ = window;
+ return TRUE;
+ }
+
+ WidgetWin* widget = reinterpret_cast<WidgetWin*>(
+ win_util::GetWindowUserData(window));
+ if (!widget)
+ return 0;
+
+ LRESULT result = 0;
+
+ // First allow messages sent by child controls to be processed directly by
+ // their associated views. If such a view is present, it will handle the
+ // message *instead of* this WidgetWin.
+ if (ProcessNativeControlMessage(message, w_param, l_param, &result))
+ return result;
+
+ // Otherwise we handle everything else.
+ if (!widget->ProcessWindowMessage(window, message, w_param, l_param, result))
+ result = DefWindowProc(window, message, w_param, l_param);
+ if (message == WM_NCDESTROY) {
+ TRACK_HWND_DESTRUCTION(window);
+ widget->hwnd_ = NULL;
+ widget->OnFinalMessage(window);
+ }
+ return result;
+}
+
+} // namespace views
diff --git a/views/widget/widget_win.h b/views/widget/widget_win.h
new file mode 100644
index 0000000..09efa21
--- /dev/null
+++ b/views/widget/widget_win.h
@@ -0,0 +1,636 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef VIEWS_WIDGET_WIDGET_WIN_H_
+#define VIEWS_WIDGET_WIDGET_WIN_H_
+
+#include <atlbase.h>
+#include <atlcrack.h>
+
+#include "base/message_loop.h"
+#include "base/system_monitor.h"
+#include "views/focus/focus_manager.h"
+#include "views/layout_manager.h"
+#include "views/widget/widget.h"
+
+class ChromeCanvas;
+
+namespace gfx {
+class Rect;
+}
+
+namespace views {
+
+class RootView;
+class TooltipManager;
+class Window;
+
+bool SetRootViewForHWND(HWND hwnd, RootView* root_view);
+RootView* GetRootViewForHWND(HWND hwnd);
+
+// A Windows message reflected from other windows. This message is sent
+// with the following arguments:
+// hWnd - Target window
+// uMsg - kReflectedMessage
+// wParam - Should be 0
+// lParam - Pointer to MSG struct containing the original message.
+static const int kReflectedMessage = WM_APP + 3;
+
+// These two messages aren't defined in winuser.h, but they are sent to windows
+// with captions. They appear to paint the window caption and frame.
+// Unfortunately if you override the standard non-client rendering as we do
+// with CustomFrameWindow, sometimes Windows (not deterministically
+// reproducibly but definitely frequently) will send these messages to the
+// window and paint the standard caption/title over the top of the custom one.
+// So we need to handle these messages in CustomFrameWindow to prevent this
+// from happening.
+static const int WM_NCUAHDRAWCAPTION = 0xAE;
+static const int WM_NCUAHDRAWFRAME = 0xAF;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// WidgetWin
+// A Widget for a views hierarchy used to represent anything that can be
+// contained within an HWND, e.g. a control, a window, etc. Specializations
+// suitable for specific tasks, e.g. top level window, are derived from this.
+//
+// This Widget contains a RootView which owns the hierarchy of views within it.
+// As long as views are part of this tree, they will be deleted automatically
+// when the RootView is destroyed. If you remove a view from the tree, you are
+// then responsible for cleaning up after it.
+//
+///////////////////////////////////////////////////////////////////////////////
+class WidgetWin : public Widget,
+ public MessageLoopForUI::Observer,
+ public FocusTraversable,
+ public AcceleratorTarget {
+ public:
+ WidgetWin();
+ virtual ~WidgetWin();
+
+ // Initialize the Widget with a parent and an initial desired size.
+ // |contents_view| is the view that will be the single child of RootView
+ // within this Widget. As contents_view is inserted into RootView's tree,
+ // RootView assumes ownership of this view and cleaning it up. If you remove
+ // this view, you are responsible for its destruction. If this value is NULL,
+ // the caller is responsible for populating the RootView, and sizing its
+ // contents as the window is sized.
+ // If |has_own_focus_manager| is true, the focus traversal stay confined to
+ // the window.
+ void Init(HWND parent,
+ const gfx::Rect& bounds,
+ bool has_own_focus_manager);
+
+ // Sets the specified view as the contents of this Widget. There can only
+ // be one contnets view child of this Widget's RootView. This view is sized to
+ // fit the entire size of the RootView. The RootView takes ownership of this
+ // View, unless it is set as not being parent-owned.
+ virtual void SetContentsView(View* view);
+
+ // Sets the window styles. This is ONLY used when the window is created.
+ // In other words, if you invoke this after invoking Init, nothing happens.
+ void set_window_style(DWORD style) { window_style_ = style; }
+ DWORD window_style() const { return window_style_; }
+
+ // Sets the extended window styles. See comment about |set_window_style|.
+ void set_window_ex_style(DWORD style) { window_ex_style_ = style; }
+ DWORD window_ex_style() const { return window_ex_style_; };
+
+ // Sets the class style to use. The default is CS_DBLCLKS.
+ void set_initial_class_style(UINT class_style) {
+ // We dynamically generate the class name, so don't register it globally!
+ DCHECK((class_style & CS_GLOBALCLASS) == 0);
+ class_style_ = class_style;
+ }
+ UINT initial_class_style() { return class_style_; }
+
+ void set_delete_on_destroy(bool delete_on_destroy) {
+ delete_on_destroy_ = delete_on_destroy;
+ }
+
+ // Sets the initial opacity of a layered window, or updates the window's
+ // opacity if it is on the screen.
+ void SetLayeredAlpha(BYTE layered_alpha);
+
+ // See description of use_layered_buffer_ for details.
+ void SetUseLayeredBuffer(bool use_layered_buffer);
+
+ // Disable Layered Window updates by setting to false.
+ void set_can_update_layered_window(bool can_update_layered_window) {
+ can_update_layered_window_ = can_update_layered_window;
+ }
+
+ // Returns the RootView associated with the specified HWND (if any).
+ static RootView* FindRootView(HWND hwnd);
+
+ // Closes the window asynchronously by scheduling a task for it. The window
+ // is destroyed as a result.
+ // This invokes Hide to hide the window, and schedules a task that
+ // invokes CloseNow.
+ virtual void Close();
+
+ // Hides the window. This does NOT delete the window, it just hides it.
+ virtual void Hide();
+
+ // Shows the window without changing size/position/activation state.
+ virtual void Show();
+
+ // Closes the window synchronously. Note that this should not be called from
+ // an ATL message callback as it deletes the WidgetWin and ATL will
+ // dereference it after the callback is processed.
+ void CloseNow();
+
+ // All classes registered by WidgetWin start with this name.
+ static const wchar_t* const kBaseClassName;
+
+ BEGIN_MSG_MAP_EX(0)
+ // Range handlers must go first!
+ MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
+ MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCMOUSEMOVE, OnMouseRange)
+
+ // Reflected message handler
+ MESSAGE_HANDLER_EX(kReflectedMessage, OnReflectedMessage)
+
+ // CustomFrameWindow hacks
+ MESSAGE_HANDLER_EX(WM_NCUAHDRAWCAPTION, OnNCUAHDrawCaption)
+ MESSAGE_HANDLER_EX(WM_NCUAHDRAWFRAME, OnNCUAHDrawFrame)
+
+ // Vista and newer
+ MESSAGE_HANDLER_EX(WM_DWMCOMPOSITIONCHANGED, OnDwmCompositionChanged)
+
+ // Non-atlcrack.h handlers
+ MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
+ MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnNCMouseLeave)
+ MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseLeave)
+ MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, OnMouseWheel)
+
+ // This list is in _ALPHABETICAL_ order! OR I WILL HURT YOU.
+ MSG_WM_ACTIVATE(OnActivate)
+ MSG_WM_ACTIVATEAPP(OnActivateApp)
+ MSG_WM_APPCOMMAND(OnAppCommand)
+ MSG_WM_CANCELMODE(OnCancelMode)
+ MSG_WM_CAPTURECHANGED(OnCaptureChanged)
+ MSG_WM_CLOSE(OnClose)
+ MSG_WM_COMMAND(OnCommand)
+ MSG_WM_CREATE(OnCreate)
+ MSG_WM_DESTROY(OnDestroy)
+ MSG_WM_ERASEBKGND(OnEraseBkgnd)
+ MSG_WM_ENDSESSION(OnEndSession)
+ MSG_WM_ENTERSIZEMOVE(OnEnterSizeMove)
+ MSG_WM_EXITMENULOOP(OnExitMenuLoop)
+ MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo)
+ MSG_WM_HSCROLL(OnHScroll)
+ MSG_WM_INITMENU(OnInitMenu)
+ MSG_WM_INITMENUPOPUP(OnInitMenuPopup)
+ MSG_WM_KEYDOWN(OnKeyDown)
+ MSG_WM_KEYUP(OnKeyUp)
+ MSG_WM_SYSKEYDOWN(OnKeyDown)
+ MSG_WM_SYSKEYUP(OnKeyUp)
+ MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
+ MSG_WM_LBUTTONDOWN(OnLButtonDown)
+ MSG_WM_LBUTTONUP(OnLButtonUp)
+ MSG_WM_MBUTTONDOWN(OnMButtonDown)
+ MSG_WM_MBUTTONUP(OnMButtonUp)
+ MSG_WM_MBUTTONDBLCLK(OnMButtonDblClk)
+ MSG_WM_MOUSEACTIVATE(OnMouseActivate)
+ MSG_WM_MOUSEMOVE(OnMouseMove)
+ MSG_WM_MOVE(OnMove)
+ MSG_WM_MOVING(OnMoving)
+ MSG_WM_NCACTIVATE(OnNCActivate)
+ MSG_WM_NCCALCSIZE(OnNCCalcSize)
+ MSG_WM_NCHITTEST(OnNCHitTest)
+ MSG_WM_NCMOUSEMOVE(OnNCMouseMove)
+ MSG_WM_NCLBUTTONDBLCLK(OnNCLButtonDblClk)
+ MSG_WM_NCLBUTTONDOWN(OnNCLButtonDown)
+ MSG_WM_NCLBUTTONUP(OnNCLButtonUp)
+ MSG_WM_NCMBUTTONDBLCLK(OnNCMButtonDblClk)
+ MSG_WM_NCMBUTTONDOWN(OnNCMButtonDown)
+ MSG_WM_NCMBUTTONUP(OnNCMButtonUp)
+ MSG_WM_NCPAINT(OnNCPaint)
+ MSG_WM_NCRBUTTONDBLCLK(OnNCRButtonDblClk)
+ MSG_WM_NCRBUTTONDOWN(OnNCRButtonDown)
+ MSG_WM_NCRBUTTONUP(OnNCRButtonUp)
+ MSG_WM_NOTIFY(OnNotify)
+ MSG_WM_PAINT(OnPaint)
+ MSG_WM_POWERBROADCAST(OnPowerBroadcast)
+ MSG_WM_RBUTTONDBLCLK(OnRButtonDblClk)
+ MSG_WM_RBUTTONDOWN(OnRButtonDown)
+ MSG_WM_RBUTTONUP(OnRButtonUp)
+ MSG_WM_SETCURSOR(OnSetCursor)
+ MSG_WM_SETFOCUS(OnSetFocus)
+ MSG_WM_SETICON(OnSetIcon)
+ MSG_WM_SETTEXT(OnSetText)
+ MSG_WM_SETTINGCHANGE(OnSettingChange)
+ MSG_WM_SIZE(OnSize)
+ MSG_WM_SYSCOMMAND(OnSysCommand)
+ MSG_WM_THEMECHANGED(OnThemeChanged)
+ MSG_WM_VSCROLL(OnVScroll)
+ MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging)
+ MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
+ END_MSG_MAP()
+
+ // Overridden from Widget:
+ virtual void GetBounds(gfx::Rect* out, bool including_frame) const;
+ virtual gfx::NativeView GetNativeView() const;
+ virtual void PaintNow(const gfx::Rect& update_rect);
+ virtual RootView* GetRootView();
+ virtual bool IsVisible() const;
+ virtual bool IsActive() const;
+ virtual TooltipManager* GetTooltipManager();
+ virtual Window* GetWindow();
+ virtual const Window* GetWindow() const;
+
+ // Overridden from MessageLoop::Observer:
+ void WillProcessMessage(const MSG& msg);
+ virtual void DidProcessMessage(const MSG& msg);
+
+ // Overridden from FocusTraversable:
+ virtual View* FindNextFocusableView(View* starting_view,
+ bool reverse,
+ Direction direction,
+ bool dont_loop,
+ FocusTraversable** focus_traversable,
+ View** focus_traversable_view);
+ virtual FocusTraversable* GetFocusTraversableParent();
+ virtual View* GetFocusTraversableParentView();
+
+ // Overridden from AcceleratorTarget:
+ virtual bool AcceleratorPressed(const Accelerator& accelerator) {
+ return false;
+ }
+
+ void SetFocusTraversableParent(FocusTraversable* parent);
+ void SetFocusTraversableParentView(View* parent_view);
+
+ virtual bool GetAccelerator(int cmd_id, Accelerator* accelerator) {
+ return false;
+ }
+
+ BOOL IsWindow() const {
+ return ::IsWindow(GetNativeView());
+ }
+
+ BOOL ShowWindow(int command) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::ShowWindow(GetNativeView(), command);
+ }
+
+ HWND SetCapture() {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::SetCapture(GetNativeView());
+ }
+
+ HWND GetParent() const {
+ return ::GetParent(GetNativeView());
+ }
+
+ LONG GetWindowLong(int index) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::GetWindowLong(GetNativeView(), index);
+ }
+
+ BOOL GetWindowRect(RECT* rect) const {
+ return ::GetWindowRect(GetNativeView(), rect);
+ }
+
+ LONG SetWindowLong(int index, LONG new_long) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::SetWindowLong(GetNativeView(), index, new_long);
+ }
+
+ BOOL SetWindowPos(HWND hwnd_after, int x, int y, int cx, int cy, UINT flags) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::SetWindowPos(GetNativeView(), hwnd_after, x, y, cx, cy, flags);
+ }
+
+ BOOL IsZoomed() const {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::IsZoomed(GetNativeView());
+ }
+
+ BOOL MoveWindow(int x, int y, int width, int height) {
+ return MoveWindow(x, y, width, height, TRUE);
+ }
+
+ BOOL MoveWindow(int x, int y, int width, int height, BOOL repaint) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::MoveWindow(GetNativeView(), x, y, width, height, repaint);
+ }
+
+ int SetWindowRgn(HRGN region, BOOL redraw) {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::SetWindowRgn(GetNativeView(), region, redraw);
+ }
+
+ BOOL GetClientRect(RECT* rect) const {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::GetClientRect(GetNativeView(), rect);
+ }
+
+ protected:
+
+ // Call close instead of this to Destroy the window.
+ BOOL DestroyWindow() {
+ DCHECK(::IsWindow(GetNativeView()));
+ return ::DestroyWindow(GetNativeView());
+ }
+
+ // Message Handlers
+ // These are all virtual so that specialized Widgets can modify or augment
+ // processing.
+ // This list is in _ALPHABETICAL_ order!
+ // Note: in the base class these functions must do nothing but convert point
+ // coordinates to client coordinates (if necessary) and forward the
+ // handling to the appropriate Process* function. This is so that
+ // subclasses can easily override these methods to do different things
+ // and have a convenient function to call to get the default behavior.
+ virtual void OnActivate(UINT action, BOOL minimized, HWND window) {
+ SetMsgHandled(FALSE);
+ }
+ virtual void OnActivateApp(BOOL active, DWORD thread_id) {
+ SetMsgHandled(FALSE);
+ }
+ virtual LRESULT OnAppCommand(HWND window, short app_command, WORD device,
+ int keystate) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual void OnCancelMode() {}
+ virtual void OnCaptureChanged(HWND hwnd);
+ virtual void OnClose();
+ virtual void OnCommand(UINT notification_code, int command_id, HWND window) {
+ SetMsgHandled(FALSE);
+ }
+ virtual LRESULT OnCreate(LPCREATESTRUCT create_struct) { return 0; }
+ // WARNING: If you override this be sure and invoke super, otherwise we'll
+ // leak a few things.
+ virtual void OnDestroy();
+ virtual LRESULT OnDwmCompositionChanged(UINT msg,
+ WPARAM w_param,
+ LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual void OnEndSession(BOOL ending, UINT logoff) { SetMsgHandled(FALSE); }
+ virtual void OnEnterSizeMove() { SetMsgHandled(FALSE); }
+ virtual void OnExitMenuLoop(BOOL is_track_popup_menu) {
+ SetMsgHandled(FALSE);
+ }
+ virtual LRESULT OnEraseBkgnd(HDC dc);
+ virtual LRESULT OnGetObject(UINT uMsg, WPARAM w_param, LPARAM l_param);
+ virtual void OnGetMinMaxInfo(MINMAXINFO* minmax_info) {
+ SetMsgHandled(FALSE);
+ }
+ virtual void OnHScroll(int scroll_type, short position, HWND scrollbar) {
+ SetMsgHandled(FALSE);
+ }
+ virtual void OnInitMenu(HMENU menu) { SetMsgHandled(FALSE); }
+ virtual void OnInitMenuPopup(HMENU menu, UINT position, BOOL is_system_menu) {
+ SetMsgHandled(FALSE);
+ }
+ virtual void OnKeyDown(TCHAR c, UINT rep_cnt, UINT flags);
+ virtual void OnKeyUp(TCHAR c, UINT rep_cnt, UINT flags);
+ virtual void OnLButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnLButtonDown(UINT flags, const CPoint& point);
+ virtual void OnLButtonUp(UINT flags, const CPoint& point);
+ virtual void OnMButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnMButtonDown(UINT flags, const CPoint& point);
+ virtual void OnMButtonUp(UINT flags, const CPoint& point);
+ virtual LRESULT OnMouseActivate(HWND window, UINT hittest_code, UINT message);
+ virtual void OnMouseMove(UINT flags, const CPoint& point);
+ virtual LRESULT OnMouseLeave(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual LRESULT OnMouseWheel(UINT message, WPARAM w_param, LPARAM l_param);
+ virtual void OnMove(const CPoint& point) { SetMsgHandled(FALSE); }
+ virtual void OnMoving(UINT param, const LPRECT new_bounds) { }
+ virtual LRESULT OnMouseRange(UINT msg, WPARAM w_param, LPARAM l_param);
+ virtual LRESULT OnNCActivate(BOOL active) { SetMsgHandled(FALSE); return 0; }
+ virtual LRESULT OnNCCalcSize(BOOL w_param, LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual LRESULT OnNCHitTest(const CPoint& pt) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual void OnNCLButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnNCLButtonDown(UINT flags, const CPoint& point);
+ virtual void OnNCLButtonUp(UINT flags, const CPoint& point);
+ virtual void OnNCMButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnNCMButtonDown(UINT flags, const CPoint& point);
+ virtual void OnNCMButtonUp(UINT flags, const CPoint& point);
+ virtual LRESULT OnNCMouseLeave(UINT uMsg, WPARAM w_param, LPARAM l_param);
+ virtual LRESULT OnNCMouseMove(UINT flags, const CPoint& point);
+ virtual void OnNCPaint(HRGN rgn) { SetMsgHandled(FALSE); }
+ virtual void OnNCRButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnNCRButtonDown(UINT flags, const CPoint& point);
+ virtual void OnNCRButtonUp(UINT flags, const CPoint& point);
+ virtual LRESULT OnNCUAHDrawCaption(UINT msg,
+ WPARAM w_param,
+ LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual LRESULT OnNCUAHDrawFrame(UINT msg, WPARAM w_param, LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual LRESULT OnNotify(int w_param, NMHDR* l_param);
+ virtual void OnPaint(HDC dc);
+ virtual LRESULT OnPowerBroadcast(DWORD power_event, DWORD data) {
+ base::SystemMonitor* monitor = base::SystemMonitor::Get();
+ if (monitor)
+ monitor->ProcessWmPowerBroadcastMessage(power_event);
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual void OnRButtonDblClk(UINT flags, const CPoint& point);
+ virtual void OnRButtonDown(UINT flags, const CPoint& point);
+ virtual void OnRButtonUp(UINT flags, const CPoint& point);
+ virtual LRESULT OnReflectedMessage(UINT msg, WPARAM w_param, LPARAM l_param) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual LRESULT OnSetCursor(HWND window, UINT hittest_code, UINT message) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual void OnSetFocus(HWND focused_window) {
+ SetMsgHandled(FALSE);
+ }
+ virtual LRESULT OnSetIcon(UINT size_type, HICON new_icon) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual LRESULT OnSetText(const wchar_t* text) {
+ SetMsgHandled(FALSE);
+ return 0;
+ }
+ virtual void OnSettingChange(UINT flags, const wchar_t* section) {
+ SetMsgHandled(FALSE);
+ }
+ virtual void OnSize(UINT param, const CSize& size);
+ virtual void OnSysCommand(UINT notification_code, CPoint click) { }
+ virtual void OnThemeChanged();
+ virtual void OnVScroll(int scroll_type, short position, HWND scrollbar) {
+ SetMsgHandled(FALSE);
+ }
+ virtual void OnWindowPosChanging(WINDOWPOS* window_pos) {
+ SetMsgHandled(FALSE);
+ }
+ virtual void OnWindowPosChanged(WINDOWPOS* window_pos) {
+ SetMsgHandled(FALSE);
+ }
+
+ // deletes this window as it is destroyed, override to provide different
+ // behavior.
+ virtual void OnFinalMessage(HWND window);
+
+ // Start tracking all mouse events so that this window gets sent mouse leave
+ // messages too. |is_nonclient| is true when we should track WM_NCMOUSELEAVE
+ // messages instead of WM_MOUSELEAVE ones.
+ void TrackMouseEvents(DWORD mouse_tracking_flags);
+
+ // Actually handle mouse events. These functions are called by subclasses who
+ // override the message handlers above to do the actual real work of handling
+ // the event in the View system.
+ bool ProcessMousePressed(const CPoint& point,
+ UINT flags,
+ bool dbl_click,
+ bool non_client);
+ void ProcessMouseDragged(const CPoint& point, UINT flags);
+ void ProcessMouseReleased(const CPoint& point, UINT flags);
+ void ProcessMouseMoved(const CPoint& point, UINT flags, bool is_nonclient);
+ void ProcessMouseExited();
+
+ // Handles re-laying out content in response to a window size change.
+ virtual void ChangeSize(UINT size_param, const CSize& size);
+
+ // Returns whether capture should be released on mouse release. The default
+ // is true.
+ virtual bool ReleaseCaptureOnMouseReleased() { return true; }
+
+ enum FrameAction {FA_NONE = 0, FA_RESIZING, FA_MOVING, FA_FORWARDING};
+
+ virtual RootView* CreateRootView();
+
+ // Returns true if this WidgetWin is opaque.
+ bool opaque() const { return opaque_; }
+
+ // The root of the View hierarchy attached to this window.
+ scoped_ptr<RootView> root_view_;
+
+ // Current frame ui action
+ FrameAction current_action_;
+
+ // Whether or not we have capture the mouse.
+ bool has_capture_;
+
+ // If true, the mouse is currently down.
+ bool is_mouse_down_;
+
+ scoped_ptr<TooltipManager> tooltip_manager_;
+
+ // Are a subclass of WindowWin?
+ bool is_window_;
+
+ private:
+ // Implementation of GetWindow. Ascends the parents of |hwnd| returning the
+ // first ancestor that is a Window.
+ static Window* GetWindowImpl(HWND hwnd);
+
+ // Resize the bitmap used to contain the contents of the layered window. This
+ // recreates the entire bitmap.
+ void SizeContents(const CRect& window_rect);
+
+ // Paint into a DIB and then update the layered window with its contents.
+ void PaintLayeredWindow();
+
+ // In layered mode, update the layered window. |dib_dc| represents a handle
+ // to a device context that contains the contents of the window.
+ void UpdateWindowFromContents(HDC dib_dc);
+
+ // Invoked from WM_DESTROY. Does appropriate cleanup and invokes OnDestroy
+ // so that subclasses can do any cleanup they need to.
+ void OnDestroyImpl();
+
+ // The windows procedure used by all WidgetWins.
+ static LRESULT CALLBACK WndProc(HWND window,
+ UINT message,
+ WPARAM w_param,
+ LPARAM l_param);
+
+ // Gets the window class name to use when creating the corresponding HWND.
+ // If necessary, this registers the window class.
+ std::wstring GetWindowClassName();
+
+ // The following factory is used for calls to close the WidgetWin
+ // instance.
+ ScopedRunnableMethodFactory<WidgetWin> close_widget_factory_;
+
+ // The flags currently being used with TrackMouseEvent to track mouse
+ // messages. 0 if there is no active tracking. The value of this member is
+ // used when tracking is canceled.
+ DWORD active_mouse_tracking_flags_;
+
+ bool opaque_;
+
+ // Window Styles used when creating the window.
+ DWORD window_style_;
+
+ // Window Extended Styles used when creating the window.
+ DWORD window_ex_style_;
+
+ // Style of the class to use.
+ UINT class_style_;
+
+ // Should we keep an offscreen buffer? This is initially true and if the
+ // window has WS_EX_LAYERED then it remains true. You can set this to false
+ // at any time to ditch the buffer, and similarly set back to true to force
+ // creation of the buffer.
+ //
+ // NOTE: this is intended to be used with a layered window (a window with an
+ // extended window style of WS_EX_LAYERED). If you are using a layered window
+ // and NOT changing the layered alpha or anything else, then leave this value
+ // alone. OTOH if you are invoking SetLayeredWindowAttributes then you'll
+ // must likely want to set this to false, or after changing the alpha toggle
+ // the extended style bit to false than back to true. See MSDN for more
+ // details.
+ bool use_layered_buffer_;
+
+ // The default alpha to be applied to the layered window.
+ BYTE layered_alpha_;
+
+ // A canvas that contains the window contents in the case of a layered
+ // window.
+ scoped_ptr<ChromeCanvas> contents_;
+
+ // Whether or not the window should delete itself when it is destroyed.
+ // Set this to false via its setter for stack allocated instances.
+ bool delete_on_destroy_;
+
+ // True if we are allowed to update the layered window from the DIB backing
+ // store if necessary.
+ bool can_update_layered_window_;
+
+ // The following are used to detect duplicate mouse move events and not
+ // deliver them. Displaying a window may result in the system generating
+ // duplicate move events even though the mouse hasn't moved.
+
+ // If true, the last event was a mouse move event.
+ bool last_mouse_event_was_move_;
+
+ // Coordinates of the last mouse move event, in screen coordinates.
+ int last_mouse_move_x_;
+ int last_mouse_move_y_;
+
+ // Instance of accessibility information and handling for MSAA root
+ CComPtr<IAccessible> accessibility_root_;
+
+ // Our hwnd.
+ HWND hwnd_;
+};
+
+} // namespace views
+
+#endif // #ifndef VIEWS_WIDGET_WIDGET_WIN_H_