Commit df801314 authored by Nicholas Hollingum's avatar Nicholas Hollingum Committed by Commit Bot

Launch xdg windows in maximized state if they are larger than the display.

Before the use of _NET_WM_STATE was common, windows would expect to be
maximized on launch if their size was larger than the display working
area. See
https://github.com/linuxmint/muffin/blob/f5778ba1433c3ac86f5aeb8fa7443baf600eb9db/src/core/place.c#L977

This change emultes that behaviour for CrOS. We add a callback in
widget initialization that we use to check the window size against
the display area, and maximize if necessary.

Bug: 994009
Change-Id: I0e6409a4c28eb9ea5071461c736a6fbf44f56606
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1788420
Commit-Queue: Nic Hollingum <hollingum@google.com>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#701025}
parent 445a1cdd
......@@ -239,6 +239,7 @@ source_set("unit_tests") {
"surface_unittest.cc",
"text_input_unittest.cc",
"touch_unittest.cc",
"xdg_shell_surface_unittest.cc",
]
deps += [
......
......@@ -21,6 +21,7 @@
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/transient_window_manager.h"
......@@ -265,6 +266,11 @@ void ShellSurface::StartResize(int component) {
AttemptToStartDrag(component);
}
bool ShellSurface::ShouldAutoMaximize() {
// Unless a child class overrides the behaviour, we will never auto-maximize.
return false;
}
////////////////////////////////////////////////////////////////////////////////
// SurfaceDelegate overrides:
......@@ -503,6 +509,10 @@ bool ShellSurface::OnPreWidgetCommit() {
return false;
}
// Allow the window to maximize itself on launch.
if (ShouldAutoMaximize())
initial_show_state_ = ui::SHOW_STATE_MAXIMIZED;
CreateShellSurfaceWidget(initial_show_state_);
}
......
......@@ -10,6 +10,7 @@
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "components/exo/shell_surface_base.h"
#include "ui/base/ui_base_types.h"
namespace ui {
class CompositorLock;
......@@ -81,6 +82,14 @@ class ShellSurface : public ShellSurfaceBase, public ash::WindowStateObserver {
// Start an interactive move of surface.
void StartMove();
// Before widget initialization, this method will be called. Depending on the
// implementation, it may return true to force the surface to launch in a
// maximized state.
virtual bool ShouldAutoMaximize();
// Return the initial show state for this surface.
ui::WindowShowState initial_show_state() { return initial_show_state_; }
// Overridden from SurfaceDelegate:
void OnSetParent(Surface* parent, const gfx::Point& position) override;
......@@ -163,7 +172,7 @@ class ShellSurface : public ShellSurfaceBase, public ash::WindowStateObserver {
gfx::Vector2d pending_origin_offset_accumulator_;
int resize_component_ = HTCAPTION; // HT constant (see ui/base/hit_test.h)
int pending_resize_component_ = HTCAPTION;
ui::WindowShowState initial_show_state_ = ui::SHOW_STATE_NORMAL;
ui::WindowShowState initial_show_state_ = ui::SHOW_STATE_DEFAULT;
bool ignore_window_bounds_changes_ = false;
DISALLOW_COPY_AND_ASSIGN(ShellSurface);
......
......@@ -4,6 +4,13 @@
#include "components/exo/xdg_shell_surface.h"
#include "ash/frame/non_client_frame_view_ash.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/window/caption_button_layout_constants.h"
namespace exo {
////////////////////////////////////////////////////////////////////////////////
......@@ -14,12 +21,33 @@ XdgShellSurface::XdgShellSurface(Surface* surface,
bool activatable,
bool can_minimize,
int container)
: ShellSurface(surface,
origin,
activatable,
can_minimize,
container) {}
: ShellSurface(surface, origin, activatable, can_minimize, container) {}
XdgShellSurface::~XdgShellSurface() {}
bool XdgShellSurface::ShouldAutoMaximize() {
if (initial_show_state() != ui::SHOW_STATE_DEFAULT || is_popup_ ||
!CanMaximize())
return false;
DCHECK(!widget_);
gfx::Size work_area_size = display::Screen::GetScreen()
->GetDisplayNearestWindow(host_window())
.work_area_size();
DCHECK(!work_area_size.IsEmpty());
gfx::Rect window_bounds = GetVisibleBounds();
// This way to predict the size of the widget if it were maximized is brittle.
// We rely on unit tests to guard against changes in the size of the window
// decorations.
if (frame_enabled()) {
window_bounds.Inset(0, 0, 0,
-views::GetCaptionButtonLayoutSize(
views::CaptionButtonLayoutSize::kNonBrowserCaption)
.height());
}
return window_bounds.width() >= work_area_size.width() &&
window_bounds.height() >= work_area_size.height();
}
} // namespace exo
......@@ -50,6 +50,11 @@ class XdgShellSurface : public ShellSurface {
int container);
~XdgShellSurface() override;
// Xdg surfaces have the behaviour that they should maximize themselves if
// their bounds are larger or equal to the display area. This behaviour is
// implemented in linux display managers (e.g. Muffin/Cinnamon).
bool ShouldAutoMaximize() override;
bool x_flipped() const { return x_flipped_; }
void set_x_flipped(bool flipped) { x_flipped_ = flipped; }
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/exo/xdg_shell_surface.h"
#include "components/exo/buffer.h"
#include "components/exo/display.h"
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace exo {
namespace {
struct SurfaceTriplet {
std::unique_ptr<Surface> surface;
std::unique_ptr<ShellSurface> shell_surface;
std::unique_ptr<Buffer> buffer;
};
class XdgShellSurfaceTest : public test::ExoTestBase {
protected:
SurfaceTriplet BuildSurface(int w, int h) {
auto surface = std::make_unique<Surface>();
auto shell_surface = std::make_unique<XdgShellSurface>(
surface.get(), gfx::Point{0, 0},
/*activatable=*/true,
/*can_minimize=*/true, ash::desks_util::GetActiveDeskContainerId());
auto buffer = std::make_unique<Buffer>(
exo_test_helper()->CreateGpuMemoryBuffer({w, h}));
surface->Attach(buffer.get());
return {std::move(surface), std::move(shell_surface), std::move(buffer)};
}
// Returns the size of the surface associated with a maximized widget. If the
// widget is |decorated| the size will be smaller due to the widget's
// decorations.
gfx::Size GetMaximizedSurfaceSize(bool decorated) {
SurfaceTriplet temp = BuildSurface(1, 1);
temp.surface->SetFrame(decorated ? SurfaceFrameType::NORMAL
: SurfaceFrameType::NONE);
temp.shell_surface->Maximize();
temp.surface->Commit();
EXPECT_TRUE(temp.shell_surface->GetWidget()->IsMaximized());
return temp.shell_surface->GetWidget()->client_view()->size();
}
};
// We don't actually care about the size of decorations. The purpose of this
// test is to ensure that enabling decorations in the way that we do actually
// causes the widget to be drawn with a (nonzero-sized) frame.
TEST_F(XdgShellSurfaceTest, DecoratedSurfaceSmallerThanUndecorated) {
gfx::Size undecorated_size = GetMaximizedSurfaceSize(false);
gfx::Size decorated_size = GetMaximizedSurfaceSize(true);
// The best expectation we can have is that the window decoration must be
// nonzero in one direction.
int decoration_width = undecorated_size.width() - decorated_size.width();
int decoration_height = undecorated_size.height() - decorated_size.height();
EXPECT_GE(decoration_width, 0);
EXPECT_GE(decoration_height, 0);
EXPECT_GT(decoration_width + decoration_height, 0);
}
TEST_F(XdgShellSurfaceTest, UndecoratedSurfaceAutoMaximizes) {
gfx::Size maximized_size = GetMaximizedSurfaceSize(/*decorated=*/false);
SurfaceTriplet max_surface =
BuildSurface(maximized_size.width(), maximized_size.height());
max_surface.surface->Commit();
EXPECT_TRUE(max_surface.shell_surface->GetWidget()->IsMaximized());
SurfaceTriplet narrow_surface =
BuildSurface(maximized_size.width() - 1, maximized_size.height());
narrow_surface.surface->Commit();
EXPECT_FALSE(narrow_surface.shell_surface->GetWidget()->IsMaximized());
SurfaceTriplet short_surface =
BuildSurface(maximized_size.width(), maximized_size.height() - 1);
short_surface.surface->Commit();
EXPECT_FALSE(short_surface.shell_surface->GetWidget()->IsMaximized());
}
TEST_F(XdgShellSurfaceTest, DecoratedSurfaceAutoMaximizes) {
gfx::Size maximized_size = GetMaximizedSurfaceSize(/*decorated=*/true);
SurfaceTriplet max_surface =
BuildSurface(maximized_size.width(), maximized_size.height());
max_surface.surface->SetFrame(SurfaceFrameType::NORMAL);
max_surface.surface->Commit();
EXPECT_TRUE(max_surface.shell_surface->GetWidget()->IsMaximized());
SurfaceTriplet narrow_surface =
BuildSurface(maximized_size.width() - 1, maximized_size.height());
narrow_surface.surface->SetFrame(SurfaceFrameType::NORMAL);
narrow_surface.surface->Commit();
EXPECT_FALSE(narrow_surface.shell_surface->GetWidget()->IsMaximized());
SurfaceTriplet short_surface =
BuildSurface(maximized_size.width(), maximized_size.height() - 1);
short_surface.surface->SetFrame(SurfaceFrameType::NORMAL);
short_surface.surface->Commit();
EXPECT_FALSE(short_surface.shell_surface->GetWidget()->IsMaximized());
}
TEST_F(XdgShellSurfaceTest, DontMaximizeIfStateWasModified) {
gfx::Size maximized_size = GetMaximizedSurfaceSize(/*decorated=*/true);
SurfaceTriplet test_surface =
BuildSurface(maximized_size.width() + 1, maximized_size.height() + 1);
// Explicitly restoring the window should prevent auto maximize.
test_surface.shell_surface->Restore();
test_surface.surface->Commit();
EXPECT_FALSE(test_surface.shell_surface->GetWidget()->IsMaximized());
}
} // namespace
} // namespace exo
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment