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

Side by Side Diff: chrome/browser/ui/gtk/extensions/native_app_window_gtk.cc

Issue 21344002: Move native_app_window code to apps areas (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase to after mac app shim fix Created 7 years, 4 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/ui/gtk/extensions/native_app_window_gtk.h"
6
7 #include <gdk/gdkx.h>
8 #include <vector>
9
10 #include "base/message_loop/message_pump_gtk.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h"
14 #include "chrome/browser/ui/gtk/gtk_util.h"
15 #include "chrome/browser/ui/gtk/gtk_window_util.h"
16 #include "chrome/browser/web_applications/web_app.h"
17 #include "chrome/common/extensions/extension.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/render_widget_host_view.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_view.h"
22 #include "ui/base/x/active_window_watcher_x.h"
23 #include "ui/gfx/gtk_util.h"
24 #include "ui/gfx/image/image.h"
25 #include "ui/gfx/rect.h"
26
27 using apps::ShellWindow;
28
29 namespace {
30
31 // The timeout in milliseconds before we'll get the true window position with
32 // gtk_window_get_position() after the last GTK configure-event signal.
33 const int kDebounceTimeoutMilliseconds = 100;
34
35 const char* kAtomsToCache[] = {
36 "_NET_WM_STATE",
37 "_NET_WM_STATE_HIDDEN",
38 NULL
39 };
40
41 } // namespace
42
43 NativeAppWindowGtk::NativeAppWindowGtk(ShellWindow* shell_window,
44 const ShellWindow::CreateParams& params)
45 : shell_window_(shell_window),
46 window_(NULL),
47 state_(GDK_WINDOW_STATE_WITHDRAWN),
48 is_active_(false),
49 content_thinks_its_fullscreen_(false),
50 frameless_(params.frame == ShellWindow::FRAME_NONE),
51 frame_cursor_(NULL),
52 atom_cache_(base::MessagePumpGtk::GetDefaultXDisplay(), kAtomsToCache),
53 is_x_event_listened_(false) {
54 window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
55
56 gfx::NativeView native_view =
57 web_contents()->GetView()->GetNativeView();
58 gtk_container_add(GTK_CONTAINER(window_), native_view);
59
60 if (params.bounds.x() != INT_MIN && params.bounds.y() != INT_MIN)
61 gtk_window_move(window_, params.bounds.x(), params.bounds.y());
62
63 // This is done to avoid a WM "feature" where setting the window size to
64 // the monitor size causes the WM to set the EWMH for full screen mode.
65 int win_height = params.bounds.height();
66 if (frameless_ &&
67 gtk_window_util::BoundsMatchMonitorSize(window_, params.bounds)) {
68 win_height -= 1;
69 }
70 gtk_window_set_default_size(window_, params.bounds.width(), win_height);
71
72 resizable_ = params.resizable;
73 if (!resizable_) {
74 // If the window doesn't have a size request when we set resizable to
75 // false, GTK will shrink the window to 1x1px.
76 gtk_widget_set_size_request(GTK_WIDGET(window_),
77 params.bounds.width(), win_height);
78 gtk_window_set_resizable(window_, FALSE);
79 }
80
81 // make sure bounds_ and restored_bounds_ have correct values until we
82 // get our first configure-event
83 bounds_ = restored_bounds_ = params.bounds;
84 gint x, y;
85 gtk_window_get_position(window_, &x, &y);
86 bounds_.set_origin(gfx::Point(x, y));
87
88 // Hide titlebar when {frame: 'none'} specified on ShellWindow.
89 if (frameless_)
90 gtk_window_set_decorated(window_, false);
91
92 int min_width = params.minimum_size.width();
93 int min_height = params.minimum_size.height();
94 int max_width = params.maximum_size.width();
95 int max_height = params.maximum_size.height();
96 GdkGeometry hints;
97 int hints_mask = 0;
98 if (min_width || min_height) {
99 hints.min_height = min_height;
100 hints.min_width = min_width;
101 hints_mask |= GDK_HINT_MIN_SIZE;
102 }
103 if (max_width || max_height) {
104 hints.max_height = max_height ? max_height : G_MAXINT;
105 hints.max_width = max_width ? max_width : G_MAXINT;
106 hints_mask |= GDK_HINT_MAX_SIZE;
107 }
108 if (hints_mask) {
109 gtk_window_set_geometry_hints(
110 window_,
111 GTK_WIDGET(window_),
112 &hints,
113 static_cast<GdkWindowHints>(hints_mask));
114 }
115
116 // In some (older) versions of compiz, raising top-level windows when they
117 // are partially off-screen causes them to get snapped back on screen, not
118 // always even on the current virtual desktop. If we are running under
119 // compiz, suppress such raises, as they are not necessary in compiz anyway.
120 if (ui::GuessWindowManager() == ui::WM_COMPIZ)
121 suppress_window_raise_ = true;
122
123 gtk_window_set_title(window_, extension()->name().c_str());
124
125 std::string app_name = web_app::GenerateApplicationNameFromExtensionId(
126 extension()->id());
127 gtk_window_util::SetWindowCustomClass(window_,
128 web_app::GetWMClassFromAppName(app_name));
129
130 g_signal_connect(window_, "delete-event",
131 G_CALLBACK(OnMainWindowDeleteEventThunk), this);
132 g_signal_connect(window_, "configure-event",
133 G_CALLBACK(OnConfigureThunk), this);
134 g_signal_connect(window_, "window-state-event",
135 G_CALLBACK(OnWindowStateThunk), this);
136 if (frameless_) {
137 g_signal_connect(window_, "button-press-event",
138 G_CALLBACK(OnButtonPressThunk), this);
139 g_signal_connect(window_, "motion-notify-event",
140 G_CALLBACK(OnMouseMoveEventThunk), this);
141 }
142
143 // If _NET_WM_STATE_HIDDEN is in _NET_SUPPORTED, listen for XEvent to work
144 // around GTK+ not reporting minimization state changes. See comment in the
145 // |OnXEvent|.
146 std::vector< ::Atom> supported_atoms;
147 if (ui::GetAtomArrayProperty(ui::GetX11RootWindow(),
148 "_NET_SUPPORTED",
149 &supported_atoms)) {
150 if (std::find(supported_atoms.begin(),
151 supported_atoms.end(),
152 atom_cache_.GetAtom("_NET_WM_STATE_HIDDEN")) !=
153 supported_atoms.end()) {
154 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(window_));
155 gdk_window_add_filter(window,
156 &NativeAppWindowGtk::OnXEventThunk,
157 this);
158 is_x_event_listened_ = true;
159 }
160 }
161
162 // Add the keybinding registry.
163 extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryGtk(
164 shell_window_->profile(),
165 window_,
166 extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY,
167 shell_window_));
168
169 ui::ActiveWindowWatcherX::AddObserver(this);
170 }
171
172 NativeAppWindowGtk::~NativeAppWindowGtk() {
173 ui::ActiveWindowWatcherX::RemoveObserver(this);
174 if (is_x_event_listened_) {
175 gdk_window_remove_filter(NULL,
176 &NativeAppWindowGtk::OnXEventThunk,
177 this);
178 }
179 }
180
181 bool NativeAppWindowGtk::IsActive() const {
182 if (ui::ActiveWindowWatcherX::WMSupportsActivation())
183 return is_active_;
184
185 // This still works even though we don't get the activation notification.
186 return gtk_window_is_active(window_);
187 }
188
189 bool NativeAppWindowGtk::IsMaximized() const {
190 return (state_ & GDK_WINDOW_STATE_MAXIMIZED);
191 }
192
193 bool NativeAppWindowGtk::IsMinimized() const {
194 return (state_ & GDK_WINDOW_STATE_ICONIFIED);
195 }
196
197 bool NativeAppWindowGtk::IsFullscreen() const {
198 return (state_ & GDK_WINDOW_STATE_FULLSCREEN);
199 }
200
201 gfx::NativeWindow NativeAppWindowGtk::GetNativeWindow() {
202 return window_;
203 }
204
205 gfx::Rect NativeAppWindowGtk::GetRestoredBounds() const {
206 gfx::Rect window_bounds = restored_bounds_;
207 window_bounds.Inset(-GetFrameInsets());
208 return window_bounds;
209 }
210
211 ui::WindowShowState NativeAppWindowGtk::GetRestoredState() const {
212 if (IsMaximized())
213 return ui::SHOW_STATE_MAXIMIZED;
214 return ui::SHOW_STATE_NORMAL;
215 }
216
217 gfx::Rect NativeAppWindowGtk::GetBounds() const {
218 gfx::Rect window_bounds = bounds_;
219 window_bounds.Inset(-GetFrameInsets());
220 return window_bounds;
221 }
222
223 void NativeAppWindowGtk::Show() {
224 gtk_window_present(window_);
225 }
226
227 void NativeAppWindowGtk::ShowInactive() {
228 gtk_window_set_focus_on_map(window_, false);
229 gtk_widget_show(GTK_WIDGET(window_));
230 }
231
232 void NativeAppWindowGtk::Hide() {
233 gtk_widget_hide(GTK_WIDGET(window_));
234 }
235
236 void NativeAppWindowGtk::Close() {
237 shell_window_->OnNativeWindowChanged();
238
239 // Cancel any pending callback from the window configure debounce timer.
240 window_configure_debounce_timer_.Stop();
241
242 GtkWidget* window = GTK_WIDGET(window_);
243 // To help catch bugs in any event handlers that might get fired during the
244 // destruction, set window_ to NULL before any handlers will run.
245 window_ = NULL;
246
247 // OnNativeClose does a delete this so no other members should
248 // be accessed after. gtk_widget_destroy is safe (and must
249 // be last).
250 shell_window_->OnNativeClose();
251 gtk_widget_destroy(window);
252 }
253
254 void NativeAppWindowGtk::Activate() {
255 gtk_window_present(window_);
256 }
257
258 void NativeAppWindowGtk::Deactivate() {
259 gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(window_)));
260 }
261
262 void NativeAppWindowGtk::Maximize() {
263 // Represent the window first in order to keep the maximization behavior
264 // consistency with Windows platform. Otherwise the window will be hidden if
265 // it has been minimized.
266 gtk_window_present(window_);
267 gtk_window_maximize(window_);
268 }
269
270 void NativeAppWindowGtk::Minimize() {
271 gtk_window_iconify(window_);
272 }
273
274 void NativeAppWindowGtk::Restore() {
275 if (IsMaximized())
276 gtk_window_unmaximize(window_);
277 else if (IsMinimized())
278 gtk_window_deiconify(window_);
279
280 // Represent the window to keep restoration behavior consistency with Windows
281 // platform.
282 // TODO(zhchbin): verify whether we need this until http://crbug.com/261013 is
283 // fixed.
284 gtk_window_present(window_);
285 }
286
287 void NativeAppWindowGtk::SetBounds(const gfx::Rect& bounds) {
288 gfx::Rect content_bounds = bounds;
289 content_bounds.Inset(GetFrameInsets());
290 gtk_window_move(window_, content_bounds.x(), content_bounds.y());
291 if (!resizable_) {
292 if (frameless_ &&
293 gtk_window_util::BoundsMatchMonitorSize(window_, content_bounds)) {
294 content_bounds.set_height(content_bounds.height() - 1);
295 }
296 // TODO(jeremya): set_size_request doesn't honor min/max size, so the
297 // bounds should be constrained manually.
298 gtk_widget_set_size_request(GTK_WIDGET(window_),
299 content_bounds.width(), content_bounds.height());
300 } else {
301 gtk_window_util::SetWindowSize(window_,
302 gfx::Size(bounds.width(), bounds.height()));
303 }
304 }
305
306 GdkFilterReturn NativeAppWindowGtk::OnXEvent(GdkXEvent* gdk_x_event,
307 GdkEvent* gdk_event) {
308 // Work around GTK+ not reporting minimization state changes. Listen
309 // for _NET_WM_STATE property changes and use _NET_WM_STATE_HIDDEN's
310 // presence to set or clear the iconified bit if _NET_WM_STATE_HIDDEN
311 // is supported. http://crbug.com/162794.
312 XEvent* x_event = static_cast<XEvent*>(gdk_x_event);
313 std::vector< ::Atom> atom_list;
314
315 if (x_event->type == PropertyNotify &&
316 x_event->xproperty.atom == atom_cache_.GetAtom("_NET_WM_STATE") &&
317 ui::GetAtomArrayProperty(GDK_WINDOW_XWINDOW(GTK_WIDGET(window_)->window),
318 "_NET_WM_STATE",
319 &atom_list)) {
320 std::vector< ::Atom>::iterator it =
321 std::find(atom_list.begin(),
322 atom_list.end(),
323 atom_cache_.GetAtom("_NET_WM_STATE_HIDDEN"));
324 state_ = (it != atom_list.end()) ? GDK_WINDOW_STATE_ICONIFIED :
325 static_cast<GdkWindowState>(state_ & ~GDK_WINDOW_STATE_ICONIFIED);
326
327 shell_window_->OnNativeWindowChanged();
328 }
329
330 return GDK_FILTER_CONTINUE;
331 }
332
333 void NativeAppWindowGtk::FlashFrame(bool flash) {
334 gtk_window_set_urgency_hint(window_, flash);
335 }
336
337 bool NativeAppWindowGtk::IsAlwaysOnTop() const {
338 return false;
339 }
340
341 void NativeAppWindowGtk::RenderViewHostChanged() {
342 web_contents()->GetView()->Focus();
343 }
344
345 gfx::Insets NativeAppWindowGtk::GetFrameInsets() const {
346 if (frameless_)
347 return gfx::Insets();
348 GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
349 if (!gdk_window)
350 return gfx::Insets();
351
352 gint current_width = 0;
353 gint current_height = 0;
354 gtk_window_get_size(window_, &current_width, &current_height);
355 gint current_x = 0;
356 gint current_y = 0;
357 gdk_window_get_position(gdk_window, &current_x, &current_y);
358 GdkRectangle rect_with_decorations = {0};
359 gdk_window_get_frame_extents(gdk_window,
360 &rect_with_decorations);
361
362 int left_inset = current_x - rect_with_decorations.x;
363 int top_inset = current_y - rect_with_decorations.y;
364 return gfx::Insets(
365 top_inset,
366 left_inset,
367 rect_with_decorations.height - current_height - top_inset,
368 rect_with_decorations.width - current_width - left_inset);
369 }
370
371 gfx::NativeView NativeAppWindowGtk::GetHostView() const {
372 NOTIMPLEMENTED();
373 return NULL;
374 }
375
376 gfx::Point NativeAppWindowGtk::GetDialogPosition(const gfx::Size& size) {
377 gint current_width = 0;
378 gint current_height = 0;
379 gtk_window_get_size(window_, &current_width, &current_height);
380 return gfx::Point(current_width / 2 - size.width() / 2,
381 current_height / 2 - size.height() / 2);
382 }
383
384 void NativeAppWindowGtk::AddObserver(
385 web_modal::WebContentsModalDialogHostObserver* observer) {
386 observer_list_.AddObserver(observer);
387 }
388
389 void NativeAppWindowGtk::RemoveObserver(
390 web_modal::WebContentsModalDialogHostObserver* observer) {
391 observer_list_.RemoveObserver(observer);
392 }
393
394 void NativeAppWindowGtk::ActiveWindowChanged(GdkWindow* active_window) {
395 // Do nothing if we're in the process of closing the browser window.
396 if (!window_)
397 return;
398
399 is_active_ = gtk_widget_get_window(GTK_WIDGET(window_)) == active_window;
400 if (is_active_)
401 shell_window_->OnNativeWindowActivated();
402 }
403
404 // Callback for the delete event. This event is fired when the user tries to
405 // close the window (e.g., clicking on the X in the window manager title bar).
406 gboolean NativeAppWindowGtk::OnMainWindowDeleteEvent(GtkWidget* widget,
407 GdkEvent* event) {
408 Close();
409
410 // Return true to prevent the GTK window from being destroyed. Close will
411 // destroy it for us.
412 return TRUE;
413 }
414
415 gboolean NativeAppWindowGtk::OnConfigure(GtkWidget* widget,
416 GdkEventConfigure* event) {
417 // We update |bounds_| but not |restored_bounds_| here. The latter needs
418 // to be updated conditionally when the window is non-maximized and non-
419 // fullscreen, but whether those state updates have been processed yet is
420 // window-manager specific. We update |restored_bounds_| in the debounced
421 // handler below, after the window state has been updated.
422 bounds_.SetRect(event->x, event->y, event->width, event->height);
423
424 // The GdkEventConfigure* we get here doesn't have quite the right
425 // coordinates though (they're relative to the drawable window area, rather
426 // than any window manager decorations, if enabled), so we need to call
427 // gtk_window_get_position() to get the right values. (Otherwise session
428 // restore, if enabled, will restore windows to incorrect positions.) That's
429 // a round trip to the X server though, so we set a debounce timer and only
430 // call it (in OnConfigureDebounced() below) after we haven't seen a
431 // reconfigure event in a short while.
432 // We don't use Reset() because the timer may not yet be running.
433 // (In that case Stop() is a no-op.)
434 window_configure_debounce_timer_.Stop();
435 window_configure_debounce_timer_.Start(FROM_HERE,
436 base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds), this,
437 &NativeAppWindowGtk::OnConfigureDebounced);
438
439 return FALSE;
440 }
441
442 void NativeAppWindowGtk::OnConfigureDebounced() {
443 gtk_window_util::UpdateWindowPosition(this, &bounds_, &restored_bounds_);
444 shell_window_->OnNativeWindowChanged();
445
446 FOR_EACH_OBSERVER(web_modal::WebContentsModalDialogHostObserver,
447 observer_list_,
448 OnPositionRequiresUpdate());
449
450 // Fullscreen of non-resizable windows requires them to be made resizable
451 // first. After that takes effect and OnConfigure is called we transition
452 // to fullscreen.
453 if (!IsFullscreen() && IsFullscreenOrPending()) {
454 gtk_window_fullscreen(window_);
455 }
456 }
457
458 gboolean NativeAppWindowGtk::OnWindowState(GtkWidget* sender,
459 GdkEventWindowState* event) {
460 state_ = event->new_window_state;
461
462 if (content_thinks_its_fullscreen_ &&
463 !(state_ & GDK_WINDOW_STATE_FULLSCREEN)) {
464 content_thinks_its_fullscreen_ = false;
465 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
466 if (rvh)
467 rvh->ExitFullscreen();
468 }
469
470 return FALSE;
471 }
472
473 bool NativeAppWindowGtk::GetWindowEdge(int x, int y, GdkWindowEdge* edge) {
474 if (!frameless_)
475 return false;
476
477 if (IsMaximized() || IsFullscreen())
478 return false;
479
480 return gtk_window_util::GetWindowEdge(bounds_.size(), 0, x, y, edge);
481 }
482
483 gboolean NativeAppWindowGtk::OnMouseMoveEvent(GtkWidget* widget,
484 GdkEventMotion* event) {
485 if (!frameless_) {
486 // Reset the cursor.
487 if (frame_cursor_) {
488 frame_cursor_ = NULL;
489 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)), NULL);
490 }
491 return FALSE;
492 }
493
494 if (!resizable_)
495 return FALSE;
496
497 // Update the cursor if we're on the custom frame border.
498 GdkWindowEdge edge;
499 bool has_hit_edge = GetWindowEdge(static_cast<int>(event->x),
500 static_cast<int>(event->y), &edge);
501 GdkCursorType new_cursor = GDK_LAST_CURSOR;
502 if (has_hit_edge)
503 new_cursor = gtk_window_util::GdkWindowEdgeToGdkCursorType(edge);
504
505 GdkCursorType last_cursor = GDK_LAST_CURSOR;
506 if (frame_cursor_)
507 last_cursor = frame_cursor_->type;
508
509 if (last_cursor != new_cursor) {
510 frame_cursor_ = has_hit_edge ? gfx::GetCursor(new_cursor) : NULL;
511 gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)),
512 frame_cursor_);
513 }
514 return FALSE;
515 }
516
517 gboolean NativeAppWindowGtk::OnButtonPress(GtkWidget* widget,
518 GdkEventButton* event) {
519 DCHECK(frameless_);
520 // Make the button press coordinate relative to the browser window.
521 int win_x, win_y;
522 GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_));
523 gdk_window_get_origin(gdk_window, &win_x, &win_y);
524
525 GdkWindowEdge edge;
526 gfx::Point point(static_cast<int>(event->x_root - win_x),
527 static_cast<int>(event->y_root - win_y));
528 bool has_hit_edge = resizable_ && GetWindowEdge(point.x(), point.y(), &edge);
529 bool has_hit_titlebar =
530 draggable_region_ && draggable_region_->contains(event->x, event->y);
531
532 if (event->button == 1) {
533 if (GDK_BUTTON_PRESS == event->type) {
534 // Raise the window after a click on either the titlebar or the border to
535 // match the behavior of most window managers, unless that behavior has
536 // been suppressed.
537 if ((has_hit_titlebar || has_hit_edge) && !suppress_window_raise_)
538 gdk_window_raise(GTK_WIDGET(widget)->window);
539
540 if (has_hit_edge) {
541 gtk_window_begin_resize_drag(window_, edge, event->button,
542 static_cast<gint>(event->x_root),
543 static_cast<gint>(event->y_root),
544 event->time);
545 return TRUE;
546 } else if (has_hit_titlebar) {
547 return gtk_window_util::HandleTitleBarLeftMousePress(
548 window_, bounds_, event);
549 }
550 } else if (GDK_2BUTTON_PRESS == event->type) {
551 if (has_hit_titlebar && resizable_) {
552 // Maximize/restore on double click.
553 if (IsMaximized()) {
554 gtk_window_util::UnMaximize(GTK_WINDOW(widget),
555 bounds_, restored_bounds_);
556 } else {
557 gtk_window_maximize(window_);
558 }
559 return TRUE;
560 }
561 }
562 } else if (event->button == 2) {
563 if (has_hit_titlebar || has_hit_edge)
564 gdk_window_lower(gdk_window);
565 return TRUE;
566 }
567
568 return FALSE;
569 }
570
571 void NativeAppWindowGtk::SetFullscreen(bool fullscreen) {
572 content_thinks_its_fullscreen_ = fullscreen;
573 if (fullscreen){
574 if (resizable_) {
575 gtk_window_fullscreen(window_);
576 } else {
577 // We must first make the window resizable. That won't take effect
578 // immediately, so OnConfigureDebounced completes the fullscreen call.
579 gtk_window_set_resizable(window_, TRUE);
580 }
581 } else {
582 gtk_window_unfullscreen(window_);
583 if (!resizable_)
584 gtk_window_set_resizable(window_, FALSE);
585 }
586 }
587
588 bool NativeAppWindowGtk::IsFullscreenOrPending() const {
589 return content_thinks_its_fullscreen_;
590 }
591
592 bool NativeAppWindowGtk::IsDetached() const {
593 return false;
594 }
595
596 void NativeAppWindowGtk::UpdateWindowIcon() {
597 Profile* profile = shell_window_->profile();
598 gfx::Image app_icon = shell_window_->app_icon();
599 if (!app_icon.IsEmpty())
600 gtk_util::SetWindowIcon(window_, profile, app_icon.ToGdkPixbuf());
601 else
602 gtk_util::SetWindowIcon(window_, profile);
603 }
604
605 void NativeAppWindowGtk::UpdateWindowTitle() {
606 string16 title = shell_window_->GetTitle();
607 gtk_window_set_title(window_, UTF16ToUTF8(title).c_str());
608 }
609
610 void NativeAppWindowGtk::HandleKeyboardEvent(
611 const content::NativeWebKeyboardEvent& event) {
612 // No-op.
613 }
614
615 void NativeAppWindowGtk::UpdateDraggableRegions(
616 const std::vector<extensions::DraggableRegion>& regions) {
617 // Draggable region is not supported for non-frameless window.
618 if (!frameless_)
619 return;
620
621 draggable_region_.reset(ShellWindow::RawDraggableRegionsToSkRegion(regions));
622 }
623
624 // static
625 NativeAppWindow* NativeAppWindow::Create(
626 ShellWindow* shell_window,
627 const ShellWindow::CreateParams& params) {
628 return new NativeAppWindowGtk(shell_window, params);
629 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698