blob: d28b89dddda701f2522f73f794e67bca2e384bfc [file] [log] [blame]
// Copyright 2016 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 "ui/ozone/platform/wayland/wayland_window.h"
#include <wayland-client.h>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "ui/events/event.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v5.h"
#include "ui/ozone/platform/wayland/xdg_surface_wrapper_v6.h"
#include "ui/platform_window/platform_window_delegate.h"
namespace ui {
namespace {
// Factory, which decides which version type of xdg object to build.
class XDGShellObjectFactory {
public:
XDGShellObjectFactory() = default;
~XDGShellObjectFactory() = default;
std::unique_ptr<XDGSurfaceWrapper> CreateXDGSurface(
WaylandConnection* connection,
WaylandWindow* wayland_window) {
if (connection->shell_v6())
return base::MakeUnique<XDGSurfaceWrapperV6>(wayland_window);
DCHECK(connection->shell());
return base::MakeUnique<XDGSurfaceWrapperV5>(wayland_window);
}
private:
DISALLOW_COPY_AND_ASSIGN(XDGShellObjectFactory);
};
} // namespace
WaylandWindow::WaylandWindow(PlatformWindowDelegate* delegate,
WaylandConnection* connection,
const gfx::Rect& bounds)
: delegate_(delegate),
connection_(connection),
xdg_shell_objects_factory_(new XDGShellObjectFactory()),
bounds_(bounds) {}
WaylandWindow::~WaylandWindow() {
if (xdg_surface_) {
PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
connection_->RemoveWindow(surface_.id());
}
}
// static
WaylandWindow* WaylandWindow::FromSurface(wl_surface* surface) {
return static_cast<WaylandWindow*>(
wl_proxy_get_user_data(reinterpret_cast<wl_proxy*>(surface)));
}
bool WaylandWindow::Initialize() {
DCHECK(xdg_shell_objects_factory_);
surface_.reset(wl_compositor_create_surface(connection_->compositor()));
if (!surface_) {
LOG(ERROR) << "Failed to create wl_surface";
return false;
}
wl_surface_set_user_data(surface_.get(), this);
CreateXdgSurface();
connection_->ScheduleFlush();
connection_->AddWindow(surface_.id(), this);
PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
delegate_->OnAcceleratedWidgetAvailable(surface_.id(), 1.f);
return true;
}
void WaylandWindow::CreateXdgSurface() {
xdg_surface_ =
xdg_shell_objects_factory_->CreateXDGSurface(connection_, this);
if (!xdg_surface_ || !xdg_surface_->Initialize(connection_, surface_.get())) {
CHECK(false) << "Failed to create xdg_surface";
}
}
void WaylandWindow::ApplyPendingBounds() {
if (pending_bounds_.IsEmpty())
return;
SetBounds(pending_bounds_);
DCHECK(xdg_surface_);
xdg_surface_->SetWindowGeometry(bounds_);
xdg_surface_->AckConfigure();
pending_bounds_ = gfx::Rect();
connection_->ScheduleFlush();
}
void WaylandWindow::Show() {}
void WaylandWindow::Hide() {
NOTIMPLEMENTED();
}
void WaylandWindow::Close() {
NOTIMPLEMENTED();
}
void WaylandWindow::PrepareForShutdown() {}
void WaylandWindow::SetBounds(const gfx::Rect& bounds) {
if (bounds == bounds_)
return;
bounds_ = bounds;
delegate_->OnBoundsChanged(bounds);
}
gfx::Rect WaylandWindow::GetBounds() {
return bounds_;
}
void WaylandWindow::SetTitle(const base::string16& title) {
DCHECK(xdg_surface_);
xdg_surface_->SetTitle(title);
connection_->ScheduleFlush();
}
void WaylandWindow::SetCapture() {
NOTIMPLEMENTED();
}
void WaylandWindow::ReleaseCapture() {
NOTIMPLEMENTED();
}
void WaylandWindow::ToggleFullscreen() {
NOTIMPLEMENTED();
}
void WaylandWindow::Maximize() {
DCHECK(xdg_surface_);
xdg_surface_->SetMaximized();
connection_->ScheduleFlush();
}
void WaylandWindow::Minimize() {
DCHECK(xdg_surface_);
xdg_surface_->SetMinimized();
connection_->ScheduleFlush();
}
void WaylandWindow::Restore() {
DCHECK(xdg_surface_);
xdg_surface_->UnSetMaximized();
connection_->ScheduleFlush();
}
void WaylandWindow::SetCursor(PlatformCursor cursor) {
NOTIMPLEMENTED();
}
void WaylandWindow::MoveCursorTo(const gfx::Point& location) {
NOTIMPLEMENTED();
}
void WaylandWindow::ConfineCursorToBounds(const gfx::Rect& bounds) {
NOTIMPLEMENTED();
}
PlatformImeController* WaylandWindow::GetPlatformImeController() {
NOTIMPLEMENTED();
return nullptr;
}
bool WaylandWindow::CanDispatchEvent(const PlatformEvent& native_event) {
Event* event = static_cast<Event*>(native_event);
if (event->IsMouseEvent())
return has_pointer_focus_;
if (event->IsKeyEvent())
return has_keyboard_focus_;
return false;
}
uint32_t WaylandWindow::DispatchEvent(const PlatformEvent& native_event) {
DispatchEventFromNativeUiEvent(
native_event, base::Bind(&PlatformWindowDelegate::DispatchEvent,
base::Unretained(delegate_)));
return POST_DISPATCH_STOP_PROPAGATION;
}
void WaylandWindow::HandleSurfaceConfigure(int32_t width, int32_t height) {
// Width or height set 0 means that we should decide on width and height by
// ourselves, but we don't want to set to anything else. Use previous size.
if (width == 0 || height == 0) {
width = GetBounds().width();
height = GetBounds().height();
}
// Rather than call SetBounds here for every configure event, just save the
// most recent bounds, and have WaylandConnection call ApplyPendingBounds
// when it has finished processing events. We may get many configure events
// in a row during an interactive resize, and only the last one matters.
pending_bounds_ = gfx::Rect(0, 0, width, height);
}
void WaylandWindow::OnCloseRequest() {
NOTIMPLEMENTED();
}
} // namespace ui