| Index: ui/ozone/platform/x11/x11_window_ozone.cc
|
| diff --git a/ui/ozone/platform/x11/x11_window_ozone.cc b/ui/ozone/platform/x11/x11_window_ozone.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a60e3aa511aa90b43c52100910f6b9c6eba8861d
|
| --- /dev/null
|
| +++ b/ui/ozone/platform/x11/x11_window_ozone.cc
|
| @@ -0,0 +1,278 @@
|
| +// 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/x11/x11_window_ozone.h"
|
| +
|
| +#include <X11/Xatom.h>
|
| +#include <X11/Xlib.h>
|
| +#include <X11/Xutil.h>
|
| +#include <X11/extensions/XInput2.h>
|
| +
|
| +#include <string>
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "ui/events/event.h"
|
| +#include "ui/events/ozone/events_ozone.h"
|
| +#include "ui/events/platform/platform_event_dispatcher.h"
|
| +#include "ui/events/platform/platform_event_source.h"
|
| +#include "ui/gfx/geometry/rect.h"
|
| +#include "ui/ozone/platform/x11/x11_event_factory.h"
|
| +#include "ui/platform_window/platform_window_delegate.h"
|
| +
|
| +namespace ui {
|
| +
|
| +namespace {
|
| +
|
| +const char* kAtomsToCache[] = {"UTF8_STRING", "WM_DELETE_WINDOW",
|
| + "_NET_WM_NAME", "_NET_WM_PID",
|
| + "_NET_WM_PING", NULL};
|
| +
|
| +} // namespace
|
| +
|
| +X11WindowOzone::X11WindowOzone(PlatformWindowDelegate* delegate,
|
| + WindowStatusCallback on_create_callback,
|
| + WindowStatusCallback on_destroy_callback)
|
| + : delegate_(delegate),
|
| + on_create_callback_(on_create_callback),
|
| + on_destroy_callback_(on_destroy_callback),
|
| + xdisplay_(gfx::GetXDisplay()),
|
| + xwindow_(None),
|
| + xroot_window_(DefaultRootWindow(xdisplay_)),
|
| + atom_cache_(xdisplay_, kAtomsToCache) {
|
| + CHECK(delegate_);
|
| +}
|
| +
|
| +X11WindowOzone::~X11WindowOzone() {
|
| + Destroy();
|
| +}
|
| +
|
| +void X11WindowOzone::Destroy() {
|
| + delegate_->OnClosed();
|
| + if (xwindow_ == None)
|
| + return;
|
| +
|
| + // Stop processing events.
|
| + on_destroy_callback_.Run(xwindow_, this);
|
| + PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
|
| + XDestroyWindow(xdisplay_, xwindow_);
|
| + xwindow_ = None;
|
| +}
|
| +
|
| +void X11WindowOzone::Create() {
|
| + CHECK(PlatformEventSource::GetInstance());
|
| + PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
|
| +
|
| + XSetWindowAttributes swa;
|
| + memset(&swa, 0, sizeof(swa));
|
| + swa.background_pixmap = None;
|
| + swa.override_redirect = False;
|
| + xwindow_ = XCreateWindow(xdisplay_, xroot_window_, requested_bounds_.x(),
|
| + requested_bounds_.y(), requested_bounds_.width(),
|
| + requested_bounds_.height(),
|
| + 0, // border width
|
| + CopyFromParent, // depth
|
| + InputOutput,
|
| + CopyFromParent, // visual
|
| + CWBackPixmap | CWOverrideRedirect, &swa);
|
| + on_create_callback_.Run(xwindow_, this);
|
| +
|
| + long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
|
| + KeyPressMask | KeyReleaseMask | EnterWindowMask |
|
| + LeaveWindowMask | ExposureMask | VisibilityChangeMask |
|
| + StructureNotifyMask | PropertyChangeMask |
|
| + PointerMotionMask;
|
| + XSelectInput(xdisplay_, xwindow_, event_mask);
|
| +
|
| + unsigned char mask[XIMaskLen(XI_LASTEVENT)];
|
| + memset(mask, 0, sizeof(mask));
|
| +
|
| + XISetMask(mask, XI_TouchBegin);
|
| + XISetMask(mask, XI_TouchUpdate);
|
| + XISetMask(mask, XI_TouchEnd);
|
| + XISetMask(mask, XI_ButtonPress);
|
| + XISetMask(mask, XI_ButtonRelease);
|
| + XISetMask(mask, XI_Motion);
|
| + XISetMask(mask, XI_KeyPress);
|
| + XISetMask(mask, XI_KeyRelease);
|
| +
|
| + XIEventMask evmask;
|
| + evmask.deviceid = XIAllDevices;
|
| + evmask.mask_len = sizeof(mask);
|
| + evmask.mask = mask;
|
| + XISelectEvents(xdisplay_, xwindow_, &evmask, 1);
|
| + XFlush(xdisplay_);
|
| +
|
| + ::Atom protocols[2];
|
| + protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
|
| + protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
|
| + XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
|
| +
|
| + // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
|
| + // the desktop environment.
|
| + XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
|
| +
|
| + // Likewise, the X server needs to know this window's pid so it knows which
|
| + // program to kill if the window hangs.
|
| + // XChangeProperty() expects "pid" to be long.
|
| + static_assert(sizeof(long) >= sizeof(pid_t),
|
| + "pid_t should not be larger than long");
|
| + long pid = getpid();
|
| + XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_PID"),
|
| + XA_CARDINAL, 32, PropModeReplace,
|
| + reinterpret_cast<unsigned char*>(&pid), 1);
|
| + // Before we map the window, set size hints. Otherwise, some window managers
|
| + // will ignore toplevel XMoveWindow commands.
|
| + XSizeHints size_hints;
|
| + size_hints.flags = PPosition | PWinGravity;
|
| + size_hints.x = requested_bounds_.x();
|
| + size_hints.y = requested_bounds_.y();
|
| + // Set StaticGravity so that the window position is not affected by the
|
| + // frame width when running with window manager.
|
| + size_hints.win_gravity = StaticGravity;
|
| + XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
|
| +
|
| + delegate_->OnAcceleratedWidgetAvailable(xwindow_, 1.f);
|
| +}
|
| +
|
| +void X11WindowOzone::Show() {
|
| + if (window_mapped_)
|
| + return;
|
| + if (xwindow_ == None)
|
| + Create();
|
| +
|
| + XMapWindow(xdisplay_, xwindow_);
|
| +
|
| + // We now block until our window is mapped. Some X11 APIs will crash and
|
| + // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
|
| + // asynchronous.
|
| + X11EventFactory::GetInstance()->BlockUntilWindowMapped(xwindow_);
|
| + window_mapped_ = true;
|
| +}
|
| +
|
| +void X11WindowOzone::Hide() {
|
| + if (!window_mapped_)
|
| + return;
|
| + XWithdrawWindow(xdisplay_, xwindow_, 0);
|
| + window_mapped_ = false;
|
| +}
|
| +
|
| +void X11WindowOzone::Close() {
|
| + Destroy();
|
| +}
|
| +
|
| +void X11WindowOzone::SetBounds(const gfx::Rect& bounds) {
|
| + requested_bounds_ = bounds;
|
| + if (!window_mapped_ || bounds == confirmed_bounds_)
|
| + return;
|
| + XWindowChanges changes = {0};
|
| + unsigned value_mask = CWX | CWY | CWWidth | CWHeight;
|
| + changes.x = bounds.x();
|
| + changes.y = bounds.y();
|
| + changes.width = bounds.width();
|
| + changes.height = bounds.height();
|
| + XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
|
| +}
|
| +
|
| +gfx::Rect X11WindowOzone::GetBounds() {
|
| + return confirmed_bounds_;
|
| +}
|
| +
|
| +void X11WindowOzone::SetTitle(const base::string16& title) {
|
| + if (window_title_ == title)
|
| + return;
|
| + window_title_ = title;
|
| + std::string utf8str = base::UTF16ToUTF8(title);
|
| + XChangeProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_NAME"),
|
| + atom_cache_.GetAtom("UTF8_STRING"), 8, PropModeReplace,
|
| + reinterpret_cast<const unsigned char*>(utf8str.c_str()),
|
| + utf8str.size());
|
| + XTextProperty xtp;
|
| + char* c_utf8_str = const_cast<char*>(utf8str.c_str());
|
| + if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1, XUTF8StringStyle,
|
| + &xtp) == Success) {
|
| + XSetWMName(xdisplay_, xwindow_, &xtp);
|
| + XFree(xtp.value);
|
| + }
|
| +}
|
| +
|
| +void X11WindowOzone::SetCapture() {}
|
| +
|
| +void X11WindowOzone::ReleaseCapture() {}
|
| +
|
| +void X11WindowOzone::ToggleFullscreen() {}
|
| +
|
| +void X11WindowOzone::Maximize() {}
|
| +
|
| +void X11WindowOzone::Minimize() {}
|
| +
|
| +void X11WindowOzone::Restore() {}
|
| +
|
| +void X11WindowOzone::SetCursor(PlatformCursor cursor) {}
|
| +
|
| +void X11WindowOzone::MoveCursorTo(const gfx::Point& location) {}
|
| +
|
| +void X11WindowOzone::ConfineCursorToBounds(const gfx::Rect& bounds) {}
|
| +
|
| +PlatformImeController* X11WindowOzone::GetPlatformImeController() {
|
| + return nullptr;
|
| +}
|
| +
|
| +void X11WindowOzone::ProcessXEvent(const XEvent& xev) {
|
| + switch (xev.type) {
|
| + case Expose: {
|
| + gfx::Rect damage_rect(xev.xexpose.x, xev.xexpose.y, xev.xexpose.width,
|
| + xev.xexpose.height);
|
| + delegate_->OnDamageRect(damage_rect);
|
| + break;
|
| + }
|
| +
|
| + case FocusOut:
|
| + if (xev.xfocus.mode != NotifyGrab)
|
| + delegate_->OnLostCapture();
|
| + break;
|
| +
|
| + case ConfigureNotify: {
|
| + DCHECK_EQ(xwindow_, xev.xconfigure.event);
|
| + DCHECK_EQ(xwindow_, xev.xconfigure.window);
|
| + gfx::Rect bounds(xev.xconfigure.x, xev.xconfigure.y, xev.xconfigure.width,
|
| + xev.xconfigure.height);
|
| + if (confirmed_bounds_ != bounds) {
|
| + confirmed_bounds_ = bounds;
|
| + delegate_->OnBoundsChanged(confirmed_bounds_);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case ClientMessage: {
|
| + Atom message = static_cast<Atom>(xev.xclient.data.l[0]);
|
| + if (message == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
|
| + delegate_->OnCloseRequest();
|
| + } else if (message == atom_cache_.GetAtom("_NET_WM_PING")) {
|
| + XEvent reply_event = xev;
|
| + reply_event.xclient.window = xroot_window_;
|
| +
|
| + XSendEvent(xdisplay_, reply_event.xclient.window, False,
|
| + SubstructureRedirectMask | SubstructureNotifyMask,
|
| + &reply_event);
|
| + XFlush(xdisplay_);
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +bool X11WindowOzone::CanDispatchEvent(const PlatformEvent& event) {
|
| + // TODO(kylechar): Fix events to work with multiple PlatformWindows.
|
| + return true;
|
| +}
|
| +
|
| +uint32_t X11WindowOzone::DispatchEvent(const PlatformEvent& event) {
|
| + DispatchEventFromNativeUiEvent(
|
| + event, base::Bind(&PlatformWindowDelegate::DispatchEvent,
|
| + base::Unretained(delegate_)));
|
| + return POST_DISPATCH_STOP_PROPAGATION;
|
| +}
|
| +
|
| +} // namespace ui
|
|
|