| Index: views/widget/native_widget_gtk.cc
|
| ===================================================================
|
| --- views/widget/native_widget_gtk.cc (revision 88529)
|
| +++ views/widget/native_widget_gtk.cc (working copy)
|
| @@ -25,6 +25,7 @@
|
| #include "ui/base/gtk/scoped_handle_gtk.h"
|
| #include "ui/base/x/x11_util.h"
|
| #include "ui/gfx/canvas_skia_paint.h"
|
| +#include "ui/gfx/gtk_util.h"
|
| #include "ui/gfx/path.h"
|
| #include "views/controls/textfield/native_textfield_views.h"
|
| #include "views/focus/view_storage.h"
|
| @@ -36,6 +37,7 @@
|
| #include "views/widget/gtk_views_window.h"
|
| #include "views/widget/tooltip_manager_gtk.h"
|
| #include "views/widget/widget_delegate.h"
|
| +#include "views/window/hit_test.h"
|
| #include "views/window/native_window_gtk.h"
|
|
|
| #if defined(TOUCH_UI)
|
| @@ -192,6 +194,61 @@
|
| return GTK_WINDOW_TOPLEVEL;
|
| }
|
|
|
| +// Converts a Windows-style hit test result code into a GDK window edge.
|
| +GdkWindowEdge HitTestCodeToGDKWindowEdge(int hittest_code) {
|
| + switch (hittest_code) {
|
| + case HTBOTTOM:
|
| + return GDK_WINDOW_EDGE_SOUTH;
|
| + case HTBOTTOMLEFT:
|
| + return GDK_WINDOW_EDGE_SOUTH_WEST;
|
| + case HTBOTTOMRIGHT:
|
| + case HTGROWBOX:
|
| + return GDK_WINDOW_EDGE_SOUTH_EAST;
|
| + case HTLEFT:
|
| + return GDK_WINDOW_EDGE_WEST;
|
| + case HTRIGHT:
|
| + return GDK_WINDOW_EDGE_EAST;
|
| + case HTTOP:
|
| + return GDK_WINDOW_EDGE_NORTH;
|
| + case HTTOPLEFT:
|
| + return GDK_WINDOW_EDGE_NORTH_WEST;
|
| + case HTTOPRIGHT:
|
| + return GDK_WINDOW_EDGE_NORTH_EAST;
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + // Default to something defaultish.
|
| + return HitTestCodeToGDKWindowEdge(HTGROWBOX);
|
| +}
|
| +
|
| +// Converts a Windows-style hit test result code into a GDK cursor type.
|
| +GdkCursorType HitTestCodeToGdkCursorType(int hittest_code) {
|
| + switch (hittest_code) {
|
| + case HTBOTTOM:
|
| + return GDK_BOTTOM_SIDE;
|
| + case HTBOTTOMLEFT:
|
| + return GDK_BOTTOM_LEFT_CORNER;
|
| + case HTBOTTOMRIGHT:
|
| + case HTGROWBOX:
|
| + return GDK_BOTTOM_RIGHT_CORNER;
|
| + case HTLEFT:
|
| + return GDK_LEFT_SIDE;
|
| + case HTRIGHT:
|
| + return GDK_RIGHT_SIDE;
|
| + case HTTOP:
|
| + return GDK_TOP_SIDE;
|
| + case HTTOPLEFT:
|
| + return GDK_TOP_LEFT_CORNER;
|
| + case HTTOPRIGHT:
|
| + return GDK_TOP_RIGHT_CORNER;
|
| + default:
|
| + break;
|
| + }
|
| + // Default to something defaultish.
|
| + return GDK_LEFT_PTR;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // During drag and drop GTK sends a drag-leave during a drop. This means we
|
| @@ -702,6 +759,8 @@
|
| G_CALLBACK(&OnMapThunk), this);
|
| g_signal_connect(widget_, "hide",
|
| G_CALLBACK(&OnHideThunk), this);
|
| + g_signal_connect(widget_, "configure-event",
|
| + G_CALLBACK(&OnConfigureEventThunk), this);
|
|
|
| // Views/FocusManager (re)sets the focus to the root window,
|
| // so we need to connect signal handlers to the gtk window.
|
| @@ -914,6 +973,10 @@
|
| void NativeWidgetGtk::SetAccessibleState(ui::AccessibilityTypes::State state) {
|
| }
|
|
|
| +void NativeWidgetGtk::BecomeModal() {
|
| + gtk_window_set_modal(GetNativeWindow(), true);
|
| +}
|
| +
|
| gfx::Rect NativeWidgetGtk::GetWindowScreenBounds() const {
|
| // Client == Window bounds on Gtk.
|
| return GetClientAreaScreenBounds();
|
| @@ -1207,6 +1270,20 @@
|
| return;
|
| size_ = new_size;
|
| delegate_->OnNativeWidgetSizeChanged(size_);
|
| +
|
| + if (GetWidget()->non_client_view()) {
|
| + // The Window's NonClientView may provide a custom shape for the Window.
|
| + gfx::Path window_mask;
|
| + GetWidget()->non_client_view()->GetWindowMask(gfx::Size(allocation->width,
|
| + allocation->height),
|
| + &window_mask);
|
| + GdkRegion* mask_region = window_mask.CreateNativeRegion();
|
| + gdk_window_shape_combine_region(GetNativeView()->window, mask_region, 0, 0);
|
| + if (mask_region)
|
| + gdk_region_destroy(mask_region);
|
| +
|
| + SaveWindowPosition();
|
| + }
|
| }
|
|
|
| gboolean NativeWidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) {
|
| @@ -1349,6 +1426,8 @@
|
|
|
| gboolean NativeWidgetGtk::OnLeaveNotify(GtkWidget* widget,
|
| GdkEventCrossing* event) {
|
| + gdk_window_set_cursor(widget->window, gfx::GetCursor(GDK_LEFT_PTR));
|
| +
|
| GetWidget()->ResetLastMouseMoveFlag();
|
|
|
| if (!HasMouseCapture() && !GetWidget()->is_mouse_button_pressed_) {
|
| @@ -1360,6 +1439,20 @@
|
|
|
| gboolean NativeWidgetGtk::OnMotionNotify(GtkWidget* widget,
|
| GdkEventMotion* event) {
|
| + if (GetWidget()->non_client_view()) {
|
| + GdkEventMotion transformed_event = *event;
|
| + TransformEvent(&transformed_event);
|
| + gfx::Point translated_location(transformed_event.x, transformed_event.y);
|
| +
|
| + // Update the cursor for the screen edge.
|
| + int hittest_code =
|
| + GetWidget()->non_client_view()->NonClientHitTest(translated_location);
|
| + if (hittest_code != HTCLIENT) {
|
| + GdkCursorType cursor_type = HitTestCodeToGdkCursorType(hittest_code);
|
| + gdk_window_set_cursor(widget->window, gfx::GetCursor(cursor_type));
|
| + }
|
| + }
|
| +
|
| MouseEvent mouse_event(TransformEvent(event));
|
| delegate_->OnMouseEvent(mouse_event);
|
| return true;
|
| @@ -1367,6 +1460,55 @@
|
|
|
| gboolean NativeWidgetGtk::OnButtonPress(GtkWidget* widget,
|
| GdkEventButton* event) {
|
| + if (GetWidget()->non_client_view()) {
|
| + GdkEventButton transformed_event = *event;
|
| + MouseEvent mouse_event(TransformEvent(&transformed_event));
|
| +
|
| + int hittest_code = GetWidget()->non_client_view()->NonClientHitTest(
|
| + mouse_event.location());
|
| + switch (hittest_code) {
|
| + case HTCAPTION: {
|
| + // Start dragging if the mouse event is a single click and *not* a right
|
| + // click. If it is a right click, then pass it through to
|
| + // NativeWidgetGtk::OnButtonPress so that View class can show
|
| + // ContextMenu upon a mouse release event. We only start drag on single
|
| + // clicks as we get a crash in Gtk on double/triple clicks.
|
| + if (event->type == GDK_BUTTON_PRESS &&
|
| + !mouse_event.IsOnlyRightMouseButton()) {
|
| + gfx::Point screen_point(event->x, event->y);
|
| + View::ConvertPointToScreen(GetWidget()->GetRootView(), &screen_point);
|
| + gtk_window_begin_move_drag(GetNativeWindow(), event->button,
|
| + screen_point.x(), screen_point.y(),
|
| + event->time);
|
| + return TRUE;
|
| + }
|
| + break;
|
| + }
|
| + case HTBOTTOM:
|
| + case HTBOTTOMLEFT:
|
| + case HTBOTTOMRIGHT:
|
| + case HTGROWBOX:
|
| + case HTLEFT:
|
| + case HTRIGHT:
|
| + case HTTOP:
|
| + case HTTOPLEFT:
|
| + case HTTOPRIGHT: {
|
| + gfx::Point screen_point(event->x, event->y);
|
| + View::ConvertPointToScreen(GetWidget()->GetRootView(), &screen_point);
|
| + // TODO(beng): figure out how to get a good minimum size.
|
| + gtk_widget_set_size_request(GetNativeView(), 100, 100);
|
| + gtk_window_begin_resize_drag(GetNativeWindow(),
|
| + HitTestCodeToGDKWindowEdge(hittest_code),
|
| + event->button, screen_point.x(),
|
| + screen_point.y(), event->time);
|
| + return TRUE;
|
| + }
|
| + default:
|
| + // Everything else falls into standard client event handling...
|
| + break;
|
| + }
|
| + }
|
| +
|
| if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) {
|
| // The sequence for double clicks is press, release, press, 2press, release.
|
| // This means that at the time we get the second 'press' we don't know
|
| @@ -1508,10 +1650,20 @@
|
|
|
| gboolean NativeWidgetGtk::OnWindowStateEvent(GtkWidget* widget,
|
| GdkEventWindowState* event) {
|
| + if (GetWidget()->non_client_view() &&
|
| + !(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) {
|
| + SaveWindowPosition();
|
| + }
|
| window_state_ = event->new_window_state;
|
| return FALSE;
|
| }
|
|
|
| +gboolean NativeWidgetGtk::OnConfigureEvent(GtkWidget* widget,
|
| + GdkEventConfigure* event) {
|
| + SaveWindowPosition();
|
| + return FALSE;
|
| +}
|
| +
|
| void NativeWidgetGtk::HandleXGrabBroke() {
|
| }
|
|
|
| @@ -1807,6 +1959,17 @@
|
| cairo_destroy(cr);
|
| }
|
|
|
| +void NativeWidgetGtk::SaveWindowPosition() {
|
| + // The delegate may have gone away on us.
|
| + if (!GetWidget()->widget_delegate())
|
| + return;
|
| +
|
| + bool maximized = window_state_ & GDK_WINDOW_STATE_MAXIMIZED;
|
| + GetWidget()->widget_delegate()->SaveWindowPlacement(
|
| + GetWidget()->GetWindowScreenBounds(),
|
| + maximized);
|
| +}
|
| +
|
| ////////////////////////////////////////////////////////////////////////////////
|
| // Widget, public:
|
|
|
|
|