blob: d53f91cba18898ef87fd9ddb58a1871d8d508e33 [file] [log] [blame]
// Copyright (c) 2012 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.
#ifndef UI_BASE_X_X11_UTIL_H_
#define UI_BASE_X_X11_UTIL_H_
// This file declares utility functions for X11 (Linux only).
//
// These functions do not require the Xlib headers to be included (which is why
// we use a void* for Visual*). The Xlib headers are highly polluting so we try
// hard to limit their spread into the rest of the code.
#include <stddef.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_refptr.h"
#include "base/synchronization/lock.h"
#include "build/build_config.h"
#include "ui/base/x/x11_cursor.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/platform_event.h"
#include "ui/gfx/icc_profile.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gfx/x/xproto_types.h"
typedef unsigned long Cursor;
class SkPixmap;
namespace base {
template <typename T>
struct DefaultSingletonTraits;
}
namespace gfx {
class Insets;
class Point;
class Rect;
} // namespace gfx
namespace ui {
enum WmState : uint32_t {
WM_STATE_WITHDRAWN = 0,
WM_STATE_NORMAL = 1,
WM_STATE_ICONIC = 3,
};
enum SizeHintsFlags : int32_t {
SIZE_HINT_US_POSITION = 1 << 0,
SIZE_HINT_US_SIZE = 1 << 1,
SIZE_HINT_P_POSITION = 1 << 2,
SIZE_HINT_P_SIZE = 1 << 3,
SIZE_HINT_P_MIN_SIZE = 1 << 4,
SIZE_HINT_P_MAX_SIZE = 1 << 5,
SIZE_HINT_P_RESIZE_INC = 1 << 6,
SIZE_HINT_P_ASPECT = 1 << 7,
SIZE_HINT_BASE_SIZE = 1 << 8,
SIZE_HINT_P_WIN_GRAVITY = 1 << 9,
};
struct SizeHints {
// User specified flags
int32_t flags;
// User-specified position
int32_t x, y;
// User-specified size
int32_t width, height;
// Program-specified minimum size
int32_t min_width, min_height;
// Program-specified maximum size
int32_t max_width, max_height;
// Program-specified resize increments
int32_t width_inc, height_inc;
// Program-specified minimum aspect ratios
int32_t min_aspect_num, min_aspect_den;
// Program-specified maximum aspect ratios
int32_t max_aspect_num, max_aspect_den;
// Program-specified base size
int32_t base_width, base_height;
// Program-specified window gravity
uint32_t win_gravity;
};
enum WmHintsFlags : uint32_t {
WM_HINT_INPUT = 1L << 0,
WM_HINT_STATE = 1L << 1,
WM_HINT_ICON_PIXMAP = 1L << 2,
WM_HINT_ICON_WINDOW = 1L << 3,
WM_HINT_ICON_POSITION = 1L << 4,
WM_HINT_ICON_MASK = 1L << 5,
WM_HINT_WINDOW_GROUP = 1L << 6,
// 1L << 7 doesn't have any defined meaning
WM_HINT_X_URGENCY = 1L << 8
};
struct WmHints {
// Marks which fields in this structure are defined
int32_t flags;
// Does this application rely on the window manager to get keyboard input?
uint32_t input;
// See below
int32_t initial_state;
// Pixmap to be used as icon
xcb_pixmap_t icon_pixmap;
// Window to be used as icon
xcb_window_t icon_window;
// Initial position of icon
int32_t icon_x, icon_y;
// Icon mask bitmap
xcb_pixmap_t icon_mask;
// Identifier of related window group
xcb_window_t window_group;
};
// These functions use the default display and this /must/ be called from
// the UI thread. Thus, they don't support multiple displays.
template <typename T>
bool GetArrayProperty(x11::Window window,
x11::Atom name,
std::vector<T>* value,
x11::Atom* out_type = nullptr,
size_t amount = 0) {
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "");
size_t bytes = amount * sizeof(T);
// The length field specifies the maximum amount of data we would like the
// server to give us. It's specified in units of 4 bytes, so divide by 4.
// Add 3 before division to round up.
size_t length = (bytes + 3) / 4;
using lentype = decltype(x11::GetPropertyRequest::long_length);
auto response =
x11::Connection::Get()
->GetProperty(
{.window = static_cast<x11::Window>(window),
.property = name,
.long_length =
amount ? length : std::numeric_limits<lentype>::max()})
.Sync();
if (!response || response->format != CHAR_BIT * sizeof(T))
return false;
DCHECK_EQ(response->format / CHAR_BIT * response->value_len,
response->value->size());
value->resize(response->value_len);
memcpy(value->data(), response->value->data(), response->value->size());
if (out_type)
*out_type = response->type;
return true;
}
template <typename T>
bool GetProperty(x11::Window window, const x11::Atom name, T* value) {
std::vector<T> values;
if (!GetArrayProperty(window, name, &values, nullptr, 1) || values.empty())
return false;
*value = values[0];
return true;
}
template <typename T>
void SetArrayProperty(x11::Window window,
x11::Atom name,
x11::Atom type,
const std::vector<T>& values) {
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "");
std::vector<uint8_t> data(sizeof(T) * values.size());
memcpy(data.data(), values.data(), sizeof(T) * values.size());
x11::Connection::Get()->ChangeProperty(
{.window = static_cast<x11::Window>(window),
.property = name,
.type = type,
.format = CHAR_BIT * sizeof(T),
.data_len = values.size(),
.data = base::RefCountedBytes::TakeVector(&data)});
}
template <typename T>
void SetProperty(x11::Window window,
x11::Atom name,
x11::Atom type,
const T& value) {
SetArrayProperty(window, name, type, std::vector<T>{value});
}
template <typename T>
x11::Future<void> SendEvent(const T& event,
x11::Window target,
x11::EventMask mask) {
static_assert(T::type_id > 0, "T must be an x11::*Event type");
auto write_buffer = x11::Write(event);
DCHECK_EQ(write_buffer.GetBuffers().size(), 1ul);
auto& first_buffer = write_buffer.GetBuffers()[0];
DCHECK_LE(first_buffer->size(), 32ul);
std::vector<uint8_t> event_bytes(32);
memcpy(event_bytes.data(), first_buffer->data(), first_buffer->size());
x11::SendEventRequest send_event{false, target, mask};
std::copy(event_bytes.begin(), event_bytes.end(), send_event.event.begin());
return x11::Connection::Get()->SendEvent(send_event);
}
COMPONENT_EXPORT(UI_BASE_X)
void DeleteProperty(x11::Window window, x11::Atom name);
COMPONENT_EXPORT(UI_BASE_X)
bool GetWmNormalHints(x11::Window window, SizeHints* hints);
COMPONENT_EXPORT(UI_BASE_X)
void SetWmNormalHints(x11::Window window, const SizeHints& hints);
COMPONENT_EXPORT(UI_BASE_X)
bool GetWmHints(x11::Window window, WmHints* hints);
COMPONENT_EXPORT(UI_BASE_X)
void SetWmHints(x11::Window window, const WmHints& hints);
COMPONENT_EXPORT(UI_BASE_X)
void WithdrawWindow(x11::Window window);
COMPONENT_EXPORT(UI_BASE_X)
void RaiseWindow(x11::Window window);
COMPONENT_EXPORT(UI_BASE_X)
void LowerWindow(x11::Window window);
COMPONENT_EXPORT(UI_BASE_X)
void DefineCursor(x11::Window window, x11::Cursor cursor);
COMPONENT_EXPORT(UI_BASE_X)
x11::Window CreateDummyWindow(const std::string& name = "");
// Draws an SkPixmap on |drawable| using the given |gc|, converting to the
// server side visual as needed.
COMPONENT_EXPORT(UI_BASE_X)
void DrawPixmap(x11::Connection* connection,
x11::VisualId visual,
x11::Drawable drawable,
x11::GraphicsContext gc,
const SkPixmap& skia_pixmap,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height);
// These functions cache their results ---------------------------------
// Returns true if the system supports XINPUT2.
COMPONENT_EXPORT(UI_BASE_X) bool IsXInput2Available();
// Return true iff the display supports MIT-SHM.
COMPONENT_EXPORT(UI_BASE_X) bool QueryShmSupport();
// Coalesce all pending motion events (touch or mouse) that are at the top of
// the queue, and return the number eliminated, storing the last one in
// |last_event|.
COMPONENT_EXPORT(UI_BASE_X)
int CoalescePendingMotionEvents(const x11::Event* xev, x11::Event* last_event);
// Sets whether |window| should use the OS window frame.
COMPONENT_EXPORT(UI_BASE_X)
void SetUseOSWindowFrame(x11::Window window, bool use_os_window_frame);
// These functions do not cache their results --------------------------
// Returns true if the shape extension is supported.
COMPONENT_EXPORT(UI_BASE_X) bool IsShapeExtensionAvailable();
// Get the X window id for the default root window
COMPONENT_EXPORT(UI_BASE_X) x11::Window GetX11RootWindow();
// Returns the user's current desktop.
COMPONENT_EXPORT(UI_BASE_X) bool GetCurrentDesktop(int* desktop);
enum HideTitlebarWhenMaximized : uint32_t {
SHOW_TITLEBAR_WHEN_MAXIMIZED = 0,
HIDE_TITLEBAR_WHEN_MAXIMIZED = 1,
};
// Sets _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED on |window|.
COMPONENT_EXPORT(UI_BASE_X)
void SetHideTitlebarWhenMaximizedProperty(x11::Window window,
HideTitlebarWhenMaximized property);
// Returns true if |window| is visible.
COMPONENT_EXPORT(UI_BASE_X) bool IsWindowVisible(x11::Window window);
// Returns the inner bounds of |window| (excluding the non-client area).
COMPONENT_EXPORT(UI_BASE_X)
bool GetInnerWindowBounds(x11::Window window, gfx::Rect* rect);
// Returns the non-client area extents of |window|. This is a negative inset; it
// represents the negative size of the window border on all sides.
// InnerWindowBounds.Inset(WindowExtents) = OuterWindowBounds.
// Returns false if the window manager does not provide extents information.
COMPONENT_EXPORT(UI_BASE_X)
bool GetWindowExtents(x11::Window window, gfx::Insets* extents);
// Returns the outer bounds of |window| (including the non-client area).
COMPONENT_EXPORT(UI_BASE_X)
bool GetOuterWindowBounds(x11::Window window, gfx::Rect* rect);
// Returns true if |window| contains the point |screen_loc|.
COMPONENT_EXPORT(UI_BASE_X)
bool WindowContainsPoint(x11::Window window, gfx::Point screen_loc);
// Return true if |window| has any property with |property_name|.
COMPONENT_EXPORT(UI_BASE_X)
bool PropertyExists(x11::Window window, const std::string& property_name);
// Returns the raw bytes from a property with minimal
// interpretation. |out_data| should be freed by XFree() after use.
COMPONENT_EXPORT(UI_BASE_X)
bool GetRawBytesOfProperty(x11::Window window,
x11::Atom property,
scoped_refptr<base::RefCountedMemory>* out_data,
x11::Atom* out_type);
// Get the value of an int, int array, atom array or string property. On
// success, true is returned and the value is stored in |value|.
//
// These functions should no longer be used. TODO(thomasanderson): migrate
// existing callers to {Set,Get}{,Array}Property<> instead.
COMPONENT_EXPORT(UI_BASE_X)
bool GetIntProperty(x11::Window window,
const std::string& property_name,
int32_t* value);
COMPONENT_EXPORT(UI_BASE_X)
bool GetIntArrayProperty(x11::Window window,
const std::string& property_name,
std::vector<int32_t>* value);
COMPONENT_EXPORT(UI_BASE_X)
bool GetAtomArrayProperty(x11::Window window,
const std::string& property_name,
std::vector<x11::Atom>* value);
COMPONENT_EXPORT(UI_BASE_X)
bool GetStringProperty(x11::Window window,
const std::string& property_name,
std::string* value);
COMPONENT_EXPORT(UI_BASE_X)
void SetIntProperty(x11::Window window,
const std::string& name,
const std::string& type,
int32_t value);
COMPONENT_EXPORT(UI_BASE_X)
void SetIntArrayProperty(x11::Window window,
const std::string& name,
const std::string& type,
const std::vector<int32_t>& value);
COMPONENT_EXPORT(UI_BASE_X)
void SetAtomProperty(x11::Window window,
const std::string& name,
const std::string& type,
x11::Atom value);
COMPONENT_EXPORT(UI_BASE_X)
void SetAtomArrayProperty(x11::Window window,
const std::string& name,
const std::string& type,
const std::vector<x11::Atom>& value);
COMPONENT_EXPORT(UI_BASE_X)
void SetStringProperty(x11::Window window,
x11::Atom property,
x11::Atom type,
const std::string& value);
// Sets the WM_CLASS attribute for a given X11 window.
COMPONENT_EXPORT(UI_BASE_X)
void SetWindowClassHint(x11::Connection* connection,
x11::Window window,
const std::string& res_name,
const std::string& res_class);
// Sets the WM_WINDOW_ROLE attribute for a given X11 window.
COMPONENT_EXPORT(UI_BASE_X)
void SetWindowRole(x11::Window window, const std::string& role);
// Sends a message to the x11 window manager, enabling or disabling the
// states |state1| and |state2|.
COMPONENT_EXPORT(UI_BASE_X)
void SetWMSpecState(x11::Window window,
bool enabled,
x11::Atom state1,
x11::Atom state2);
// Sends a NET_WM_MOVERESIZE message to the x11 window manager, enabling the
// move/resize mode. As per NET_WM_MOVERESIZE spec, |location| is the position
// in pixels (relative to the root window) of mouse button press, and
// |direction| indicates whether this is a move or resize event, and if it is a
// resize event, which edges of the window the size grip applies to.
COMPONENT_EXPORT(UI_BASE_X)
void DoWMMoveResize(x11::Connection* connection,
x11::Window root_window,
x11::Window window,
const gfx::Point& location_px,
int direction);
// Checks if the window manager has set a specific state.
COMPONENT_EXPORT(UI_BASE_X)
bool HasWMSpecProperty(const base::flat_set<x11::Atom>& properties,
x11::Atom atom);
// Determine whether we should default to native decorations or the custom
// frame based on the currently-running window manager.
COMPONENT_EXPORT(UI_BASE_X) bool GetCustomFramePrefDefault();
static const int kAllDesktops = -1;
// Queries the desktop |window| is on, kAllDesktops if sticky. Returns false if
// property not found.
COMPONENT_EXPORT(UI_BASE_X)
bool GetWindowDesktop(x11::Window window, int* desktop);
// Translates an X11 error code into a printable string.
COMPONENT_EXPORT(UI_BASE_X)
std::string GetX11ErrorString(XDisplay* display, int err);
// Implementers of this interface receive a notification for every X window of
// the main display.
class EnumerateWindowsDelegate {
public:
// |window| is the X Window ID of the enumerated window. Return true to stop
// further iteration.
virtual bool ShouldStopIterating(x11::Window window) = 0;
protected:
virtual ~EnumerateWindowsDelegate() = default;
};
// Enumerates all windows in the current display. Will recurse into child
// windows up to a depth of |max_depth|.
COMPONENT_EXPORT(UI_BASE_X)
bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth);
// Enumerates the top-level windows of the current display.
COMPONENT_EXPORT(UI_BASE_X)
void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate);
// Returns all children windows of a given window in top-to-bottom stacking
// order.
COMPONENT_EXPORT(UI_BASE_X)
bool GetXWindowStack(x11::Window window, std::vector<x11::Window>* windows);
enum WindowManagerName {
WM_OTHER, // We were able to obtain the WM's name, but there is
// no corresponding entry in this enum.
WM_UNNAMED, // Either there is no WM or there is no way to obtain
// the WM name.
WM_AWESOME,
WM_BLACKBOX,
WM_COMPIZ,
WM_ENLIGHTENMENT,
WM_FLUXBOX,
WM_I3,
WM_ICE_WM,
WM_ION3,
WM_KWIN,
WM_MATCHBOX,
WM_METACITY,
WM_MUFFIN,
WM_MUTTER,
WM_NOTION,
WM_OPENBOX,
WM_QTILE,
WM_RATPOISON,
WM_STUMPWM,
WM_WMII,
WM_XFWM4,
WM_XMONAD,
};
// Attempts to guess the window maager. Returns WM_OTHER or WM_UNNAMED
// if we can't determine it for one reason or another.
COMPONENT_EXPORT(UI_BASE_X) WindowManagerName GuessWindowManager();
// The same as GuessWindowManager(), but returns the raw string. If we
// can't determine it, return "Unknown".
COMPONENT_EXPORT(UI_BASE_X) std::string GuessWindowManagerName();
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// Append new window managers before kMaxValue and update LinuxWindowManagerName
// in tools/metrics/histograms/enums.xml accordingly.
//
// See also tools/metrics/histograms/README.md#enum-histograms
enum class UMALinuxWindowManager {
kOther = 0,
kBlackbox = 1,
kChromeOS = 2, // Deprecated.
kCompiz = 3,
kEnlightenment = 4,
kIceWM = 5,
kKWin = 6,
kMetacity = 7,
kMuffin = 8,
kMutter = 9,
kOpenbox = 10,
kXfwm4 = 11,
kAwesome = 12,
kI3 = 13,
kIon3 = 14,
kMatchbox = 15,
kNotion = 16,
kQtile = 17,
kRatpoison = 18,
kStumpWM = 19,
kWmii = 20,
kFluxbox = 21,
kXmonad = 22,
kUnnamed = 23,
kMaxValue = kUnnamed
};
COMPONENT_EXPORT(UI_BASE_X) UMALinuxWindowManager GetWindowManagerUMA();
// Returns a buest-effort guess as to whether |window_manager| is tiling (true)
// or stacking (false).
COMPONENT_EXPORT(UI_BASE_X) bool IsWmTiling(WindowManagerName window_manager);
// Returns true if a compositing manager is present.
COMPONENT_EXPORT(UI_BASE_X) bool IsCompositingManagerPresent();
// Enable the default X error handlers. These will log the error and abort
// the process if called. Use SetX11ErrorHandlers() to set your own error
// handlers.
COMPONENT_EXPORT(UI_BASE_X) void SetDefaultX11ErrorHandlers();
// Returns true if a given window is in full-screen mode.
COMPONENT_EXPORT(UI_BASE_X) bool IsX11WindowFullScreen(x11::Window window);
// Returns true if the window manager supports the given hint.
COMPONENT_EXPORT(UI_BASE_X) bool WmSupportsHint(x11::Atom atom);
// Returns the ICCProfile corresponding to |monitor| using XGetWindowProperty.
COMPONENT_EXPORT(UI_BASE_X)
gfx::ICCProfile GetICCProfileForMonitor(int monitor);
// Return true if the display supports SYNC extension.
COMPONENT_EXPORT(UI_BASE_X) bool IsSyncExtensionAvailable();
// Returns the preferred Skia colortype for an X11 visual. Returns
// kUnknown_SkColorType if there isn't a suitable colortype.
COMPONENT_EXPORT(UI_BASE_X)
SkColorType ColorTypeForVisual(x11::VisualId visual_id);
COMPONENT_EXPORT(UI_BASE_X)
x11::Future<void> SendClientMessage(
x11::Window window,
x11::Window target,
x11::Atom type,
const std::array<uint32_t, 5> data,
x11::EventMask event_mask = x11::EventMask::SubstructureNotify |
x11::EventMask::SubstructureRedirect);
// Manages a piece of X11 allocated memory as a RefCountedMemory segment. This
// object takes ownership over the passed in memory and will free it with the
// X11 allocator when done.
class COMPONENT_EXPORT(UI_BASE_X) XRefcountedMemory
: public base::RefCountedMemory {
public:
XRefcountedMemory(unsigned char* x11_data, size_t length);
// Overridden from RefCountedMemory:
const unsigned char* front() const override;
size_t size() const override;
private:
~XRefcountedMemory() override;
gfx::XScopedPtr<unsigned char> x11_data_;
size_t length_;
DISALLOW_COPY_AND_ASSIGN(XRefcountedMemory);
};
struct COMPONENT_EXPORT(UI_BASE_X) XImageDeleter {
void operator()(XImage* image) const;
};
using XScopedImage = std::unique_ptr<XImage, XImageDeleter>;
// --------------------------------------------------------------------------
// X11 error handling.
// Sets the X Error Handlers. Passing NULL for either will enable the default
// error handler, which if called will log the error and abort the process.
COMPONENT_EXPORT(UI_BASE_X)
void SetX11ErrorHandlers(XErrorHandler error_handler,
XIOErrorHandler io_error_handler);
// NOTE: This function should not be called directly from the
// X11 Error handler because it queries the server to decode the
// error message, which may trigger other errors. A suitable workaround
// is to post a task in the error handler to call this function.
COMPONENT_EXPORT(UI_BASE_X)
void LogErrorEventDescription(Display* dpy, const XErrorEvent& error_event);
// --------------------------------------------------------------------------
// Selects a visual with a preference for alpha support on compositing window
// managers.
class COMPONENT_EXPORT(UI_BASE_X) XVisualManager {
public:
static XVisualManager* GetInstance();
// Picks the best argb or opaque visual given |want_argb_visual|.
void ChooseVisualForWindow(bool want_argb_visual,
x11::VisualId* visual_id,
uint8_t* depth,
x11::ColorMap* colormap,
bool* visual_has_alpha);
bool GetVisualInfo(x11::VisualId visual_id,
uint8_t* depth,
x11::ColorMap* colormap,
bool* visual_has_alpha);
// Called by GpuDataManagerImplPrivate when GPUInfo becomes available. It is
// necessary for the GPU process to find out which visuals are best for GL
// because we don't want to load GL in the browser process. Returns false iff
// |default_visual_id| or |transparent_visual_id| are invalid.
bool OnGPUInfoChanged(bool software_rendering,
x11::VisualId default_visual_id,
x11::VisualId transparent_visual_id);
// Are all of the system requirements met for using transparent visuals?
bool ArgbVisualAvailable() const;
~XVisualManager();
private:
friend struct base::DefaultSingletonTraits<XVisualManager>;
class XVisualData {
public:
XVisualData(x11::Connection* connection,
uint8_t depth,
const x11::VisualType* info);
~XVisualData();
x11::ColorMap GetColormap();
const uint8_t depth;
const x11::VisualType* const info;
private:
x11::ColorMap colormap_{};
x11::Connection* const connection_;
};
XVisualManager();
bool GetVisualInfoImpl(x11::VisualId visual_id,
uint8_t* depth,
x11::ColorMap* colormap,
bool* visual_has_alpha);
mutable base::Lock lock_;
std::unordered_map<x11::VisualId, std::unique_ptr<XVisualData>> visuals_;
x11::Connection* const connection_;
x11::VisualId default_visual_id_{};
// The system visual is usually the same as the default visual, but
// may not be in general.
x11::VisualId system_visual_id_{};
x11::VisualId transparent_visual_id_{};
bool using_software_rendering_ = false;
bool have_gpu_argb_visual_ = false;
DISALLOW_COPY_AND_ASSIGN(XVisualManager);
};
} // namespace ui
#endif // UI_BASE_X_X11_UTIL_H_