diff options
-rw-r--r-- | chrome/browser/gtk/bookmark_bubble_gtk.cc | 26 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_bubble_gtk.h | 26 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_window_gtk.cc | 2 | ||||
-rw-r--r-- | chrome/browser/gtk/info_bubble_gtk.cc | 208 | ||||
-rw-r--r-- | chrome/browser/gtk/info_bubble_gtk.h | 72 | ||||
-rw-r--r-- | chrome/browser/gtk/toolbar_star_toggle_gtk.cc | 18 | ||||
-rw-r--r-- | chrome/chrome.gyp | 8 |
7 files changed, 357 insertions, 3 deletions
diff --git a/chrome/browser/gtk/bookmark_bubble_gtk.cc b/chrome/browser/gtk/bookmark_bubble_gtk.cc new file mode 100644 index 0000000..3ea2197 --- /dev/null +++ b/chrome/browser/gtk/bookmark_bubble_gtk.cc @@ -0,0 +1,26 @@ +// 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 "chrome/browser/gtk/bookmark_bubble_gtk.h" + +#include <gtk/gtk.h> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "chrome/browser/gtk/info_bubble_gtk.h" + +// static +void BookmarkBubbleGtk::Show(const gfx::Rect& rect, + Profile* profile, + const GURL& url, + bool newly_bookmarked) { + // TODO(deanm): Implement the real bookmark bubble. For now we just have + // a placeholder for testing that input and focus works correctly. + GtkWidget* content = gtk_vbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(content), gtk_label_new("Hej!"), TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(content), gtk_entry_new(), TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(content), gtk_entry_new(), TRUE, TRUE, 0); + InfoBubbleGtk* bubble = InfoBubbleGtk::Show(rect, content); + DCHECK(bubble); +} diff --git a/chrome/browser/gtk/bookmark_bubble_gtk.h b/chrome/browser/gtk/bookmark_bubble_gtk.h new file mode 100644 index 0000000..f456ba1 --- /dev/null +++ b/chrome/browser/gtk/bookmark_bubble_gtk.h @@ -0,0 +1,26 @@ +// 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 CHROME_BROWSER_GTK_BOOKMARK_BUBBLE_GTK_H_ +#define CHROME_BROWSER_GTK_BOOKMARK_BUBBLE_GTK_H_ + +#include "base/basictypes.h" +#include "googleurl/src/gurl.h" + +typedef struct _GtkWidget GtkWidget; + +class Profile; +namespace gfx { +class Rect; +} + +class BookmarkBubbleGtk { + public: + static void Show(const gfx::Rect& rect, + Profile* profile, + const GURL& url, + bool newly_bookmarked); +}; + +#endif // CHROME_BROWSER_GTK_BOOKMARK_BUBBLE_GTK_H_ diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index 8500a17..ee1d1e1 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -487,7 +487,7 @@ void BrowserWindowGtk::ShowBookmarkManager() { void BrowserWindowGtk::ShowBookmarkBubble(const GURL& url, bool already_bookmarked) { - NOTIMPLEMENTED(); + toolbar_->star()->ShowStarBubble(url, !already_bookmarked); } void BrowserWindowGtk::ShowReportBugDialog() { diff --git a/chrome/browser/gtk/info_bubble_gtk.cc b/chrome/browser/gtk/info_bubble_gtk.cc new file mode 100644 index 0000000..3758cd2 --- /dev/null +++ b/chrome/browser/gtk/info_bubble_gtk.cc @@ -0,0 +1,208 @@ +// 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 "chrome/browser/gtk/info_bubble_gtk.h" + +#include <gtk/gtk.h> + +#include "base/basictypes.h" +#include "base/gfx/gtk_util.h" +#include "base/gfx/rect.h" +#include "base/logging.h" +#include "chrome/common/gfx/path.h" + +namespace { + +// The height of the arrow, and the width will be about twice the height. +const int kArrowSize = 5; +// Number of pixels to the start of the arrow from the edge of the window. +const int kArrowX = 13; +// Number of pixels between the tip of the arrow and the region we're +// pointing to. +const int kArrowToContentPadding = -6; +// We draw flat diagonal corners, each corner is an NxN square. +const int kCornerSize = 3; +// Margins around the content. +const int kTopMargin = kArrowSize + kCornerSize + 6; +const int kBottomMargin = kCornerSize + 6; +const int kLeftMargin = kCornerSize + 6; +const int kRightMargin = kCornerSize + 6; + +const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff); +const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63); + +// A small convenience since GdkPoint is a POD without a constructor. +GdkPoint MakeGdkPoint(gint x, gint y) { + GdkPoint point = {x, y}; + return point; +} + +enum FrameType { + FRAME_MASK, + FRAME_STROKE, +}; + +// Make the points for our polygon frame, either for fill (the mask), or for +// when we stroke the border. 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. +std::vector<GdkPoint> MakeFramePolygonPoints(int width, + int height, + FrameType type) { + std::vector<GdkPoint> points; + + // If we have a stroke, we have to offset some of our points by 1 pixel. + int off = (type == FRAME_MASK) ? 0 : 1; + + // Top left corner. + points.push_back(MakeGdkPoint(0, kArrowSize + kCornerSize - 1)); + points.push_back(MakeGdkPoint(kCornerSize - 1, kArrowSize)); + + // The arrow. + points.push_back(MakeGdkPoint(kArrowX - kArrowSize, kArrowSize)); + points.push_back(MakeGdkPoint(kArrowX, 0)); + points.push_back(MakeGdkPoint(kArrowX + 1 - off, 0)); + points.push_back(MakeGdkPoint(kArrowX + kArrowSize + 1 - off, kArrowSize)); + + // Top right corner. + points.push_back(MakeGdkPoint(width - kCornerSize + 1 - off, kArrowSize)); + points.push_back(MakeGdkPoint(width - off, kArrowSize + kCornerSize - 1)); + + // Bottom right corner. + points.push_back(MakeGdkPoint(width - off, height - kCornerSize)); + points.push_back(MakeGdkPoint(width - kCornerSize, height - off)); + + // Bottom left corner. + points.push_back(MakeGdkPoint(kCornerSize - off, height - off)); + points.push_back(MakeGdkPoint(0, height - kCornerSize)); + + return points; +} + +// When our size is initially allocated or changed, we need to recompute +// and apply our shape mask region. +void HandleSizeAllocate(GtkWidget* widget, + GtkAllocation* allocation, + gpointer unused) { + DCHECK(allocation->x == 0 && allocation->y == 0); + std::vector<GdkPoint> points = MakeFramePolygonPoints( + allocation->width, allocation->height, FRAME_MASK); + GdkRegion* mask_region = gdk_region_polygon(&points[0], + points.size(), + GDK_EVEN_ODD_RULE); + gdk_window_shape_combine_region(widget->window, mask_region, 0, 0); + gdk_region_destroy(mask_region); +} + +gboolean HandleExpose(GtkWidget* widget, + GdkEventExpose* event, + gpointer unused) { + GdkDrawable* drawable = GDK_DRAWABLE(event->window); + GdkGC* gc = gdk_gc_new(drawable); + gdk_gc_set_rgb_fg_color(gc, &kFrameColor); + + // Stroke the frame border. + std::vector<GdkPoint> points = MakeFramePolygonPoints( + widget->allocation.width, widget->allocation.height, FRAME_STROKE); + gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size()); + + g_object_unref(gc); + return FALSE; // Propagate so our children paint, etc. +} + +} // namespace + +// static +InfoBubbleGtk* InfoBubbleGtk::Show(const gfx::Rect& rect, GtkWidget* content) { + InfoBubbleGtk* bubble = new InfoBubbleGtk(); + bubble->Init(rect, content); + return bubble; +} + +InfoBubbleGtk::InfoBubbleGtk() + : window_(NULL), + screen_x_(0), + screen_y_(0), + closed_(false) { +} + +InfoBubbleGtk::~InfoBubbleGtk() { +} + +void InfoBubbleGtk::Init(const gfx::Rect& rect, GtkWidget* content) { + DCHECK(!window_); + screen_x_ = rect.x() + (rect.width() / 2) - kArrowX; + screen_y_ = rect.y() + rect.height() + kArrowToContentPadding; + + window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_decorated(GTK_WINDOW(window_), TRUE); + gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); + gtk_widget_set_app_paintable(window_, TRUE); + // Have GTK double buffer around the expose signal. + gtk_widget_set_double_buffered(window_, TRUE); + // Set the background color, so we don't need to paint it manually. + gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &kBackgroundColor); + // Make sure that our window can be focused. + GTK_WIDGET_SET_FLAGS(window_, GTK_CAN_FOCUS); + + GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), + kTopMargin, kBottomMargin, + kLeftMargin, kRightMargin); + + 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 + // HandleSizeAllocate, so the mask can be applied to the GdkWindow. + gtk_widget_realize(window_); + gtk_window_move(GTK_WINDOW(window_), screen_x_, screen_y_); + + gtk_widget_add_events(window_, GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK); + + g_signal_connect(window_, "size-allocate", + G_CALLBACK(HandleSizeAllocate), NULL); + g_signal_connect(window_, "expose-event", + G_CALLBACK(HandleExpose), NULL); + g_signal_connect(window_, "configure-event", + G_CALLBACK(&HandleConfigureThunk), this); + g_signal_connect(window_, "button-press-event", + G_CALLBACK(&HandleButtonPressThunk), this); + + gtk_widget_show_all(window_); + gtk_window_present(GTK_WINDOW(window_)); + gtk_grab_add(window_); +} + +void InfoBubbleGtk::Close() { + DCHECK(!closed_); + DCHECK(window_); + gtk_widget_destroy(window_); + window_ = NULL; + closed_ = true; +} + +gboolean InfoBubbleGtk::HandleConfigure(GdkEventConfigure* event) { + // If the window is moved someplace besides where we want it, move it back. + // TODO(deanm): In the end, I will probably remove this code and just let + // the user move around the bubble like a normal dialog. I want to try + // this for now and see if it causes problems when any window managers. + if (event->x != screen_x_ || event->y != screen_y_) + gtk_window_move(GTK_WINDOW(window_), screen_x_, screen_y_); + return FALSE; +} + +gboolean InfoBubbleGtk::HandleButtonPress(GdkEventButton* event) { + // If we got a click in our own window, that's ok. + if (event->window == window_->window) + return FALSE; // Propagate. + + // Otherwise we had a click outside of our window, close ourself. + Close(); + return TRUE; +} diff --git a/chrome/browser/gtk/info_bubble_gtk.h b/chrome/browser/gtk/info_bubble_gtk.h new file mode 100644 index 0000000..d5a3b7b --- /dev/null +++ b/chrome/browser/gtk/info_bubble_gtk.h @@ -0,0 +1,72 @@ +// 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 CHROME_BROWSER_GTK_INFO_BUBBLE_GTK_H_ +#define CHROME_BROWSER_GTK_INFO_BUBBLE_GTK_H_ + +#include "base/basictypes.h" + +#include <gtk/gtk.h> + +namespace gfx { +class Rect; +} + +class InfoBubbleGtk { + public: + // Show an InfoBubble, pointing at the area |rect| (in screen coordinates). + // An infobubble will try to fit on the screen, so it can point to any edge + // of |rect|. The bubble will host |widget| as the content. + static InfoBubbleGtk* Show(const gfx::Rect& rect, GtkWidget* content); + + InfoBubbleGtk(); + virtual ~InfoBubbleGtk(); + + void Close(); + + private: + // Creates the InfoBubble. + void Init(const gfx::Rect& rect, GtkWidget* content); + + // Closes the window notifying the delegate. |closed_by_escape| is true if + // the close is the result of pressing escape. + void Close(bool closed_by_escape); + + static gboolean HandleConfigureThunk(GtkWidget* widget, + GdkEventConfigure* event, + gpointer user_data) { + return reinterpret_cast<InfoBubbleGtk*>(user_data)->HandleConfigure(event); + } + gboolean HandleConfigure(GdkEventConfigure* event); + + static gboolean HandleButtonPressThunk(GtkWidget* widget, + GdkEventButton* event, + gpointer userdata) { + return reinterpret_cast<InfoBubbleGtk*>(userdata)-> + HandleButtonPress(event); + } + gboolean HandleButtonPress(GdkEventButton* event); + + static gboolean HandleButtonReleaseThunk(GtkWidget* widget, + GdkEventButton* event, + gpointer userdata) { + return reinterpret_cast<InfoBubbleGtk*>(userdata)-> + HandleButtonRelease(event); + } + gboolean HandleButtonRelease(GdkEventButton* event); + + // Our GtkWindow popup window. + GtkWidget* window_; + + // Where we want our window to be positioned on the screen. + int screen_x_; + int screen_y_; + + // Have we been closed? + bool closed_; + + DISALLOW_COPY_AND_ASSIGN(InfoBubbleGtk); +}; + +#endif // CHROME_BROWSER_GTK_INFO_BUBBLE_GTK_H_ diff --git a/chrome/browser/gtk/toolbar_star_toggle_gtk.cc b/chrome/browser/gtk/toolbar_star_toggle_gtk.cc index e6edf24..92cfc16 100644 --- a/chrome/browser/gtk/toolbar_star_toggle_gtk.cc +++ b/chrome/browser/gtk/toolbar_star_toggle_gtk.cc @@ -4,6 +4,8 @@ #include "chrome/browser/gtk/toolbar_star_toggle_gtk.h" +#include "base/gfx/rect.h" +#include "chrome/browser/gtk/bookmark_bubble_gtk.h" #include "chrome/common/resource_bundle.h" #include "grit/theme_resources.h" @@ -27,6 +29,22 @@ ToolbarStarToggleGtk::~ToolbarStarToggleGtk() { widget_.Destroy(); } +void ToolbarStarToggleGtk::ShowStarBubble(const GURL& url, + bool newly_bookmarked) { + GtkWidget* widget = widget_.get(); + gint x, y; + gdk_window_get_origin(widget->window, &x, &y); + x += widget->allocation.x; + y += widget->allocation.y; + gint width = widget->allocation.width; + gint height = widget->allocation.height; + + BookmarkBubbleGtk::Show(gfx::Rect(x, y, width, height), + NULL, + url, + newly_bookmarked); +} + void ToolbarStarToggleGtk::SetStarred(bool starred) { is_starred_ = starred; gtk_widget_queue_draw(widget_.get()); diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 3d845d5..de92c3e 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -728,6 +728,8 @@ 'browser/gtk/back_forward_menu_model_gtk.h', 'browser/gtk/bookmark_bar_gtk.cc', 'browser/gtk/bookmark_bar_gtk.h', + 'browser/gtk/bookmark_bubble_gtk.cc', + 'browser/gtk/bookmark_bubble_gtk.h', 'browser/gtk/bookmark_editor_gtk.cc', 'browser/gtk/bookmark_editor_gtk.h', 'browser/gtk/browser_toolbar_gtk.cc', @@ -746,10 +748,12 @@ 'browser/gtk/go_button_gtk.h', 'browser/gtk/gtk_chrome_button.cc', 'browser/gtk/gtk_chrome_button.h', - 'browser/gtk/infobar_gtk.cc', - 'browser/gtk/infobar_gtk.h', + 'browser/gtk/info_bubble_gtk.cc', + 'browser/gtk/info_bubble_gtk.h', 'browser/gtk/infobar_container_gtk.cc', 'browser/gtk/infobar_container_gtk.h', + 'browser/gtk/infobar_gtk.cc', + 'browser/gtk/infobar_gtk.h', 'browser/gtk/find_bar_gtk.cc', 'browser/gtk/find_bar_gtk.h', 'browser/gtk/link_button_gtk.cc', |