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

Side by Side Diff: ui/views/controls/native/native_view_host_gtk.cc

Issue 9728002: Removing deprecated GTK-Views code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 9 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/views/controls/native/native_view_host_gtk.h ('k') | ui/views/controls/native_control_gtk.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "ui/views/controls/native/native_view_host_gtk.h"
6
7 #include <gtk/gtk.h>
8
9 #include <algorithm>
10
11 #include "base/logging.h"
12 #include "ui/views/controls/native/native_view_host.h"
13 #include "ui/views/focus/focus_manager.h"
14 #include "ui/views/views_delegate.h"
15 #include "ui/views/widget/gtk_views_fixed.h"
16 #include "ui/views/widget/native_widget_gtk.h"
17 #include "ui/views/widget/widget.h"
18
19 namespace views {
20
21 namespace {
22 static bool signal_id_initialized_ = false;
23 static guint focus_in_event_signal_id_;
24 static guint focus_out_event_signal_id_;
25
26 ////////////////////////////////////////////////////////////////////////////////
27 // Utility functions to block focus signals while re-creating
28 // Fixed widget.
29
30 void InitSignalIds() {
31 if (!signal_id_initialized_) {
32 signal_id_initialized_ = true;
33 focus_in_event_signal_id_ =
34 g_signal_lookup("focus-in-event", GTK_TYPE_WIDGET);
35 focus_out_event_signal_id_ =
36 g_signal_lookup("focus-out-event", GTK_TYPE_WIDGET);
37 }
38 }
39
40 // Blocks a |signal_id| on the given |widget| if any.
41 void BlockSignal(GtkWidget* widget, guint signal_id) {
42 gulong handler_id = g_signal_handler_find(G_OBJECT(widget),
43 G_SIGNAL_MATCH_ID,
44 signal_id,
45 0, NULL, NULL, NULL);
46 if (handler_id) {
47 g_signal_handler_block(G_OBJECT(widget), handler_id);
48 }
49 }
50
51 // Unblocks a |signal_id| on the given |widget| if any.
52 void UnblockSignal(GtkWidget* widget, guint signal_id) {
53 gulong handler_id = g_signal_handler_find(G_OBJECT(widget),
54 G_SIGNAL_MATCH_ID,
55 signal_id,
56 0, NULL, NULL, NULL);
57 if (handler_id) {
58 g_signal_handler_unblock(G_OBJECT(widget), handler_id);
59 }
60 }
61
62 // Blocks focus in/out signals of the widget and its descendent
63 // children.
64 // Note: Due to the limiation of Gtk API, this only blocks the 1st
65 // handler found and won't block the rest if there is more than one handlers.
66 // See bug http://crbug.com/33236.
67 void BlockFocusSignals(GtkWidget* widget, gpointer data) {
68 if (!widget)
69 return;
70 InitSignalIds();
71 BlockSignal(widget, focus_in_event_signal_id_);
72 BlockSignal(widget, focus_out_event_signal_id_);
73 if (GTK_IS_CONTAINER(widget))
74 gtk_container_foreach(GTK_CONTAINER(widget), BlockFocusSignals, data);
75 }
76
77 // Unlocks focus in/out signals of the widget and its descendent children.
78 void UnblockFocusSignals(GtkWidget* widget, gpointer data) {
79 if (!widget)
80 return;
81 InitSignalIds();
82 UnblockSignal(widget, focus_in_event_signal_id_);
83 UnblockSignal(widget, focus_out_event_signal_id_);
84 if (GTK_IS_CONTAINER(widget))
85 gtk_container_foreach(GTK_CONTAINER(widget), UnblockFocusSignals, data);
86 }
87
88 // Removes |child| from |parent|.
89 void RemoveFromParent(GtkWidget* child, gpointer parent) {
90 gtk_container_remove(GTK_CONTAINER(parent), child);
91 }
92
93 // Reparents |child| to be a child of |parent|.
94 void Reparent(GtkWidget* child, gpointer parent) {
95 gtk_widget_reparent(child, GTK_WIDGET(parent));
96 }
97
98 } // namespace
99
100 ////////////////////////////////////////////////////////////////////////////////
101 // NativeViewHostGtk, public:
102
103 NativeViewHostGtk::NativeViewHostGtk(NativeViewHost* host)
104 : host_(host),
105 installed_clip_(false),
106 destroy_signal_id_(0),
107 focus_signal_id_(0),
108 fixed_(NULL) {
109 CreateFixed(false);
110 }
111
112 NativeViewHostGtk::~NativeViewHostGtk() {
113 if (fixed_) {
114 gtk_container_foreach(GTK_CONTAINER(fixed_), RemoveFromParent, fixed_);
115 gtk_widget_destroy(fixed_);
116 }
117 }
118
119 ////////////////////////////////////////////////////////////////////////////////
120 // NativeViewHostGtk, NativeViewHostWrapper implementation:
121
122 void NativeViewHostGtk::NativeViewAttached() {
123 AttachHostWidget();
124
125 GtkWidget* host_widget = host_->native_view();
126
127 // Let the widget know that the native component has been painted.
128 views::NativeWidgetGtk::RegisterChildExposeHandler(host_widget);
129
130 if (!destroy_signal_id_) {
131 destroy_signal_id_ = g_signal_connect(host_widget,
132 "destroy", G_CALLBACK(CallDestroy),
133 this);
134 }
135
136 if (!focus_signal_id_) {
137 focus_signal_id_ = g_signal_connect(host_widget,
138 "focus-in-event",
139 G_CALLBACK(CallFocusIn), this);
140 }
141
142 // Always layout though.
143 host_->Layout();
144
145 // TODO(port): figure out focus.
146 }
147
148 void NativeViewHostGtk::NativeViewDetaching(bool destroyed) {
149 GtkWidget* host_widget = host_->native_view();
150 DCHECK(host_widget);
151
152 views::NativeWidgetGtk::UnregisterChildExposeHandler(host_widget);
153
154 g_signal_handler_disconnect(G_OBJECT(host_widget), destroy_signal_id_);
155 destroy_signal_id_ = 0;
156
157 g_signal_handler_disconnect(G_OBJECT(host_widget), focus_signal_id_);
158 focus_signal_id_ = 0;
159
160 installed_clip_ = false;
161 }
162
163 void NativeViewHostGtk::AddedToWidget() {
164 if (!fixed_)
165 CreateFixed(false);
166 if (gtk_widget_get_parent(fixed_))
167 GetHostWidget()->ReparentChild(fixed_);
168 else
169 GetHostWidget()->AddChild(fixed_);
170
171 if (!host_->native_view())
172 return;
173
174 AttachHostWidget();
175
176 if (host_->IsDrawn()) {
177 gtk_widget_show(host_->native_view());
178 gtk_widget_show(fixed_);
179 } else {
180 gtk_widget_hide(fixed_);
181 }
182 host_->Layout();
183 }
184
185 void NativeViewHostGtk::RemovedFromWidget() {
186 if (!host_->native_view())
187 return;
188 DestroyFixed();
189 }
190
191 void NativeViewHostGtk::InstallClip(int x, int y, int w, int h) {
192 DCHECK(w > 0 && h > 0);
193 installed_clip_bounds_.SetRect(x, y, w, h);
194 if (!installed_clip_) {
195 installed_clip_ = true;
196
197 // We only re-create the fixed with a window when a cliprect is installed.
198 // Because the presence of a X Window will prevent transparency from working
199 // properly, we only want it to be active for the duration of a clip
200 // (typically during animations and scrolling.)
201 CreateFixed(true);
202 }
203 }
204
205 bool NativeViewHostGtk::HasInstalledClip() {
206 return installed_clip_;
207 }
208
209 void NativeViewHostGtk::UninstallClip() {
210 installed_clip_ = false;
211 // We now re-create the fixed without a X Window so transparency works again.
212 CreateFixed(false);
213 }
214
215 void NativeViewHostGtk::ShowWidget(int x, int y, int w, int h) {
216 // x and y are the desired position of host_ in NativeWidgetGtk coordinates.
217 int fixed_x = x;
218 int fixed_y = y;
219 int fixed_w = w;
220 int fixed_h = h;
221 int child_x = 0;
222 int child_y = 0;
223 int child_w = w;
224 int child_h = h;
225 if (installed_clip_) {
226 child_x = -installed_clip_bounds_.x();
227 child_y = -installed_clip_bounds_.y();
228 fixed_x += -child_x;
229 fixed_y += -child_y;
230 fixed_w = std::min(installed_clip_bounds_.width(), w);
231 fixed_h = std::min(installed_clip_bounds_.height(), h);
232 }
233
234 GtkWidget* host_widget = host_->native_view();
235 // Don't call gtk_widget_size_allocate now, as we're possibly in the
236 // middle of a re-size, and it kicks off another re-size, and you
237 // get flashing. Instead, we'll set the desired size as properties
238 // on the widget and queue the re-size.
239 gtk_views_fixed_set_widget_size(host_widget, child_w, child_h);
240 gtk_fixed_move(GTK_FIXED(fixed_), host_widget, child_x, child_y);
241
242 // Size and place the fixed_.
243 GetHostWidget()->PositionChild(fixed_, fixed_x, fixed_y, fixed_w, fixed_h);
244
245 gtk_widget_show(host_widget);
246 gtk_widget_show(fixed_);
247 }
248
249 void NativeViewHostGtk::HideWidget() {
250 if (fixed_)
251 gtk_widget_hide(fixed_);
252 }
253
254 void NativeViewHostGtk::SetFocus() {
255 GtkWidget* host_widget = host_->native_view();
256 DCHECK(host_widget);
257 gtk_widget_grab_focus(host_widget);
258 }
259
260 gfx::NativeViewAccessible NativeViewHostGtk::GetNativeViewAccessible() {
261 return NULL;
262 }
263
264 ////////////////////////////////////////////////////////////////////////////////
265 // NativeViewHostGtk, private:
266
267 void NativeViewHostGtk::CreateFixed(bool needs_window) {
268 GtkWidget* focused_widget = GetFocusedDescendant();
269
270 bool focus_event_blocked = false;
271 // We move focus around and do not want focus events to be emitted
272 // during this process.
273 if (fixed_) {
274 BlockFocusSignals(GetHostWidget()->GetNativeView(), NULL);
275 focus_event_blocked = true;
276 }
277
278 if (focused_widget) {
279 // A descendant of our fixed has focus. When we destroy the fixed focus is
280 // automatically moved. Temporarily move focus to our host widget, then
281 // restore focus after we create the new fixed_. This way focus hasn't
282 // really moved.
283 gtk_widget_grab_focus(GetHostWidget()->GetNativeView());
284 }
285
286 // Move all the contained widgets to the new fixed.
287 GtkWidget* new_fixed = gtk_views_fixed_new();
288 if (fixed_) {
289 gtk_container_foreach(GTK_CONTAINER(fixed_), Reparent, new_fixed);
290 DestroyFixed();
291 }
292 fixed_ = new_fixed;
293
294 gtk_widget_set_name(fixed_, "views-native-view-host-fixed");
295 gtk_fixed_set_has_window(GTK_FIXED(fixed_), needs_window);
296
297 // Defeat refcounting. We need to own the fixed.
298 gtk_widget_ref(fixed_);
299
300 NativeWidgetGtk* widget_gtk = GetHostWidget();
301 if (widget_gtk) {
302 widget_gtk->AddChild(fixed_);
303 // Clear the background so we don't get flicker.
304 gtk_widget_realize(fixed_);
305 gdk_window_set_back_pixmap(fixed_->window, NULL, false);
306 }
307
308 if (host_->native_view())
309 AttachHostWidget();
310
311 if (widget_gtk && host_->native_view() && focused_widget)
312 gtk_widget_grab_focus(focused_widget);
313
314 if (focus_event_blocked) {
315 // Unblocking a signal handler that is not blocked fails.
316 // Unblock only when it's unblocked.
317 UnblockFocusSignals(GetHostWidget()->GetNativeView(), NULL);
318 }
319 }
320
321 void NativeViewHostGtk::DestroyFixed() {
322 if (!fixed_)
323 return;
324
325 gtk_widget_hide(fixed_);
326 gtk_container_foreach(GTK_CONTAINER(fixed_), RemoveFromParent, fixed_);
327 GetHostWidget()->RemoveChild(fixed_);
328
329 // fixed_ should not have any children this point.
330 DCHECK_EQ(0U,
331 g_list_length(gtk_container_get_children(GTK_CONTAINER(fixed_))));
332 gtk_widget_destroy(fixed_);
333 fixed_ = NULL;
334 }
335
336 NativeWidgetGtk* NativeViewHostGtk::GetHostWidget() const {
337 return static_cast<NativeWidgetGtk*>(host_->GetWidget()->native_widget());
338 }
339
340 GtkWidget* NativeViewHostGtk::GetFocusedDescendant() {
341 if (!fixed_)
342 return NULL;
343 NativeWidgetGtk* host = GetHostWidget();
344 if (!host)
345 return NULL;
346 GtkWidget* top_level = gtk_widget_get_toplevel(host->GetNativeView());
347 if (!top_level || !GTK_IS_WINDOW(top_level))
348 return NULL;
349 GtkWidget* focused = gtk_window_get_focus(GTK_WINDOW(top_level));
350 if (!focused)
351 return NULL;
352 return (focused == fixed_ || gtk_widget_is_ancestor(focused, fixed_)) ?
353 focused : NULL;
354 }
355
356 void NativeViewHostGtk::AttachHostWidget() {
357 GtkWidget* host_widget = host_->native_view();
358 DCHECK(host_widget);
359
360 GtkWidget* host_parent = gtk_widget_get_parent(host_widget);
361 bool parent_changed = true;
362 if (host_parent) {
363 if (host_parent != fixed_)
364 gtk_widget_reparent(host_widget, fixed_);
365 else
366 parent_changed = false;
367 } else {
368 gtk_container_add(GTK_CONTAINER(fixed_), host_widget);
369 }
370
371 if (parent_changed) {
372 // We need to clear the background so we don't get flicker on tab switching.
373 // To do that we must realize the widget if it's not already.
374 if (!GTK_WIDGET_REALIZED(host_widget))
375 gtk_widget_realize(host_widget);
376 gdk_window_set_back_pixmap(host_widget->window, NULL, false);
377 }
378 }
379
380 // static
381 void NativeViewHostGtk::CallDestroy(GtkObject* object,
382 NativeViewHostGtk* host) {
383 host->host_->NativeViewDestroyed();
384 }
385
386 // static
387 gboolean NativeViewHostGtk::CallFocusIn(GtkWidget* gtk_widget,
388 GdkEventFocus* event,
389 NativeViewHostGtk* host) {
390 Widget* widget = Widget::GetWidgetForNativeView(gtk_widget);
391 FocusManager* focus_manager = widget ? widget->GetFocusManager() : NULL;
392 if (!focus_manager) {
393 // TODO(jcampan): http://crbug.com/21378 Reenable this NOTREACHED() when the
394 // options page is only based on views.
395 // NOTREACHED();
396 NOTIMPLEMENTED();
397 return false;
398 }
399 focus_manager->SetFocusedView(host->host_->focus_view());
400 return false;
401 }
402
403 ////////////////////////////////////////////////////////////////////////////////
404 // NativeViewHostWrapper, public:
405
406 // static
407 NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper(
408 NativeViewHost* host) {
409 return new NativeViewHostGtk(host);
410 }
411
412 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/native/native_view_host_gtk.h ('k') | ui/views/controls/native_control_gtk.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698