| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/gtk/info_bubble_gtk.h" | 5 #include "chrome/browser/gtk/info_bubble_gtk.h" |
| 6 | 6 |
| 7 #include <gdk/gdkkeysyms.h> | 7 #include <gdk/gdkkeysyms.h> |
| 8 #include <gtk/gtk.h> | 8 #include <gtk/gtk.h> |
| 9 | 9 |
| 10 #include "app/gfx/path.h" | 10 #include "app/gfx/path.h" |
| 11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| 12 #include "base/gfx/gtk_util.h" | 12 #include "base/gfx/gtk_util.h" |
| 13 #include "base/gfx/rect.h" | 13 #include "base/gfx/rect.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "chrome/browser/gtk/gtk_theme_provider.h" |
| 15 #include "chrome/common/notification_service.h" | 16 #include "chrome/common/notification_service.h" |
| 16 | 17 |
| 17 namespace { | 18 namespace { |
| 18 | 19 |
| 19 // The height of the arrow, and the width will be about twice the height. | 20 // The height of the arrow, and the width will be about twice the height. |
| 20 const int kArrowSize = 5; | 21 const int kArrowSize = 5; |
| 21 // Number of pixels to the start of the arrow from the edge of the window. | 22 // Number of pixels to the start of the arrow from the edge of the window. |
| 22 const int kArrowX = 13; | 23 const int kArrowX = 13; |
| 23 // Number of pixels between the tip of the arrow and the region we're | 24 // Number of pixels between the tip of the arrow and the region we're |
| 24 // pointing to. | 25 // pointing to. |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 g_object_unref(gc); | 117 g_object_unref(gc); |
| 117 return FALSE; // Propagate so our children paint, etc. | 118 return FALSE; // Propagate so our children paint, etc. |
| 118 } | 119 } |
| 119 | 120 |
| 120 } // namespace | 121 } // namespace |
| 121 | 122 |
| 122 // static | 123 // static |
| 123 InfoBubbleGtk* InfoBubbleGtk::Show(GtkWindow* transient_toplevel, | 124 InfoBubbleGtk* InfoBubbleGtk::Show(GtkWindow* transient_toplevel, |
| 124 const gfx::Rect& rect, | 125 const gfx::Rect& rect, |
| 125 GtkWidget* content, | 126 GtkWidget* content, |
| 127 GtkThemeProvider* provider, |
| 126 InfoBubbleGtkDelegate* delegate) { | 128 InfoBubbleGtkDelegate* delegate) { |
| 127 InfoBubbleGtk* bubble = new InfoBubbleGtk(); | 129 InfoBubbleGtk* bubble = new InfoBubbleGtk(provider); |
| 128 bubble->Init(transient_toplevel, rect, content); | 130 bubble->Init(transient_toplevel, rect, content); |
| 129 bubble->set_delegate(delegate); | 131 bubble->set_delegate(delegate); |
| 130 return bubble; | 132 return bubble; |
| 131 } | 133 } |
| 132 | 134 |
| 133 InfoBubbleGtk::InfoBubbleGtk() | 135 InfoBubbleGtk::InfoBubbleGtk(GtkThemeProvider* provider) |
| 134 : delegate_(NULL), | 136 : delegate_(NULL), |
| 135 window_(NULL), | 137 window_(NULL), |
| 138 theme_provider_(provider), |
| 136 accel_group_(gtk_accel_group_new()), | 139 accel_group_(gtk_accel_group_new()), |
| 137 screen_x_(0), | 140 screen_x_(0), |
| 138 screen_y_(0) { | 141 screen_y_(0) { |
| 139 } | 142 } |
| 140 | 143 |
| 141 InfoBubbleGtk::~InfoBubbleGtk() { | 144 InfoBubbleGtk::~InfoBubbleGtk() { |
| 142 g_object_unref(accel_group_); | 145 g_object_unref(accel_group_); |
| 143 } | 146 } |
| 144 | 147 |
| 145 void InfoBubbleGtk::Init(GtkWindow* transient_toplevel, | 148 void InfoBubbleGtk::Init(GtkWindow* transient_toplevel, |
| 146 const gfx::Rect& rect, | 149 const gfx::Rect& rect, |
| 147 GtkWidget* content) { | 150 GtkWidget* content) { |
| 148 DCHECK(!window_); | 151 DCHECK(!window_); |
| 149 screen_x_ = rect.x() + (rect.width() / 2) - kArrowX; | 152 screen_x_ = rect.x() + (rect.width() / 2) - kArrowX; |
| 150 screen_y_ = rect.y() + rect.height() + kArrowToContentPadding; | 153 screen_y_ = rect.y() + rect.height() + kArrowToContentPadding; |
| 151 | 154 |
| 152 window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); | 155 window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
| 153 gtk_window_set_transient_for(GTK_WINDOW(window_), transient_toplevel); | 156 gtk_window_set_transient_for(GTK_WINDOW(window_), transient_toplevel); |
| 154 gtk_window_set_decorated(GTK_WINDOW(window_), FALSE); | 157 gtk_window_set_decorated(GTK_WINDOW(window_), FALSE); |
| 155 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); | 158 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); |
| 156 gtk_widget_set_app_paintable(window_, TRUE); | 159 gtk_widget_set_app_paintable(window_, TRUE); |
| 157 // Have GTK double buffer around the expose signal. | 160 // Have GTK double buffer around the expose signal. |
| 158 gtk_widget_set_double_buffered(window_, TRUE); | 161 gtk_widget_set_double_buffered(window_, TRUE); |
| 159 // Set the background color, so we don't need to paint it manually. | |
| 160 gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &kBackgroundColor); | |
| 161 // Make sure that our window can be focused. | 162 // Make sure that our window can be focused. |
| 162 GTK_WIDGET_SET_FLAGS(window_, GTK_CAN_FOCUS); | 163 GTK_WIDGET_SET_FLAGS(window_, GTK_CAN_FOCUS); |
| 163 | 164 |
| 164 // Attach our accelerator group to the window with an escape accelerator. | 165 // Attach our accelerator group to the window with an escape accelerator. |
| 165 gtk_accel_group_connect(accel_group_, GDK_Escape, | 166 gtk_accel_group_connect(accel_group_, GDK_Escape, |
| 166 static_cast<GdkModifierType>(0), static_cast<GtkAccelFlags>(0), | 167 static_cast<GdkModifierType>(0), static_cast<GtkAccelFlags>(0), |
| 167 g_cclosure_new(G_CALLBACK(&HandleEscapeThunk), this, NULL)); | 168 g_cclosure_new(G_CALLBACK(&HandleEscapeThunk), this, NULL)); |
| 168 gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group_); | 169 gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group_); |
| 169 | 170 |
| 170 GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | 171 GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 // Before adding the grab, we need to ensure that the bubble is added | 214 // Before adding the grab, we need to ensure that the bubble is added |
| 214 // to the window group of the top level window. This ensures that the | 215 // to the window group of the top level window. This ensures that the |
| 215 // grab only affects the current browser window, and not all the open | 216 // grab only affects the current browser window, and not all the open |
| 216 // browser windows in the application. | 217 // browser windows in the application. |
| 217 gtk_window_group_add_window(gtk_window_get_group(transient_toplevel), | 218 gtk_window_group_add_window(gtk_window_get_group(transient_toplevel), |
| 218 GTK_WINDOW(window_)); | 219 GTK_WINDOW(window_)); |
| 219 gtk_grab_add(window_); | 220 gtk_grab_add(window_); |
| 220 | 221 |
| 221 registrar_.Add(this, NotificationType::ACTIVE_WINDOW_CHANGED, | 222 registrar_.Add(this, NotificationType::ACTIVE_WINDOW_CHANGED, |
| 222 NotificationService::AllSources()); | 223 NotificationService::AllSources()); |
| 224 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, |
| 225 NotificationService::AllSources()); |
| 226 theme_provider_->InitThemesFor(this); |
| 223 } | 227 } |
| 224 | 228 |
| 225 void InfoBubbleGtk::Observe(NotificationType type, | 229 void InfoBubbleGtk::Observe(NotificationType type, |
| 226 const NotificationSource& source, | 230 const NotificationSource& source, |
| 227 const NotificationDetails& details) { | 231 const NotificationDetails& details) { |
| 228 DCHECK(type.value == NotificationType::ACTIVE_WINDOW_CHANGED); | 232 switch (type.value) { |
| 229 | 233 case NotificationType::ACTIVE_WINDOW_CHANGED: |
| 230 // If we are no longer the active toplevel for whatever reason (whether | 234 // If we are no longer the active toplevel for whatever reason (whether |
| 231 // another toplevel gained focus or our browser did), close. | 235 // another toplevel gained focus or our browser did), close. |
| 232 if (window_->window != Details<const GdkWindow>(details).ptr()) | 236 if (window_->window != Details<const GdkWindow>(details).ptr()) |
| 233 Close(); | 237 Close(); |
| 238 break; |
| 239 case NotificationType::BROWSER_THEME_CHANGED: |
| 240 if (theme_provider_->UseGtkTheme()) { |
| 241 gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, NULL); |
| 242 } else { |
| 243 // Set the background color, so we don't need to paint it manually. |
| 244 gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &kBackgroundColor); |
| 245 } |
| 246 break; |
| 247 default: |
| 248 NOTREACHED(); |
| 249 } |
| 234 } | 250 } |
| 235 | 251 |
| 236 // static | 252 // static |
| 237 GtkWindow* InfoBubbleGtk::GetToplevelForInfoBubble( | 253 GtkWindow* InfoBubbleGtk::GetToplevelForInfoBubble( |
| 238 const GdkWindow* bubble_window){ | 254 const GdkWindow* bubble_window) { |
| 239 if (!bubble_window) | 255 if (!bubble_window) |
| 240 return NULL; | 256 return NULL; |
| 241 | 257 |
| 242 return reinterpret_cast<GtkWindow*>( | 258 return reinterpret_cast<GtkWindow*>( |
| 243 g_object_get_data(G_OBJECT(bubble_window), kInfoBubbleToplevelKey)); | 259 g_object_get_data(G_OBJECT(bubble_window), kInfoBubbleToplevelKey)); |
| 244 } | 260 } |
| 245 | 261 |
| 246 void InfoBubbleGtk::Close(bool closed_by_escape) { | 262 void InfoBubbleGtk::Close(bool closed_by_escape) { |
| 247 // Notify the delegate that we're about to close. This gives the chance | 263 // Notify the delegate that we're about to close. This gives the chance |
| 248 // to save state / etc from the hosted widget before it's destroyed. | 264 // to save state / etc from the hosted widget before it's destroyed. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 279 return TRUE; | 295 return TRUE; |
| 280 } | 296 } |
| 281 | 297 |
| 282 gboolean InfoBubbleGtk::HandleDestroy() { | 298 gboolean InfoBubbleGtk::HandleDestroy() { |
| 283 // We are self deleting, we have a destroy signal setup to catch when we | 299 // We are self deleting, we have a destroy signal setup to catch when we |
| 284 // destroy the widget manually, or the window was closed via X. This will | 300 // destroy the widget manually, or the window was closed via X. This will |
| 285 // delete the InfoBubbleGtk object. | 301 // delete the InfoBubbleGtk object. |
| 286 delete this; | 302 delete this; |
| 287 return FALSE; // Propagate. | 303 return FALSE; // Propagate. |
| 288 } | 304 } |
| OLD | NEW |