OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/gtk/theme_install_bubble_view_gtk.h" | |
6 | |
7 #include <math.h> | |
8 | |
9 #include "app/l10n_util.h" | |
10 #include "chrome/browser/gtk/gtk_util.h" | |
11 #include "chrome/browser/gtk/rounded_window.h" | |
12 #include "chrome/common/notification_service.h" | |
13 #include "chrome/common/notification_type.h" | |
14 #include "grit/generated_resources.h" | |
15 | |
16 // Roundedness of bubble. | |
17 static const int kBubbleCornerRadius = 4; | |
18 | |
19 // Padding between border of bubble and text. | |
20 static const int kTextPadding = 8; | |
21 | |
22 // The bubble is partially transparent. | |
23 static const double kBubbleOpacity = static_cast<double>(0xcc) / 0xff; | |
24 | |
25 ThemeInstallBubbleViewGtk* ThemeInstallBubbleViewGtk::instance_ = NULL; | |
26 | |
27 // ThemeInstallBubbleViewGtk, public ------------------------------------------- | |
28 | |
29 // static | |
30 void ThemeInstallBubbleViewGtk::Show(GtkWindow* parent) { | |
31 if (instance_) | |
32 instance_->increment_num_loading(); | |
33 else | |
34 instance_ = new ThemeInstallBubbleViewGtk(GTK_WIDGET(parent)); | |
35 } | |
36 | |
37 void ThemeInstallBubbleViewGtk::Observe(NotificationType type, | |
38 const NotificationSource& source, | |
39 const NotificationDetails& details) { | |
40 if (--num_loads_extant_ == 0) | |
41 delete this; | |
42 } | |
43 | |
44 // ThemeInstallBubbleViewGtk, private ------------------------------------------ | |
45 | |
46 ThemeInstallBubbleViewGtk::ThemeInstallBubbleViewGtk(GtkWidget* parent) | |
47 : widget_(NULL), | |
48 parent_(parent), | |
49 num_loads_extant_(1) { | |
50 InitWidgets(); | |
51 | |
52 // Close when theme has been installed. | |
53 registrar_.Add( | |
54 this, | |
55 NotificationType::BROWSER_THEME_CHANGED, | |
56 NotificationService::AllSources()); | |
57 | |
58 // Close when we are installing an extension, not a theme. | |
59 registrar_.Add( | |
60 this, | |
61 NotificationType::NO_THEME_DETECTED, | |
62 NotificationService::AllSources()); | |
63 registrar_.Add( | |
64 this, | |
65 NotificationType::EXTENSION_INSTALLED, | |
66 NotificationService::AllSources()); | |
67 registrar_.Add( | |
68 this, | |
69 NotificationType::EXTENSION_INSTALL_ERROR, | |
70 NotificationService::AllSources()); | |
71 | |
72 // Don't let the bubble overlap the confirm dialog. | |
73 registrar_.Add( | |
74 this, | |
75 NotificationType::EXTENSION_WILL_SHOW_CONFIRM_DIALOG, | |
76 NotificationService::AllSources()); | |
77 } | |
78 | |
79 ThemeInstallBubbleViewGtk::~ThemeInstallBubbleViewGtk() { | |
80 gtk_widget_destroy(widget_); | |
81 instance_ = NULL; | |
82 } | |
83 | |
84 void ThemeInstallBubbleViewGtk::InitWidgets() { | |
85 // Widgematically, the bubble is just a label in a popup window. | |
86 widget_ = gtk_window_new(GTK_WINDOW_POPUP); | |
87 gtk_container_set_border_width(GTK_CONTAINER(widget_), kTextPadding); | |
88 GtkWidget* label = gtk_label_new(NULL); | |
89 | |
90 gchar* markup = g_markup_printf_escaped( | |
91 "<span size='xx-large'>%s</span>", | |
92 l10n_util::GetStringUTF8(IDS_THEME_LOADING_TITLE).c_str()); | |
93 gtk_label_set_markup(GTK_LABEL(label), markup); | |
94 g_free(markup); | |
95 | |
96 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, >k_util::kGdkWhite); | |
97 gtk_container_add(GTK_CONTAINER(widget_), label); | |
98 | |
99 // We need to show the label so we'll know the widget's actual size when we | |
100 // call MoveWindow(). | |
101 gtk_widget_show_all(label); | |
102 | |
103 bool composited = false; | |
104 if (gtk_util::IsScreenComposited()) { | |
105 composited = true; | |
106 GdkScreen* screen = gtk_widget_get_screen(widget_); | |
107 GdkColormap* colormap = gdk_screen_get_rgba_colormap(screen); | |
108 | |
109 if (colormap) | |
110 gtk_widget_set_colormap(widget_, colormap); | |
111 else | |
112 composited = false; | |
113 } | |
114 | |
115 if (composited) { | |
116 gtk_widget_set_app_paintable(widget_, TRUE); | |
117 g_signal_connect(widget_, "expose-event", | |
118 G_CALLBACK(OnExposeThunk), this); | |
119 gtk_widget_realize(widget_); | |
120 } else { | |
121 gtk_widget_modify_bg(widget_, GTK_STATE_NORMAL, >k_util::kGdkBlack); | |
122 GdkColor color; | |
123 gtk_util::ActAsRoundedWindow(widget_, color, kBubbleCornerRadius, | |
124 gtk_util::ROUNDED_ALL, gtk_util::BORDER_NONE); | |
125 } | |
126 | |
127 MoveWindow(); | |
128 | |
129 g_signal_connect(widget_, "unmap-event", | |
130 G_CALLBACK(OnUnmapEventThunk), this); | |
131 | |
132 gtk_widget_show_all(widget_); | |
133 } | |
134 | |
135 void ThemeInstallBubbleViewGtk::MoveWindow() { | |
136 GtkRequisition req; | |
137 gtk_widget_size_request(widget_, &req); | |
138 | |
139 gint parent_x = 0, parent_y = 0; | |
140 gdk_window_get_position(parent_->window, &parent_x, &parent_y); | |
141 gint parent_width = parent_->allocation.width; | |
142 gint parent_height = parent_->allocation.height; | |
143 | |
144 gint x = parent_x + parent_width / 2 - req.width / 2; | |
145 gint y = parent_y + parent_height / 2 - req.height / 2; | |
146 | |
147 gtk_window_move(GTK_WINDOW(widget_), x, y); | |
148 } | |
149 | |
150 gboolean ThemeInstallBubbleViewGtk::OnUnmapEvent(GtkWidget* widget) { | |
151 delete this; | |
152 return FALSE; | |
153 } | |
154 | |
155 gboolean ThemeInstallBubbleViewGtk::OnExpose(GtkWidget* widget, | |
156 GdkEventExpose* event) { | |
157 cairo_t* cr = gdk_cairo_create(event->window); | |
158 gdk_cairo_rectangle(cr, &event->area); | |
159 cairo_clip(cr); | |
160 | |
161 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); | |
162 cairo_paint(cr); | |
163 cairo_set_operator(cr, CAIRO_OPERATOR_OVER); | |
164 | |
165 // |inner_rect| has its corners at the centerpoints of the corner arcs. | |
166 gfx::Rect inner_rect(widget_->allocation); | |
167 int inset = kBubbleCornerRadius; | |
168 inner_rect.Inset(inset, inset); | |
169 | |
170 // The positive y axis is down, so M_PI_2 is down. | |
171 cairo_arc(cr, inner_rect.x(), inner_rect.y(), inset, | |
172 M_PI, 3 * M_PI_2); | |
173 cairo_arc(cr, inner_rect.right(), inner_rect.y(), inset, | |
174 3 * M_PI_2, 0); | |
175 cairo_arc(cr, inner_rect.right(), inner_rect.bottom(), inset, | |
176 0, M_PI_2); | |
177 cairo_arc(cr, inner_rect.x(), inner_rect.bottom(), inset, | |
178 M_PI_2, M_PI); | |
179 | |
180 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, kBubbleOpacity); | |
181 cairo_fill(cr); | |
182 cairo_destroy(cr); | |
183 | |
184 return FALSE; | |
185 } | |
OLD | NEW |