Index: views/widget/widget_gtk.cc |
=================================================================== |
--- views/widget/widget_gtk.cc (revision 85284) |
+++ views/widget/widget_gtk.cc (working copy) |
@@ -284,9 +284,9 @@ |
//////////////////////////////////////////////////////////////////////////////// |
// WidgetGtk, public: |
-WidgetGtk::WidgetGtk() |
+WidgetGtk::WidgetGtk(internal::NativeWidgetDelegate* delegate) |
: is_window_(false), |
- ALLOW_THIS_IN_INITIALIZER_LIST(delegate_(this)), |
+ delegate_(delegate), |
widget_(NULL), |
window_contents_(NULL), |
child_(false), |
@@ -301,6 +301,7 @@ |
transient_to_parent_(false), |
got_initial_focus_in_(false), |
has_focus_(false), |
+ focus_on_creation_(true), |
always_on_top_(false), |
is_double_buffered_(false), |
should_handle_menu_key_release_(false), |
@@ -311,7 +312,6 @@ |
// the widget. |
TouchFactory::GetInstance(); |
#endif |
- set_native_widget(this); |
static bool installed_message_loop_observer = false; |
if (!installed_message_loop_observer) { |
installed_message_loop_observer = true; |
@@ -325,8 +325,9 @@ |
// We need to delete the input method before calling DestroyRootView(), |
// because it'll set focus_manager_ to NULL. |
input_method_.reset(); |
- DestroyRootView(); |
DCHECK(delete_on_destroy_ || widget_ == NULL); |
+ if (delete_on_destroy_) |
+ delete delegate_; |
} |
GtkWindow* WidgetGtk::GetTransientParent() const { |
@@ -443,7 +444,7 @@ |
} |
void WidgetGtk::IsActiveChanged() { |
- WidgetDelegate* d = widget_delegate(); |
+ WidgetDelegate* d = GetWidget()->widget_delegate(); |
if (d) { |
bool a = IsActive(); |
d->OnWidgetActivated(a); |
@@ -451,8 +452,11 @@ |
} |
void WidgetGtk::SetInitialFocus() { |
- View* v = widget_delegate() ? |
- widget_delegate()->GetInitiallyFocusedView() : NULL; |
+ if (!focus_on_creation_) |
+ return; |
+ |
+ View* v = GetWidget()->widget_delegate() ? |
+ GetWidget()->widget_delegate()->GetInitiallyFocusedView() : NULL; |
if (v) |
v->RequestFocus(); |
} |
@@ -496,52 +500,13 @@ |
} |
if (was_active != IsActive()) { |
IsActiveChanged(); |
- GetRootView()->SchedulePaint(); |
+ GetWidget()->GetRootView()->SchedulePaint(); |
} |
} |
//////////////////////////////////////////////////////////////////////////////// |
// WidgetGtk, Widget implementation: |
-gfx::NativeView WidgetGtk::GetNativeView() const { |
- return widget_; |
-} |
- |
-gfx::NativeWindow WidgetGtk::GetNativeWindow() const { |
- return child_ ? NULL : GTK_WINDOW(widget_); |
-} |
- |
-bool WidgetGtk::GetAccelerator(int cmd_id, ui::Accelerator* accelerator) { |
- NOTIMPLEMENTED(); |
- return false; |
-} |
- |
-Window* WidgetGtk::GetWindow() { |
- return GetWindowImpl(widget_); |
-} |
- |
-const Window* WidgetGtk::GetWindow() const { |
- return GetWindowImpl(widget_); |
-} |
- |
-void WidgetGtk::ViewHierarchyChanged(bool is_add, View* parent, View* child) { |
- Widget::ViewHierarchyChanged(is_add, parent, child); |
- if (drop_target_.get()) |
- drop_target_->ResetTargetViewIfEquals(child); |
-} |
- |
-void WidgetGtk::NotifyAccessibilityEvent( |
- View* view, |
- ui::AccessibilityTypes::Event event_type, |
- bool send_native_event) { |
- // Send the notification to the delegate. |
- if (ViewsDelegate::views_delegate) |
- ViewsDelegate::views_delegate->NotifyAccessibilityEvent(view, event_type); |
- |
- // In the future if we add native GTK accessibility support, the |
- // notification should be sent here. |
-} |
- |
void WidgetGtk::ClearNativeFocus() { |
DCHECK(!child_); |
if (!GetNativeView()) { |
@@ -552,7 +517,7 @@ |
} |
bool WidgetGtk::HandleKeyboardEvent(const KeyEvent& key) { |
- if (!GetFocusManager()) |
+ if (!GetWidget()->GetFocusManager()) |
return false; |
const int key_code = key.key_code(); |
@@ -569,7 +534,7 @@ |
// VKEY_MENU is triggered by key release event. |
// FocusManager::OnKeyEvent() returns false when the key has been consumed. |
if (key_code != ui::VKEY_MENU) |
- handled = !GetFocusManager()->OnKeyEvent(key); |
+ handled = !GetWidget()->GetFocusManager()->OnKeyEvent(key); |
else |
should_handle_menu_key_release_ = true; |
} else if (key_code == ui::VKEY_MENU && should_handle_menu_key_release_ && |
@@ -577,7 +542,7 @@ |
// Trigger VKEY_MENU when only this key is pressed and released, and both |
// press and release events are not handled by others. |
Accelerator accelerator(ui::VKEY_MENU, false, false, false); |
- handled = GetFocusManager()->ProcessAccelerator(accelerator); |
+ handled = GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator); |
} |
return handled; |
@@ -626,10 +591,10 @@ |
//////////////////////////////////////////////////////////////////////////////// |
// WidgetGtk, NativeWidget implementation: |
-void WidgetGtk::InitNativeWidget(const InitParams& params) { |
+void WidgetGtk::InitNativeWidget(const Widget::InitParams& params) { |
SetInitParams(params); |
- InitParams modified_params = params; |
+ Widget::InitParams modified_params = params; |
gfx::NativeView parent = params.parent; |
if (params.parent_widget) { |
WidgetGtk* parent_gtk = |
@@ -766,9 +731,34 @@ |
} |
Widget* WidgetGtk::GetWidget() { |
- return this; |
+ return delegate_->AsWidget(); |
} |
+const Widget* WidgetGtk::GetWidget() const { |
+ return delegate_->AsWidget(); |
+} |
+ |
+gfx::NativeView WidgetGtk::GetNativeView() const { |
+ return widget_; |
+} |
+ |
+gfx::NativeWindow WidgetGtk::GetNativeWindow() const { |
+ return child_ ? NULL : GTK_WINDOW(widget_); |
+} |
+ |
+Window* WidgetGtk::GetContainingWindow() { |
+ return GetWindowImpl(widget_); |
+} |
+ |
+const Window* WidgetGtk::GetContainingWindow() const { |
+ return GetWindowImpl(widget_); |
+} |
+ |
+void WidgetGtk::ViewRemoved(View* view) { |
+ if (drop_target_.get()) |
+ drop_target_->ResetTargetViewIfEquals(view); |
+} |
+ |
void WidgetGtk::SetNativeWindowProperty(const char* name, void* value) { |
g_object_set_data(G_OBJECT(widget_), name, value); |
} |
@@ -785,6 +775,13 @@ |
return false; |
} |
+void WidgetGtk::SendNativeAccessibilityEvent( |
+ View* view, |
+ ui::AccessibilityTypes::Event event_type) { |
+ // In the future if we add native GTK accessibility support, the |
+ // notification should be sent here. |
+} |
+ |
void WidgetGtk::SetMouseCapture() { |
DCHECK(!HasMouseCapture()); |
gtk_grab_add(window_contents_); |
@@ -801,6 +798,18 @@ |
return GTK_WIDGET_HAS_GRAB(window_contents_); |
} |
+bool WidgetGtk::IsMouseButtonDown() const { |
+ bool button_pressed = false; |
+ GdkEvent* event = gtk_get_current_event(); |
+ if (event) { |
+ button_pressed = event->type == GDK_BUTTON_PRESS || |
+ event->type == GDK_2BUTTON_PRESS || |
+ event->type == GDK_3BUTTON_PRESS; |
+ gdk_event_free(event); |
+ } |
+ return button_pressed; |
+} |
+ |
InputMethod* WidgetGtk::GetInputMethodNative() { |
return input_method_.get(); |
} |
@@ -1018,7 +1027,7 @@ |
// preferred size for these would prevents us from setting smaller window |
// sizes. |
if (child_) { |
- gfx::Size size(GetRootView()->GetPreferredSize()); |
+ gfx::Size size(GetWidget()->GetRootView()->GetPreferredSize()); |
requisition->width = size.width(); |
requisition->height = size.height(); |
} |
@@ -1153,7 +1162,7 @@ |
gint y, |
guint time) { |
if (!drop_target_.get()) |
- drop_target_.reset(new DropTargetGtk(GetRootView(), context)); |
+ drop_target_.reset(new DropTargetGtk(GetWidget()->GetRootView(), context)); |
return drop_target_->OnDragMotion(context, x, y, time); |
} |
@@ -1164,7 +1173,8 @@ |
return false; |
} |
- if (!last_mouse_event_was_move_ && !is_mouse_button_pressed_) { |
+ if (!GetWidget()->last_mouse_event_was_move_ && |
+ !GetWidget()->is_mouse_button_pressed_) { |
// When a mouse button is pressed gtk generates a leave, enter, press. |
// RootView expects to get a mouse move before a press, otherwise enter is |
// not set. So we generate a move here. |
@@ -1180,13 +1190,13 @@ |
MouseEvent mouse_event(TransformEvent(&motion)); |
delegate_->OnMouseEvent(mouse_event); |
} |
- |
return false; |
} |
gboolean WidgetGtk::OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event) { |
- last_mouse_event_was_move_ = false; |
- if (!HasMouseCapture() && !is_mouse_button_pressed_) { |
+ GetWidget()->ResetLastMouseMoveFlag(); |
+ |
+ if (!HasMouseCapture() && !GetWidget()->is_mouse_button_pressed_) { |
MouseEvent mouse_event(TransformEvent(event)); |
delegate_->OnMouseEvent(mouse_event); |
} |
@@ -1346,10 +1356,6 @@ |
//////////////////////////////////////////////////////////////////////////////// |
// WidgetGtk, private: |
-RootView* WidgetGtk::CreateRootView() { |
- return new RootView(this); |
-} |
- |
gfx::AcceleratedWidget WidgetGtk::GetAcceleratedWidget() { |
DCHECK(window_contents_ && window_contents_->window); |
return GDK_WINDOW_XID(window_contents_->window); |
@@ -1392,28 +1398,24 @@ |
gtk_bindings_activate_event(GTK_OBJECT(widget_), event); |
} |
-void WidgetGtk::SetInitParams(const InitParams& params) { |
+void WidgetGtk::SetInitParams(const Widget::InitParams& params) { |
DCHECK(!GetNativeView()); |
delete_on_destroy_ = params.delete_on_destroy; |
child_ = params.child; |
+ // TODO(beng): The secondary checks here actually obviate the need for |
+ // params.transient but that's only because WidgetGtk considers |
+ // any top-level widget to be a transient widget. We will probably |
+ // want to ammend this assumption at some point. |
+ if (params.transient || params.parent || params.parent_widget) |
+ transient_to_parent_ = true; |
if (params.transparent) |
MakeTransparent(); |
if (!params.accept_events && !child_) |
ignore_events_ = true; |
if (params.double_buffer) |
EnableDoubleBuffer(true); |
- |
- if (params.type == InitParams::TYPE_MENU) { |
- GdkEvent* event = gtk_get_current_event(); |
- if (event) { |
- is_mouse_button_pressed_ = event->type == GDK_BUTTON_PRESS || |
- event->type == GDK_2BUTTON_PRESS || |
- event->type == GDK_3BUTTON_PRESS; |
- gdk_event_free(event); |
- } |
- } |
} |
gboolean WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { |
@@ -1460,13 +1462,13 @@ |
WidgetGtk* widget_gtk = static_cast<WidgetGtk*>( |
NativeWidget::GetNativeWidgetForNativeView(parent)); |
if (widget_gtk && widget_gtk->is_window_) |
- return static_cast<WindowGtk*>(widget_gtk); |
+ return static_cast<WindowGtk*>(widget_gtk)->GetWindow(); |
parent = gtk_widget_get_parent(parent); |
} |
return NULL; |
} |
-void WidgetGtk::CreateGtkWidget(const InitParams& params) { |
+void WidgetGtk::CreateGtkWidget(const Widget::InitParams& params) { |
// We turn off double buffering for two reasons: |
// 1. We draw to a canvas then composite to the screen, which means we're |
// doing our own double buffering already. |
@@ -1520,8 +1522,8 @@ |
} else { |
// Use our own window class to override GtkWindow's move_focus method. |
widget_ = gtk_views_window_new( |
- params.type == InitParams::TYPE_WINDOW ? GTK_WINDOW_TOPLEVEL |
- : GTK_WINDOW_POPUP); |
+ params.type == Widget::InitParams::TYPE_WINDOW ? GTK_WINDOW_TOPLEVEL |
+ : GTK_WINDOW_POPUP); |
gtk_widget_set_name(widget_, "views-gtkwidget-window"); |
if (transient_to_parent_) { |
gtk_window_set_transient_for(GTK_WINDOW(widget_), |
@@ -1560,7 +1562,7 @@ |
gtk_container_add(GTK_CONTAINER(widget_), window_contents_); |
gtk_widget_show(window_contents_); |
g_object_set_data(G_OBJECT(window_contents_), kNativeWidgetKey, |
- static_cast<Widget*>(this)); |
+ static_cast<WidgetGtk*>(this)); |
if (transparent_) |
ConfigureWidgetForTransparentBackground(NULL); |
@@ -1643,11 +1645,6 @@ |
// Widget, public: |
// static |
-Widget* Widget::CreateWidget() { |
- return new WidgetGtk(); |
-} |
- |
-// static |
void Widget::NotifyLocaleChanged() { |
GList *window_list = gtk_window_list_toplevels(); |
for (GList* element = window_list; element; element = g_list_next(element)) { |
@@ -1660,6 +1657,22 @@ |
} |
// static |
+void Widget::CloseAllSecondaryWidgets() { |
+ GList* windows = gtk_window_list_toplevels(); |
+ for (GList* window = windows; window; |
+ window = g_list_next(window)) { |
+ NativeWidget* native_widget = NativeWidget::GetNativeWidgetForNativeView( |
+ GTK_WIDGET(window->data)); |
+ if (native_widget) { |
+ Widget* widget = native_widget->GetWidget(); |
+ if (widget->is_secondary_widget()) |
+ widget->Close(); |
+ } |
+ } |
+ g_list_free(windows); |
+} |
+ |
+// static |
bool Widget::ConvertRect(const Widget* source, |
const Widget* target, |
gfx::Rect* rect) { |
@@ -1689,6 +1702,12 @@ |
// NativeWidget, public: |
// static |
+NativeWidget* NativeWidget::CreateNativeWidget( |
+ internal::NativeWidgetDelegate* delegate) { |
+ return new WidgetGtk(delegate); |
+} |
+ |
+// static |
NativeWidget* NativeWidget::GetNativeWidgetForNativeView( |
gfx::NativeView native_view) { |
if (!native_view) |
@@ -1740,4 +1759,40 @@ |
reinterpret_cast<gpointer>(children)); |
} |
+// static |
+void NativeWidget::ReparentNativeView(gfx::NativeView native_view, |
+ gfx::NativeView new_parent) { |
+ if (!native_view) |
+ return; |
+ |
+ gfx::NativeView previous_parent = gtk_widget_get_parent(native_view); |
+ if (previous_parent == new_parent) |
+ return; |
+ |
+ NativeWidgets widgets; |
+ GetAllNativeWidgets(native_view, &widgets); |
+ |
+ // First notify all the widgets that they are being disassociated |
+ // from their previous parent. |
+ for (NativeWidgets::iterator it = widgets.begin(); |
+ it != widgets.end(); ++it) { |
+ // TODO(beng): Rename this notification to NotifyNativeViewChanging() |
+ // and eliminate the bool parameter. |
+ (*it)->GetWidget()->NotifyNativeViewHierarchyChanged(false, |
+ previous_parent); |
+ } |
+ |
+ if (gtk_widget_get_parent(native_view)) |
+ gtk_widget_reparent(native_view, new_parent); |
+ else |
+ gtk_container_add(GTK_CONTAINER(new_parent), native_view); |
+ |
+ // And now, notify them that they have a brand new parent. |
+ for (NativeWidgets::iterator it = widgets.begin(); |
+ it != widgets.end(); ++it) { |
+ (*it)->GetWidget()->NotifyNativeViewHierarchyChanged(true, |
+ new_parent); |
+ } |
+} |
+ |
} // namespace views |