12385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "chrome/browser/ui/gtk/apps/native_app_window_gtk.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <gdk/gdkx.h> 8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include <vector> 9ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_pump_gtk.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/extensions/extension_keybinding_registry_gtk.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_util.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_window_util.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/web_applications/web_app.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_widget_host_view.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents_view.h" 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/x/active_window_watcher_x.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/gtk_util.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing apps::ShellWindow; 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The timeout in milliseconds before we'll get the true window position with 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// gtk_window_get_position() after the last GTK configure-event signal. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDebounceTimeoutMilliseconds = 100; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochconst char* kAtomsToCache[] = { 36ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch "_NET_WM_STATE", 37ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch "_NET_WM_STATE_HIDDEN", 38ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch NULL 39ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}; 40ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NativeAppWindowGtk::NativeAppWindowGtk(ShellWindow* shell_window, 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ShellWindow::CreateParams& params) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : shell_window_(shell_window), 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_(NULL), 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_(GDK_WINDOW_STATE_WITHDRAWN), 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_active_(false), 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_thinks_its_fullscreen_(false), 501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) maximize_pending_(false), 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frameless_(params.frame == ShellWindow::FRAME_NONE), 524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) always_on_top_(params.always_on_top), 53ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch frame_cursor_(NULL), 54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch atom_cache_(base::MessagePumpGtk::GetDefaultXDisplay(), kAtomsToCache), 55ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch is_x_event_listened_(false) { 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Observe(web_contents()); 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::NativeView native_view = 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_contents()->GetView()->GetNativeView(); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_container_add(GTK_CONTAINER(window_), native_view); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (params.bounds.x() != INT_MIN && params.bounds.y() != INT_MIN) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_move(window_, params.bounds.x(), params.bounds.y()); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is done to avoid a WM "feature" where setting the window size to 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the monitor size causes the WM to set the EWMH for full screen mode. 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int win_height = params.bounds.height(); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frameless_ && 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_util::BoundsMatchMonitorSize(window_, params.bounds)) { 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) win_height -= 1; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_window_set_default_size(window_, params.bounds.width(), win_height); 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) resizable_ = params.resizable; 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!resizable_) { 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the window doesn't have a size request when we set resizable to 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // false, GTK will shrink the window to 1x1px. 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_widget_set_size_request(GTK_WIDGET(window_), 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params.bounds.width(), win_height); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_window_set_resizable(window_, FALSE); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // make sure bounds_ and restored_bounds_ have correct values until we 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // get our first configure-event 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_ = restored_bounds_ = params.bounds; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gint x, y; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_get_position(window_, &x, &y); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_.set_origin(gfx::Point(x, y)); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Hide titlebar when {frame: 'none'} specified on ShellWindow. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frameless_) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_set_decorated(window_, false); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (always_on_top_) 974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gtk_window_set_keep_above(window_, TRUE); 984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) UpdateWindowMinMaxSize(); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In some (older) versions of compiz, raising top-level windows when they 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are partially off-screen causes them to get snapped back on screen, not 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // always even on the current virtual desktop. If we are running under 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // compiz, suppress such raises, as they are not necessary in compiz anyway. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::GuessWindowManager() == ui::WM_COMPIZ) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suppress_window_raise_ = true; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_set_title(window_, extension()->name().c_str()); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string app_name = web_app::GenerateApplicationNameFromExtensionId( 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension()->id()); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_util::SetWindowCustomClass(window_, 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) web_app::GetWMClassFromAppName(app_name)); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(window_, "delete-event", 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnMainWindowDeleteEventThunk), this); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(window_, "configure-event", 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnConfigureThunk), this); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(window_, "window-state-event", 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnWindowStateThunk), this); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frameless_) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_signal_connect(window_, "button-press-event", 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) G_CALLBACK(OnButtonPressThunk), this); 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) g_signal_connect(window_, "motion-notify-event", 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) G_CALLBACK(OnMouseMoveEventThunk), this); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 128ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // If _NET_WM_STATE_HIDDEN is in _NET_SUPPORTED, listen for XEvent to work 129ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // around GTK+ not reporting minimization state changes. See comment in the 130ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // |OnXEvent|. 131ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::vector< ::Atom> supported_atoms; 132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (ui::GetAtomArrayProperty(ui::GetX11RootWindow(), 133ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch "_NET_SUPPORTED", 134ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch &supported_atoms)) { 135ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (std::find(supported_atoms.begin(), 136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch supported_atoms.end(), 137ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch atom_cache_.GetAtom("_NET_WM_STATE_HIDDEN")) != 138ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch supported_atoms.end()) { 139ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(window_)); 140ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch gdk_window_add_filter(window, 141ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch &NativeAppWindowGtk::OnXEventThunk, 142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this); 143ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch is_x_event_listened_ = true; 144ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 145ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 146ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add the keybinding registry. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryGtk( 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shell_window_->profile(), 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_, 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY, 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shell_window_)); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ActiveWindowWatcherX::AddObserver(this); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NativeAppWindowGtk::~NativeAppWindowGtk() { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ActiveWindowWatcherX::RemoveObserver(this); 159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (is_x_event_listened_) { 160ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch gdk_window_remove_filter(NULL, 161ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch &NativeAppWindowGtk::OnXEventThunk, 162ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch this); 163ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NativeAppWindowGtk::IsActive() const { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::ActiveWindowWatcherX::WMSupportsActivation()) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return is_active_; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This still works even though we don't get the activation notification. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gtk_window_is_active(window_); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NativeAppWindowGtk::IsMaximized() const { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (state_ & GDK_WINDOW_STATE_MAXIMIZED); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NativeAppWindowGtk::IsMinimized() const { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (state_ & GDK_WINDOW_STATE_ICONIFIED); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NativeAppWindowGtk::IsFullscreen() const { 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return (state_ & GDK_WINDOW_STATE_FULLSCREEN); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::NativeWindow NativeAppWindowGtk::GetNativeWindow() { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return window_; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect NativeAppWindowGtk::GetRestoredBounds() const { 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect window_bounds = restored_bounds_; 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) window_bounds.Inset(-GetFrameInsets()); 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return window_bounds; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 196b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)ui::WindowShowState NativeAppWindowGtk::GetRestoredState() const { 197b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (IsMaximized()) 198b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return ui::SHOW_STATE_MAXIMIZED; 19968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (IsFullscreen()) 20068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return ui::SHOW_STATE_FULLSCREEN; 201b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return ui::SHOW_STATE_NORMAL; 202b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 203b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect NativeAppWindowGtk::GetBounds() const { 205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // :GetBounds() is expecting the outer window bounds to be returned (ie. 206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // including window decorations). The internal |bounds_| is not including them 207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // and trying to add the decoration to |bounds_| would require calling 208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // gdk_window_get_frame_extents. The best thing to do is to directly get the 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // frame bounds and only use the internal value if we can't. 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_)); 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!gdk_window) 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return bounds_; 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GdkRectangle window_bounds = {0}; 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gdk_window_get_frame_extents(gdk_window, &window_bounds); 216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return gfx::Rect(window_bounds.x, window_bounds.y, 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) window_bounds.width, window_bounds.height); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::Show() { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_present(window_); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::ShowInactive() { 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_set_focus_on_map(window_, false); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_show(GTK_WIDGET(window_)); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::Hide() { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_hide(GTK_WIDGET(window_)); 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::Close() { 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) shell_window_->OnNativeWindowChanged(); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Cancel any pending callback from the window configure debounce timer. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_configure_debounce_timer_.Stop(); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* window = GTK_WIDGET(window_); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To help catch bugs in any event handlers that might get fired during the 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // destruction, set window_ to NULL before any handlers will run. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_ = NULL; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // OnNativeClose does a delete this so no other members should 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be accessed after. gtk_widget_destroy is safe (and must 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // be last). 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shell_window_->OnNativeClose(); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_widget_destroy(window); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::Activate() { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_present(window_); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::Deactivate() { 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(window_))); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::Maximize() { 260ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Represent the window first in order to keep the maximization behavior 261ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // consistency with Windows platform. Otherwise the window will be hidden if 262ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // it has been minimized. 263ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch gtk_window_present(window_); 2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!resizable_) { 2661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // When the window is not resizable, we still want to make this call succeed 2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // but gtk will not allow it if the window is not resizable. The actual 2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // maximization will happen with the subsequent OnConfigureDebounced call, 2691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // that will be triggered when the window manager's resizable property 2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // changes. 2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) maximize_pending_ = true; 2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) gtk_window_set_resizable(window_, TRUE); 2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else { 2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) gtk_window_maximize(window_); 2751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::Minimize() { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_iconify(window_); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::Restore() { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsMaximized()) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_unmaximize(window_); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (IsMinimized()) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_deiconify(window_); 287ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Represent the window to keep restoration behavior consistency with Windows 289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // platform. 290ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // TODO(zhchbin): verify whether we need this until http://crbug.com/261013 is 291ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // fixed. 292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch gtk_window_present(window_); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::SetBounds(const gfx::Rect& bounds) { 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect content_bounds = bounds; 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_window_move(window_, content_bounds.x(), content_bounds.y()); 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!resizable_) { 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (frameless_ && 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_window_util::BoundsMatchMonitorSize(window_, content_bounds)) { 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content_bounds.set_height(content_bounds.height() - 1); 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(jeremya): set_size_request doesn't honor min/max size, so the 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // bounds should be constrained manually. 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_widget_set_size_request(GTK_WIDGET(window_), 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content_bounds.width(), content_bounds.height()); 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_window_util::SetWindowSize(window_, 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size(bounds.width(), bounds.height())); 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 313ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochGdkFilterReturn NativeAppWindowGtk::OnXEvent(GdkXEvent* gdk_x_event, 314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch GdkEvent* gdk_event) { 315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Work around GTK+ not reporting minimization state changes. Listen 316ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // for _NET_WM_STATE property changes and use _NET_WM_STATE_HIDDEN's 317ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // presence to set or clear the iconified bit if _NET_WM_STATE_HIDDEN 318ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // is supported. http://crbug.com/162794. 319ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch XEvent* x_event = static_cast<XEvent*>(gdk_x_event); 320ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::vector< ::Atom> atom_list; 321ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 322ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (x_event->type == PropertyNotify && 323ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch x_event->xproperty.atom == atom_cache_.GetAtom("_NET_WM_STATE") && 3240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) GTK_WIDGET(window_)->window && 325ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch ui::GetAtomArrayProperty(GDK_WINDOW_XWINDOW(GTK_WIDGET(window_)->window), 326ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch "_NET_WM_STATE", 327ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch &atom_list)) { 328ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::vector< ::Atom>::iterator it = 329ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::find(atom_list.begin(), 330ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch atom_list.end(), 331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch atom_cache_.GetAtom("_NET_WM_STATE_HIDDEN")); 332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GdkWindowState previous_state = state_; 334ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch state_ = (it != atom_list.end()) ? GDK_WINDOW_STATE_ICONIFIED : 335ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch static_cast<GdkWindowState>(state_ & ~GDK_WINDOW_STATE_ICONIFIED); 336ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (previous_state != state_) { 338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) shell_window_->OnNativeWindowChanged(); 339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 340ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 341ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 342ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return GDK_FILTER_CONTINUE; 343ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch} 344ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::FlashFrame(bool flash) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_set_urgency_hint(window_, flash); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NativeAppWindowGtk::IsAlwaysOnTop() const { 3504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return always_on_top_; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void NativeAppWindowGtk::RenderViewHostChanged( 3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) content::RenderViewHost* old_host, 3554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) content::RenderViewHost* new_host) { 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) web_contents()->GetView()->Focus(); 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void NativeAppWindowGtk::SetAlwaysOnTop(bool always_on_top) { 3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (always_on_top_ != always_on_top) { 3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // gdk_window_get_state() does not give us the correct value for the 3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // GDK_WINDOW_STATE_ABOVE bit. Cache the current state. 3634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) always_on_top_ = always_on_top; 3644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gtk_window_set_keep_above(window_, always_on_top_ ? TRUE : FALSE); 3654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 368a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)gfx::NativeView NativeAppWindowGtk::GetHostView() const { 369a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) NOTIMPLEMENTED(); 370a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return NULL; 371a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 372a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)gfx::Point NativeAppWindowGtk::GetDialogPosition(const gfx::Size& size) { 374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gint current_width = 0; 375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gint current_height = 0; 376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gtk_window_get_size(window_, ¤t_width, ¤t_height); 377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return gfx::Point(current_width / 2 - size.width() / 2, 378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) current_height / 2 - size.height() / 2); 379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 38158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)gfx::Size NativeAppWindowGtk::GetMaximumDialogSize() { 38258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gint current_width = 0; 38358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gint current_height = 0; 38458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gtk_window_get_size(window_, ¤t_width, ¤t_height); 38558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return gfx::Size(current_width, current_height); 38658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 38758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void NativeAppWindowGtk::AddObserver( 3894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) web_modal::ModalDialogHostObserver* observer) { 390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) observer_list_.AddObserver(observer); 391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void NativeAppWindowGtk::RemoveObserver( 3944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) web_modal::ModalDialogHostObserver* observer) { 395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) observer_list_.RemoveObserver(observer); 396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::ActiveWindowChanged(GdkWindow* active_window) { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do nothing if we're in the process of closing the browser window. 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!window_) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_active_ = gtk_widget_get_window(GTK_WIDGET(window_)) == active_window; 40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (is_active_) 40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) shell_window_->OnNativeWindowActivated(); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callback for the delete event. This event is fired when the user tries to 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// close the window (e.g., clicking on the X in the window manager title bar). 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gboolean NativeAppWindowGtk::OnMainWindowDeleteEvent(GtkWidget* widget, 4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkEvent* event) { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Close(); 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return true to prevent the GTK window from being destroyed. Close will 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // destroy it for us. 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gboolean NativeAppWindowGtk::OnConfigure(GtkWidget* widget, 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkEventConfigure* event) { 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We update |bounds_| but not |restored_bounds_| here. The latter needs 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to be updated conditionally when the window is non-maximized and non- 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fullscreen, but whether those state updates have been processed yet is 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // window-manager specific. We update |restored_bounds_| in the debounced 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // handler below, after the window state has been updated. 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_.SetRect(event->x, event->y, event->width, event->height); 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The GdkEventConfigure* we get here doesn't have quite the right 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // coordinates though (they're relative to the drawable window area, rather 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // than any window manager decorations, if enabled), so we need to call 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // gtk_window_get_position() to get the right values. (Otherwise session 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // restore, if enabled, will restore windows to incorrect positions.) That's 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a round trip to the X server though, so we set a debounce timer and only 4347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // call it (in OnConfigureDebounced() below) after we haven't seen a 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reconfigure event in a short while. 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't use Reset() because the timer may not yet be running. 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (In that case Stop() is a no-op.) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_configure_debounce_timer_.Stop(); 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_configure_debounce_timer_.Start(FROM_HERE, 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds), this, 4417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch &NativeAppWindowGtk::OnConfigureDebounced); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid NativeAppWindowGtk::OnConfigureDebounced() { 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_util::UpdateWindowPosition(this, &bounds_, &restored_bounds_); 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) shell_window_->OnNativeWindowChanged(); 449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 4504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FOR_EACH_OBSERVER(web_modal::ModalDialogHostObserver, 451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) observer_list_, 452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OnPositionRequiresUpdate()); 4537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 4547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // Fullscreen of non-resizable windows requires them to be made resizable 4557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // first. After that takes effect and OnConfigure is called we transition 4567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // to fullscreen. 4577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!IsFullscreen() && IsFullscreenOrPending()) { 4587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch gtk_window_fullscreen(window_); 4597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 4601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 4611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // maximize_pending_ is the boolean that lets us know that the window is in 4621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // the process of being maximized but was set as not resizable. 4631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // This function will be called twice during the maximization process: 4641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // 1. gtk_window_maximize() is called to maximize the window; 4651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // 2. gtk_set_resizable(, FALSE) is called to make the window no longer 4661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // resizable. 4671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // gtk_window_maximize() will cause ::OnConfigureDebounced to be called 4681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // again, at which time we will run into the second step. 4691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (maximize_pending_) { 4701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!(state_ & GDK_WINDOW_STATE_MAXIMIZED)) { 4711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) gtk_window_maximize(window_); 4721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else { 4731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) maximize_pending_ = false; 4741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!resizable_) 4751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) gtk_window_set_resizable(window_, FALSE); 4761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gboolean NativeAppWindowGtk::OnWindowState(GtkWidget* sender, 4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkEventWindowState* event) { 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = event->new_window_state; 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (content_thinks_its_fullscreen_ && 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !(state_ & GDK_WINDOW_STATE_FULLSCREEN)) { 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_thinks_its_fullscreen_ = false; 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rvh) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rvh->ExitFullscreen(); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NativeAppWindowGtk::GetWindowEdge(int x, int y, GdkWindowEdge* edge) { 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!frameless_) 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (IsMaximized() || IsFullscreen()) 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gtk_window_util::GetWindowEdge(bounds_.size(), 0, x, y, edge); 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gboolean NativeAppWindowGtk::OnMouseMoveEvent(GtkWidget* widget, 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkEventMotion* event) { 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!frameless_) { 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Reset the cursor. 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (frame_cursor_) { 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame_cursor_ = NULL; 5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)), NULL); 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return FALSE; 5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!resizable_) 5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return FALSE; 5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Update the cursor if we're on the custom frame border. 5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkWindowEdge edge; 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool has_hit_edge = GetWindowEdge(static_cast<int>(event->x), 5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static_cast<int>(event->y), &edge); 5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkCursorType new_cursor = GDK_LAST_CURSOR; 5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (has_hit_edge) 5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new_cursor = gtk_window_util::GdkWindowEdgeToGdkCursorType(edge); 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkCursorType last_cursor = GDK_LAST_CURSOR; 5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (frame_cursor_) 5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_cursor = frame_cursor_->type; 5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (last_cursor != new_cursor) { 5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame_cursor_ = has_hit_edge ? gfx::GetCursor(new_cursor) : NULL; 5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window_)), 5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) frame_cursor_); 5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return FALSE; 5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gboolean NativeAppWindowGtk::OnButtonPress(GtkWidget* widget, 5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkEventButton* event) { 5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(frameless_); 5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make the button press coordinate relative to the browser window. 5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int win_x, win_y; 5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_)); 5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gdk_window_get_origin(gdk_window, &win_x, &win_y); 5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GdkWindowEdge edge; 5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Point point(static_cast<int>(event->x_root - win_x), 5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static_cast<int>(event->y_root - win_y)); 5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool has_hit_edge = resizable_ && GetWindowEdge(point.x(), point.y(), &edge); 5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool has_hit_titlebar = 5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) draggable_region_ && draggable_region_->contains(event->x, event->y); 5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (event->button == 1) { 5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (GDK_BUTTON_PRESS == event->type) { 5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Raise the window after a click on either the titlebar or the border to 5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // match the behavior of most window managers, unless that behavior has 5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // been suppressed. 5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((has_hit_titlebar || has_hit_edge) && !suppress_window_raise_) 5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gdk_window_raise(GTK_WIDGET(widget)->window); 5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (has_hit_edge) { 5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_window_begin_resize_drag(window_, edge, event->button, 5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static_cast<gint>(event->x_root), 5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static_cast<gint>(event->y_root), 5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event->time); 5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return TRUE; 5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (has_hit_titlebar) { 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gtk_window_util::HandleTitleBarLeftMousePress( 5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) window_, bounds_, event); 5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (GDK_2BUTTON_PRESS == event->type) { 5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (has_hit_titlebar && resizable_) { 5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Maximize/restore on double click. 5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (IsMaximized()) { 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_util::UnMaximize(GTK_WINDOW(widget), 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_, restored_bounds_); 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gtk_window_maximize(window_); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (event->button == 2) { 5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (has_hit_titlebar || has_hit_edge) 5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gdk_window_lower(gdk_window); 5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return TRUE; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// NativeAppWindow implementation: 5944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 595f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void NativeAppWindowGtk::SetFullscreen(int fullscreen_types) { 596f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool fullscreen = (fullscreen_types != ShellWindow::FULLSCREEN_TYPE_NONE); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_thinks_its_fullscreen_ = fullscreen; 598f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (fullscreen) { 5997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (resizable_) { 6007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch gtk_window_fullscreen(window_); 6017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } else { 6027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // We must first make the window resizable. That won't take effect 6037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch // immediately, so OnConfigureDebounced completes the fullscreen call. 6047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch gtk_window_set_resizable(window_, TRUE); 6057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 6067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } else { 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_unfullscreen(window_); 6087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!resizable_) 6097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch gtk_window_set_resizable(window_, FALSE); 6107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool NativeAppWindowGtk::IsFullscreenOrPending() const { 61468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // |content_thinks_its_fullscreen_| is used when transitioning, and when 61568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // the state change will not be made for some time. However, it is possible 61668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // for a state update to be made before the final fullscreen state comes. 61768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // In that case, |content_thinks_its_fullscreen_| will be cleared, but we 61868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // will fall back to |IsFullscreen| which will soon have the correct state. 61968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return content_thinks_its_fullscreen_ || IsFullscreen(); 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 622b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)bool NativeAppWindowGtk::IsDetached() const { 623b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return false; 624b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 625b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::UpdateWindowIcon() { 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = shell_window_->profile(); 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Image app_icon = shell_window_->app_icon(); 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!app_icon.IsEmpty()) 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::SetWindowIcon(window_, profile, app_icon.ToGdkPixbuf()); 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_util::SetWindowIcon(window_, profile); 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::UpdateWindowTitle() { 636a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 title = shell_window_->GetTitle(); 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtk_window_set_title(window_, UTF16ToUTF8(title).c_str()); 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void NativeAppWindowGtk::UpdateDraggableRegions( 6414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const std::vector<extensions::DraggableRegion>& regions) { 6424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Draggable region is not supported for non-frameless window. 6434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!frameless_) 6444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 6454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) draggable_region_.reset(ShellWindow::RawDraggableRegionsToSkRegion(regions)); 6474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)SkRegion* NativeAppWindowGtk::GetDraggableRegion() { 6504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return draggable_region_.get(); 6514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 653f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void NativeAppWindowGtk::UpdateShape(scoped_ptr<SkRegion> region) { 6544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) NOTIMPLEMENTED(); 6554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 6564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NativeAppWindowGtk::HandleKeyboardEvent( 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NativeWebKeyboardEvent& event) { 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No-op. 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool NativeAppWindowGtk::IsFrameless() const { 6634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return frameless_; 6643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)} 6653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 6664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)gfx::Insets NativeAppWindowGtk::GetFrameInsets() const { 6674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (frameless_) 6684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return gfx::Insets(); 6694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window_)); 6704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!gdk_window) 6714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return gfx::Insets(); 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gint current_width = 0; 6744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gint current_height = 0; 6754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gtk_window_get_size(window_, ¤t_width, ¤t_height); 6764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gint current_x = 0; 6774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gint current_y = 0; 6784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gdk_window_get_position(gdk_window, ¤t_x, ¤t_y); 6794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) GdkRectangle rect_with_decorations = {0}; 6804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) gdk_window_get_frame_extents(gdk_window, 6814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) &rect_with_decorations); 6824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int left_inset = current_x - rect_with_decorations.x; 6844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int top_inset = current_y - rect_with_decorations.y; 6854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return gfx::Insets( 6864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) top_inset, 6874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) left_inset, 6884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) rect_with_decorations.height - current_height - top_inset, 6894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) rect_with_decorations.width - current_width - left_inset); 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 6924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void NativeAppWindowGtk::HideWithApp() {} 6934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void NativeAppWindowGtk::ShowWithApp() {} 6948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 6958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void NativeAppWindowGtk::UpdateWindowMinMaxSize() { 6968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) GdkGeometry hints; 6978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int hints_mask = 0; 6988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (shell_window_->size_constraints().HasMinimumSize()) { 6998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) gfx::Size min_size = shell_window_->size_constraints().GetMinimumSize(); 7008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) hints.min_height = min_size.height(); 7018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) hints.min_width = min_size.width(); 7028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) hints_mask |= GDK_HINT_MIN_SIZE; 7038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 7048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (shell_window_->size_constraints().HasMaximumSize()) { 7058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) gfx::Size max_size = shell_window_->size_constraints().GetMaximumSize(); 7068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const int kUnboundedSize = ShellWindow::SizeConstraints::kUnboundedSize; 7078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) hints.max_height = max_size.height() == kUnboundedSize ? 7088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) G_MAXINT : max_size.height(); 7098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) hints.max_width = max_size.width() == kUnboundedSize ? 7108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) G_MAXINT : max_size.width(); 7118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) hints_mask |= GDK_HINT_MAX_SIZE; 7128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 7138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (hints_mask) { 7148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) gtk_window_set_geometry_hints( 7158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) window_, 7168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) GTK_WIDGET(window_), 7178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) &hints, 7188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) static_cast<GdkWindowHints>(hints_mask)); 7198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 7208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 721