Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3199)

Unified Diff: chrome/browser/ui/gtk/bubble/bubble_gtk.cc

Issue 231733005: Delete the GTK+ port of Chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remerge to ToT Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/gtk/bubble/bubble_gtk.cc
diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc
deleted file mode 100644
index 17caa7fab9cd0656eb9d3a4b97877fd72626b7f3..0000000000000000000000000000000000000000
--- a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc
+++ /dev/null
@@ -1,798 +0,0 @@
-// Copyright (c) 2012 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 "chrome/browser/ui/gtk/bubble/bubble_gtk.h"
-
-#include <gdk/gdkkeysyms.h>
-
-#include "base/bind.h"
-#include "base/i18n/rtl.h"
-#include "base/message_loop/message_loop.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.h"
-#include "chrome/browser/ui/gtk/gtk_theme_service.h"
-#include "chrome/browser/ui/gtk/gtk_util.h"
-#include "content/public/browser/notification_source.h"
-#include "ui/base/gtk/gtk_hig_constants.h"
-#include "ui/base/gtk/gtk_windowing.h"
-#include "ui/gfx/gtk_compat.h"
-#include "ui/gfx/gtk_util.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/rect.h"
-
-namespace {
-
-// The height of the arrow, and the width will be about twice the height.
-const int kArrowSize = 8;
-
-// Number of pixels to the middle of the arrow from the close edge of the
-// window.
-const int kArrowX = 18;
-
-// Number of pixels between the tip of the arrow and the region we're
-// pointing to.
-const int kArrowToContentPadding = -4;
-
-// We draw flat diagonal corners, each corner is an NxN square.
-const int kCornerSize = 3;
-
-// The amount of padding (in pixels) from the top of |toplevel_window_| to the
-// top of |window_| when fixed positioning is used.
-const int kFixedPositionPaddingEnd = 10;
-const int kFixedPositionPaddingTop = 5;
-
-const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff);
-const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63);
-
-// Helper functions that encapsulate arrow locations.
-bool HasArrow(BubbleGtk::FrameStyle frame_style) {
- return frame_style != BubbleGtk::FLOAT_BELOW_RECT &&
- frame_style != BubbleGtk::CENTER_OVER_RECT &&
- frame_style != BubbleGtk::FIXED_TOP_LEFT &&
- frame_style != BubbleGtk::FIXED_TOP_RIGHT;
-}
-
-bool IsArrowLeft(BubbleGtk::FrameStyle frame_style) {
- return frame_style == BubbleGtk::ANCHOR_TOP_LEFT ||
- frame_style == BubbleGtk::ANCHOR_BOTTOM_LEFT;
-}
-
-bool IsArrowMiddle(BubbleGtk::FrameStyle frame_style) {
- return frame_style == BubbleGtk::ANCHOR_TOP_MIDDLE ||
- frame_style == BubbleGtk::ANCHOR_BOTTOM_MIDDLE;
-}
-
-bool IsArrowRight(BubbleGtk::FrameStyle frame_style) {
- return frame_style == BubbleGtk::ANCHOR_TOP_RIGHT ||
- frame_style == BubbleGtk::ANCHOR_BOTTOM_RIGHT;
-}
-
-bool IsArrowTop(BubbleGtk::FrameStyle frame_style) {
- return frame_style == BubbleGtk::ANCHOR_TOP_LEFT ||
- frame_style == BubbleGtk::ANCHOR_TOP_MIDDLE ||
- frame_style == BubbleGtk::ANCHOR_TOP_RIGHT;
-}
-
-bool IsArrowBottom(BubbleGtk::FrameStyle frame_style) {
- return frame_style == BubbleGtk::ANCHOR_BOTTOM_LEFT ||
- frame_style == BubbleGtk::ANCHOR_BOTTOM_MIDDLE ||
- frame_style == BubbleGtk::ANCHOR_BOTTOM_RIGHT;
-}
-
-bool IsFixed(BubbleGtk::FrameStyle frame_style) {
- return frame_style == BubbleGtk::FIXED_TOP_LEFT ||
- frame_style == BubbleGtk::FIXED_TOP_RIGHT;
-}
-
-BubbleGtk::FrameStyle AdjustFrameStyleForLocale(
- BubbleGtk::FrameStyle frame_style) {
- // Only RTL requires more work.
- if (!base::i18n::IsRTL())
- return frame_style;
-
- switch (frame_style) {
- // These don't flip.
- case BubbleGtk::ANCHOR_TOP_MIDDLE:
- case BubbleGtk::ANCHOR_BOTTOM_MIDDLE:
- case BubbleGtk::FLOAT_BELOW_RECT:
- case BubbleGtk::CENTER_OVER_RECT:
- return frame_style;
-
- // These do flip.
- case BubbleGtk::ANCHOR_TOP_LEFT:
- return BubbleGtk::ANCHOR_TOP_RIGHT;
-
- case BubbleGtk::ANCHOR_TOP_RIGHT:
- return BubbleGtk::ANCHOR_TOP_LEFT;
-
- case BubbleGtk::ANCHOR_BOTTOM_LEFT:
- return BubbleGtk::ANCHOR_BOTTOM_RIGHT;
-
- case BubbleGtk::ANCHOR_BOTTOM_RIGHT:
- return BubbleGtk::ANCHOR_BOTTOM_LEFT;
-
- case BubbleGtk::FIXED_TOP_LEFT:
- return BubbleGtk::FIXED_TOP_RIGHT;
-
- case BubbleGtk::FIXED_TOP_RIGHT:
- return BubbleGtk::FIXED_TOP_LEFT;
- }
-
- NOTREACHED();
- return BubbleGtk::ANCHOR_TOP_LEFT;
-}
-
-} // namespace
-
-// static
-BubbleGtk* BubbleGtk::Show(GtkWidget* anchor_widget,
- const gfx::Rect* rect,
- GtkWidget* content,
- FrameStyle frame_style,
- int attribute_flags,
- GtkThemeService* provider,
- BubbleDelegateGtk* delegate) {
- BubbleGtk* bubble = new BubbleGtk(provider,
- AdjustFrameStyleForLocale(frame_style),
- attribute_flags);
- bubble->Init(anchor_widget, rect, content, attribute_flags);
- bubble->set_delegate(delegate);
- return bubble;
-}
-
-BubbleGtk::BubbleGtk(GtkThemeService* provider,
- FrameStyle frame_style,
- int attribute_flags)
- : delegate_(NULL),
- window_(NULL),
- theme_service_(provider),
- accel_group_(gtk_accel_group_new()),
- toplevel_window_(NULL),
- anchor_widget_(NULL),
- mask_region_(NULL),
- requested_frame_style_(frame_style),
- actual_frame_style_(ANCHOR_TOP_LEFT),
- match_system_theme_(attribute_flags & MATCH_SYSTEM_THEME),
- grab_input_(attribute_flags & GRAB_INPUT),
- closed_by_escape_(false),
- weak_ptr_factory_(this) {}
-
-BubbleGtk::~BubbleGtk() {
- // Notify the delegate that we're about to close. This gives the chance
- // to save state / etc from the hosted widget before it's destroyed.
- if (delegate_)
- delegate_->BubbleClosing(this, closed_by_escape_);
-
- g_object_unref(accel_group_);
- if (mask_region_)
- gdk_region_destroy(mask_region_);
-}
-
-void BubbleGtk::Init(GtkWidget* anchor_widget,
- const gfx::Rect* rect,
- GtkWidget* content,
- int attribute_flags) {
- // If there is a current grab widget (menu, other bubble, etc.), hide it.
- GtkWidget* current_grab_widget = gtk_grab_get_current();
- if (current_grab_widget)
- gtk_widget_hide(current_grab_widget);
-
- DCHECK(!window_);
- anchor_widget_ = anchor_widget;
- toplevel_window_ = gtk_widget_get_toplevel(anchor_widget_);
- DCHECK(gtk_widget_is_toplevel(toplevel_window_));
- rect_ = rect ? *rect : gtk_util::WidgetBounds(anchor_widget);
-
- // Using a TOPLEVEL window may cause placement issues with certain WMs but it
- // is necessary to be able to focus the window.
- window_ = gtk_window_new(attribute_flags & POPUP_WINDOW ?
- GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
-
- gtk_widget_set_app_paintable(window_, TRUE);
- // Resizing is handled by the program, not user.
- gtk_window_set_resizable(GTK_WINDOW(window_), FALSE);
-
- if (!(attribute_flags & NO_ACCELERATORS)) {
- // Attach all of the accelerators to the bubble.
- for (BubbleAcceleratorsGtk::const_iterator
- i(BubbleAcceleratorsGtk::begin());
- i != BubbleAcceleratorsGtk::end();
- ++i) {
- gtk_accel_group_connect(accel_group_,
- i->keyval,
- i->modifier_type,
- GtkAccelFlags(0),
- g_cclosure_new(G_CALLBACK(&OnGtkAcceleratorThunk),
- this,
- NULL));
- }
- gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group_);
- }
-
- // |requested_frame_style_| is used instead of |actual_frame_style_| here
- // because |actual_frame_style_| is only correct after calling
- // |UpdateFrameStyle()|. Unfortunately, |UpdateFrameStyle()| requires knowing
- // the size of |window_| (which happens later on).
- int arrow_padding = HasArrow(requested_frame_style_) ? kArrowSize : 0;
- GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
- gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), arrow_padding, 0, 0, 0);
-
- gtk_container_add(GTK_CONTAINER(alignment), content);
- gtk_container_add(GTK_CONTAINER(window_), alignment);
-
- // GtkWidget only exposes the bitmap mask interface. Use GDK to more
- // efficently mask a GdkRegion. Make sure the window is realized during
- // OnSizeAllocate, so the mask can be applied to the GdkWindow.
- gtk_widget_realize(window_);
-
- UpdateFrameStyle(true); // Force move and reshape.
- StackWindow();
-
- gtk_widget_add_events(window_, GDK_BUTTON_PRESS_MASK);
-
- // Connect during the bubbling phase so the border is always on top.
- signals_.ConnectAfter(window_, "expose-event",
- G_CALLBACK(OnExposeThunk), this);
- signals_.Connect(window_, "size-allocate", G_CALLBACK(OnSizeAllocateThunk),
- this);
- signals_.Connect(window_, "button-press-event",
- G_CALLBACK(OnButtonPressThunk), this);
- signals_.Connect(window_, "destroy", G_CALLBACK(OnDestroyThunk), this);
- signals_.Connect(window_, "hide", G_CALLBACK(OnHideThunk), this);
- if (grab_input_) {
- signals_.Connect(window_, "grab-broken-event",
- G_CALLBACK(OnGrabBrokenThunk), this);
- }
-
- signals_.Connect(anchor_widget_, "destroy",
- G_CALLBACK(OnAnchorDestroyThunk), this);
- // If the toplevel window is being used as the anchor, then the signals below
- // are enough to keep us positioned correctly.
- if (anchor_widget_ != toplevel_window_) {
- signals_.Connect(anchor_widget_, "size-allocate",
- G_CALLBACK(OnAnchorAllocateThunk), this);
- }
-
- signals_.Connect(toplevel_window_, "configure-event",
- G_CALLBACK(OnToplevelConfigureThunk), this);
- signals_.Connect(toplevel_window_, "unmap-event",
- G_CALLBACK(OnToplevelUnmapThunk), this);
-
- gtk_widget_show_all(window_);
-
- if (grab_input_)
- gtk_grab_add(window_);
- GrabPointerAndKeyboard();
-
- registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
- content::Source<ThemeService>(theme_service_));
- theme_service_->InitThemesFor(this);
-}
-
-// NOTE: This seems a bit overcomplicated, but it requires a bunch of careful
-// fudging to get the pixels rasterized exactly where we want them, the arrow to
-// have a 1 pixel point, etc.
-// TODO(deanm): Windows draws with Skia and uses some PNG images for the
-// corners. This is a lot more work, but they get anti-aliasing.
-// static
-std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints(
- FrameStyle frame_style,
- int width,
- int height,
- FrameType type) {
- using gtk_util::MakeBidiGdkPoint;
- std::vector<GdkPoint> points;
-
- int top_arrow_size = IsArrowTop(frame_style) ? kArrowSize : 0;
- int bottom_arrow_size = IsArrowBottom(frame_style) ? kArrowSize : 0;
- bool on_left = IsArrowLeft(frame_style);
-
- // If we're stroking the frame, we need to offset some of our points by 1
- // pixel. We do this when we draw horizontal lines that are on the bottom or
- // when we draw vertical lines that are closer to the end (where "end" is the
- // right side for ANCHOR_TOP_LEFT).
- int y_off = type == FRAME_MASK ? 0 : -1;
- // We use this one for arrows located on the left.
- int x_off_l = on_left ? y_off : 0;
- // We use this one for RTL.
- int x_off_r = !on_left ? -y_off : 0;
-
- // Top left corner.
- points.push_back(MakeBidiGdkPoint(
- x_off_r, top_arrow_size + kCornerSize - 1, width, on_left));
- points.push_back(MakeBidiGdkPoint(
- kCornerSize + x_off_r - 1, top_arrow_size, width, on_left));
-
- // The top arrow.
- if (top_arrow_size) {
- int arrow_x = frame_style == ANCHOR_TOP_MIDDLE ? width / 2 : kArrowX;
- points.push_back(MakeBidiGdkPoint(
- arrow_x - top_arrow_size + x_off_r, top_arrow_size, width, on_left));
- points.push_back(MakeBidiGdkPoint(
- arrow_x + x_off_r, 0, width, on_left));
- points.push_back(MakeBidiGdkPoint(
- arrow_x + 1 + x_off_l, 0, width, on_left));
- points.push_back(MakeBidiGdkPoint(
- arrow_x + top_arrow_size + 1 + x_off_l, top_arrow_size,
- width, on_left));
- }
-
- // Top right corner.
- points.push_back(MakeBidiGdkPoint(
- width - kCornerSize + 1 + x_off_l, top_arrow_size, width, on_left));
- points.push_back(MakeBidiGdkPoint(
- width + x_off_l, top_arrow_size + kCornerSize - 1, width, on_left));
-
- // Bottom right corner.
- points.push_back(MakeBidiGdkPoint(
- width + x_off_l, height - bottom_arrow_size - kCornerSize,
- width, on_left));
- points.push_back(MakeBidiGdkPoint(
- width - kCornerSize + x_off_r, height - bottom_arrow_size + y_off,
- width, on_left));
-
- // The bottom arrow.
- if (bottom_arrow_size) {
- int arrow_x = frame_style == ANCHOR_BOTTOM_MIDDLE ?
- width / 2 : kArrowX;
- points.push_back(MakeBidiGdkPoint(
- arrow_x + bottom_arrow_size + 1 + x_off_l,
- height - bottom_arrow_size + y_off,
- width,
- on_left));
- points.push_back(MakeBidiGdkPoint(
- arrow_x + 1 + x_off_l, height + y_off, width, on_left));
- points.push_back(MakeBidiGdkPoint(
- arrow_x + x_off_r, height + y_off, width, on_left));
- points.push_back(MakeBidiGdkPoint(
- arrow_x - bottom_arrow_size + x_off_r,
- height - bottom_arrow_size + y_off,
- width,
- on_left));
- }
-
- // Bottom left corner.
- points.push_back(MakeBidiGdkPoint(
- kCornerSize + x_off_l, height -bottom_arrow_size + y_off,
- width, on_left));
- points.push_back(MakeBidiGdkPoint(
- x_off_r, height - bottom_arrow_size - kCornerSize, width, on_left));
-
- return points;
-}
-
-BubbleGtk::FrameStyle BubbleGtk::GetAllowedFrameStyle(
- FrameStyle preferred_style,
- int arrow_x,
- int arrow_y,
- int width,
- int height) {
- if (IsFixed(preferred_style))
- return preferred_style;
-
- const int screen_width = gdk_screen_get_width(gdk_screen_get_default());
- const int screen_height = gdk_screen_get_height(gdk_screen_get_default());
-
- // Choose whether to show the bubble above or below the specified location.
- const bool prefer_top_arrow = IsArrowTop(preferred_style) ||
- preferred_style == FLOAT_BELOW_RECT;
- // The bleed measures the amount of bubble that would be shown offscreen.
- const int top_arrow_bleed =
- std::max(height + kArrowSize + arrow_y - screen_height, 0);
- const int bottom_arrow_bleed = std::max(height + kArrowSize - arrow_y, 0);
-
- FrameStyle frame_style_none = FLOAT_BELOW_RECT;
- FrameStyle frame_style_left = ANCHOR_TOP_LEFT;
- FrameStyle frame_style_middle = ANCHOR_TOP_MIDDLE;
- FrameStyle frame_style_right = ANCHOR_TOP_RIGHT;
- if ((prefer_top_arrow && (top_arrow_bleed > bottom_arrow_bleed)) ||
- (!prefer_top_arrow && (top_arrow_bleed >= bottom_arrow_bleed))) {
- frame_style_none = CENTER_OVER_RECT;
- frame_style_left = ANCHOR_BOTTOM_LEFT;
- frame_style_middle = ANCHOR_BOTTOM_MIDDLE;
- frame_style_right = ANCHOR_BOTTOM_RIGHT;
- }
-
- if (!HasArrow(preferred_style))
- return frame_style_none;
-
- if (IsArrowMiddle(preferred_style))
- return frame_style_middle;
-
- // Choose whether to show the bubble left or right of the specified location.
- const bool prefer_left_arrow = IsArrowLeft(preferred_style);
- // The bleed measures the amount of bubble that would be shown offscreen.
- const int left_arrow_bleed =
- std::max(width + arrow_x - kArrowX - screen_width, 0);
- const int right_arrow_bleed = std::max(width - arrow_x - kArrowX, 0);
-
- // Use the preferred location if it doesn't bleed more than the opposite side.
- return ((prefer_left_arrow && (left_arrow_bleed <= right_arrow_bleed)) ||
- (!prefer_left_arrow && (left_arrow_bleed < right_arrow_bleed))) ?
- frame_style_left : frame_style_right;
-}
-
-bool BubbleGtk::UpdateFrameStyle(bool force_move_and_reshape) {
- if (!toplevel_window_ || !anchor_widget_)
- return false;
-
- gint toplevel_x = 0, toplevel_y = 0;
- gdk_window_get_position(gtk_widget_get_window(toplevel_window_),
- &toplevel_x, &toplevel_y);
- int offset_x, offset_y;
- gtk_widget_translate_coordinates(anchor_widget_, toplevel_window_,
- rect_.x(), rect_.y(), &offset_x, &offset_y);
-
- FrameStyle old_frame_style = actual_frame_style_;
- GtkAllocation allocation;
- gtk_widget_get_allocation(window_, &allocation);
- actual_frame_style_ = GetAllowedFrameStyle(
- requested_frame_style_,
- toplevel_x + offset_x + (rect_.width() / 2), // arrow_x
- toplevel_y + offset_y,
- allocation.width,
- allocation.height);
-
- if (force_move_and_reshape || actual_frame_style_ != old_frame_style) {
- UpdateWindowShape();
- MoveWindow();
- // We need to redraw the entire window to repaint its border.
- gtk_widget_queue_draw(window_);
- return true;
- }
- return false;
-}
-
-void BubbleGtk::UpdateWindowShape() {
- if (mask_region_) {
- gdk_region_destroy(mask_region_);
- mask_region_ = NULL;
- }
- GtkAllocation allocation;
- gtk_widget_get_allocation(window_, &allocation);
- std::vector<GdkPoint> points = MakeFramePolygonPoints(
- actual_frame_style_, allocation.width, allocation.height,
- FRAME_MASK);
- mask_region_ = gdk_region_polygon(&points[0],
- points.size(),
- GDK_EVEN_ODD_RULE);
-
- GdkWindow* gdk_window = gtk_widget_get_window(window_);
- gdk_window_shape_combine_region(gdk_window, NULL, 0, 0);
- gdk_window_shape_combine_region(gdk_window, mask_region_, 0, 0);
-}
-
-void BubbleGtk::MoveWindow() {
- if (!toplevel_window_ || !anchor_widget_)
- return;
-
- gint toplevel_x = 0, toplevel_y = 0;
- gdk_window_get_position(gtk_widget_get_window(toplevel_window_),
- &toplevel_x, &toplevel_y);
-
- int offset_x, offset_y;
- gtk_widget_translate_coordinates(anchor_widget_, toplevel_window_,
- rect_.x(), rect_.y(), &offset_x, &offset_y);
-
- gint screen_x = 0;
- if (IsFixed(actual_frame_style_)) {
- GtkAllocation toplevel_allocation;
- gtk_widget_get_allocation(toplevel_window_, &toplevel_allocation);
-
- GtkAllocation bubble_allocation;
- gtk_widget_get_allocation(window_, &bubble_allocation);
-
- int x_offset = actual_frame_style_ == FIXED_TOP_LEFT ?
- kFixedPositionPaddingEnd :
- toplevel_allocation.width - bubble_allocation.width -
- kFixedPositionPaddingEnd;
- screen_x = toplevel_x + x_offset;
- } else if (!HasArrow(actual_frame_style_) ||
- IsArrowMiddle(actual_frame_style_)) {
- GtkAllocation allocation;
- gtk_widget_get_allocation(window_, &allocation);
- screen_x =
- toplevel_x + offset_x + (rect_.width() / 2) - allocation.width / 2;
- } else if (IsArrowLeft(actual_frame_style_)) {
- screen_x = toplevel_x + offset_x + (rect_.width() / 2) - kArrowX;
- } else if (IsArrowRight(actual_frame_style_)) {
- GtkAllocation allocation;
- gtk_widget_get_allocation(window_, &allocation);
- screen_x = toplevel_x + offset_x + (rect_.width() / 2) -
- allocation.width + kArrowX;
- } else {
- NOTREACHED();
- }
-
- gint screen_y = toplevel_y + offset_y + rect_.height();
- if (IsFixed(actual_frame_style_)) {
- screen_y = toplevel_y + kFixedPositionPaddingTop;
- } else if (IsArrowTop(actual_frame_style_) ||
- actual_frame_style_ == FLOAT_BELOW_RECT) {
- screen_y += kArrowToContentPadding;
- } else {
- GtkAllocation allocation;
- gtk_widget_get_allocation(window_, &allocation);
- screen_y -= allocation.height + kArrowToContentPadding;
- }
-
- gtk_window_move(GTK_WINDOW(window_), screen_x, screen_y);
-}
-
-void BubbleGtk::StackWindow() {
- // Stack our window directly above the toplevel window.
- if (toplevel_window_)
- ui::StackPopupWindow(window_, toplevel_window_);
-}
-
-void BubbleGtk::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK_EQ(type, chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
- if (theme_service_->UsingNativeTheme() && match_system_theme_) {
- gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, NULL);
- } else {
- // Set the background color, so we don't need to paint it manually.
- gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &kBackgroundColor);
- }
-}
-
-void BubbleGtk::StopGrabbingInput() {
- UngrabPointerAndKeyboard();
- if (!grab_input_)
- return;
- grab_input_ = false;
- gtk_grab_remove(window_);
-}
-
-GtkWindow* BubbleGtk::GetNativeWindow() {
- return GTK_WINDOW(window_);
-}
-
-void BubbleGtk::Close() {
- // We don't need to ungrab the pointer or keyboard here; the X server will
- // automatically do that when we destroy our window.
- DCHECK(window_);
- gtk_widget_destroy(window_);
- // |this| has been deleted, see OnDestroy.
-}
-
-void BubbleGtk::SetPositionRelativeToAnchor(const gfx::Rect* rect) {
- rect_ = rect ? *rect : gtk_util::WidgetBounds(anchor_widget_);
- if (!UpdateFrameStyle(false))
- MoveWindow();
-}
-
-void BubbleGtk::GrabPointerAndKeyboard() {
- GdkWindow* gdk_window = gtk_widget_get_window(window_);
-
- // Install X pointer and keyboard grabs to make sure that we have the focus
- // and get all mouse and keyboard events until we're closed. As a hack, grab
- // the pointer even if |grab_input_| is false to prevent a weird error
- // rendering the bubble's frame. See
- // https://code.google.com/p/chromium/issues/detail?id=130820.
- GdkGrabStatus pointer_grab_status =
- gdk_pointer_grab(gdk_window,
- TRUE, // owner_events
- GDK_BUTTON_PRESS_MASK, // event_mask
- NULL, // confine_to
- NULL, // cursor
- GDK_CURRENT_TIME);
- if (pointer_grab_status != GDK_GRAB_SUCCESS) {
- // This will fail if someone else already has the pointer grabbed, but
- // there's not really anything we can do about that.
- DLOG(ERROR) << "Unable to grab pointer (status="
- << pointer_grab_status << ")";
- }
-
- // Only grab the keyboard input if |grab_input_| is true.
- if (grab_input_) {
- GdkGrabStatus keyboard_grab_status =
- gdk_keyboard_grab(gdk_window,
- FALSE, // owner_events
- GDK_CURRENT_TIME);
- if (keyboard_grab_status != GDK_GRAB_SUCCESS) {
- DLOG(ERROR) << "Unable to grab keyboard (status="
- << keyboard_grab_status << ")";
- }
- }
-}
-
-void BubbleGtk::UngrabPointerAndKeyboard() {
- gdk_pointer_ungrab(GDK_CURRENT_TIME);
- if (grab_input_)
- gdk_keyboard_ungrab(GDK_CURRENT_TIME);
-}
-
-gboolean BubbleGtk::OnGtkAccelerator(GtkAccelGroup* group,
- GObject* acceleratable,
- guint keyval,
- GdkModifierType modifier) {
- GdkEventKey msg;
- GdkKeymapKey* keys;
- gint n_keys;
-
- switch (keyval) {
- case GDK_Escape:
- // Close on Esc and trap the accelerator
- closed_by_escape_ = true;
- Close();
- return TRUE;
- case GDK_w:
- // Close on C-w and forward the accelerator
- if (modifier & GDK_CONTROL_MASK) {
- gdk_keymap_get_entries_for_keyval(NULL,
- keyval,
- &keys,
- &n_keys);
- if (n_keys) {
- // Forward the accelerator to root window the bubble is anchored
- // to for further processing
- msg.type = GDK_KEY_PRESS;
- msg.window = gtk_widget_get_window(toplevel_window_);
- msg.send_event = TRUE;
- msg.time = GDK_CURRENT_TIME;
- msg.state = modifier | GDK_MOD2_MASK;
- msg.keyval = keyval;
- // length and string are deprecated and thus zeroed out
- msg.length = 0;
- msg.string = NULL;
- msg.hardware_keycode = keys[0].keycode;
- msg.group = keys[0].group;
- msg.is_modifier = 0;
-
- g_free(keys);
-
- gtk_main_do_event(reinterpret_cast<GdkEvent*>(&msg));
- } else {
- // This means that there isn't a h/w code for the keyval in the
- // current keymap, which is weird but possible if the keymap just
- // changed. This isn't a critical error, but might be indicative
- // of something off if it happens regularly.
- DLOG(WARNING) << "Found no keys for value " << keyval;
- }
- Close();
- }
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-gboolean BubbleGtk::OnExpose(GtkWidget* widget, GdkEventExpose* expose) {
- // TODO(erg): This whole method will need to be rewritten in cairo.
- GdkDrawable* drawable = GDK_DRAWABLE(gtk_widget_get_window(window_));
- GdkGC* gc = gdk_gc_new(drawable);
- gdk_gc_set_rgb_fg_color(gc, &kFrameColor);
-
- // Stroke the frame border.
- GtkAllocation allocation;
- gtk_widget_get_allocation(window_, &allocation);
- std::vector<GdkPoint> points = MakeFramePolygonPoints(
- actual_frame_style_, allocation.width, allocation.height,
- FRAME_STROKE);
- gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size());
-
- // If |grab_input_| is false, pointer input has been grabbed as a hack in
- // |GrabPointerAndKeyboard()| to ensure that the polygon frame is drawn
- // correctly. Since the intention is not actually to grab the pointer, release
- // it now that the frame is drawn to prevent clicks from being missed. See
- // https://code.google.com/p/chromium/issues/detail?id=130820.
- if (!grab_input_)
- gdk_pointer_ungrab(GDK_CURRENT_TIME);
-
- g_object_unref(gc);
- return FALSE; // Propagate so our children paint, etc.
-}
-
-// When our size is initially allocated or changed, we need to recompute
-// and apply our shape mask region.
-void BubbleGtk::OnSizeAllocate(GtkWidget* widget,
- GtkAllocation* allocation) {
- if (!UpdateFrameStyle(false)) {
- UpdateWindowShape();
- MoveWindow();
- }
-}
-
-gboolean BubbleGtk::OnButtonPress(GtkWidget* widget,
- GdkEventButton* event) {
- // If we got a click in our own window, that's okay (we need to additionally
- // check that it falls within our bounds, since we've grabbed the pointer and
- // some events that actually occurred in other windows will be reported with
- // respect to our window).
- GdkWindow* gdk_window = gtk_widget_get_window(window_);
- if (event->window == gdk_window &&
- (mask_region_ && gdk_region_point_in(mask_region_, event->x, event->y))) {
- return FALSE; // Propagate.
- }
-
- // Our content widget got a click.
- if (event->window != gdk_window &&
- gdk_window_get_toplevel(event->window) == gdk_window) {
- return FALSE;
- }
-
- if (grab_input_) {
- // Otherwise we had a click outside of our window, close ourself.
- Close();
- return TRUE;
- }
-
- return FALSE;
-}
-
-gboolean BubbleGtk::OnDestroy(GtkWidget* widget) {
- // We are self deleting, we have a destroy signal setup to catch when we
- // destroy the widget manually, or the window was closed via X. This will
- // delete the BubbleGtk object.
- delete this;
- return FALSE; // Propagate.
-}
-
-void BubbleGtk::OnHide(GtkWidget* widget) {
- gtk_widget_destroy(widget);
-}
-
-gboolean BubbleGtk::OnGrabBroken(GtkWidget* widget,
- GdkEventGrabBroken* grab_broken) {
- // |grab_input_| may have been changed to false.
- if (!grab_input_)
- return FALSE;
-
- // |grab_window| can be NULL.
- if (!grab_broken->grab_window)
- return FALSE;
-
- gpointer user_data;
- gdk_window_get_user_data(grab_broken->grab_window, &user_data);
-
- if (GTK_IS_WIDGET(user_data)) {
- signals_.Connect(GTK_WIDGET(user_data), "hide",
- G_CALLBACK(OnForeshadowWidgetHideThunk), this);
- }
-
- return FALSE;
-}
-
-void BubbleGtk::OnForeshadowWidgetHide(GtkWidget* widget) {
- if (grab_input_)
- GrabPointerAndKeyboard();
-
- signals_.DisconnectAll(widget);
-}
-
-gboolean BubbleGtk::OnToplevelConfigure(GtkWidget* widget,
- GdkEventConfigure* event) {
- if (!UpdateFrameStyle(false))
- MoveWindow();
- StackWindow();
- return FALSE;
-}
-
-gboolean BubbleGtk::OnToplevelUnmap(GtkWidget* widget, GdkEvent* event) {
- Close();
- return FALSE;
-}
-
-void BubbleGtk::OnAnchorAllocate(GtkWidget* widget,
- GtkAllocation* allocation) {
- if (!UpdateFrameStyle(false))
- MoveWindow();
-}
-
-void BubbleGtk::OnAnchorDestroy(GtkWidget* widget) {
- anchor_widget_ = NULL;
-
- // Ctrl-W will first destroy the anchor, then call |this| back via
- // |accel_group_|. So that the callback |this| registered via |accel_group_|
- // doesn't run after |this| is destroyed, we delay this close (which, unlike
- // the accelerator callback, will be cancelled if |this| is destroyed).
- // http://crbug.com/286621
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&BubbleGtk::Close, weak_ptr_factory_.GetWeakPtr()));
-}

Powered by Google App Engine
This is Rietveld 408576698