Commit 4473c1b2 authored by Henrique Ferreiro's avatar Henrique Ferreiro Committed by Commit Bot

Unify Aura and Ozone X11 Cursor name selection

The main change in this CL is using the same cursor fallback selection
machinery for both Aura/X11 and Ozone/X11. In addition to that:

Cursor loading now uses cursor names, instead of a mix of cursor names
and shapes (as introduced in [0]), given that all shapes can be loaded
by Xcursor using their corresponding name.

The CSS name is preferred over other options, relying on
cursor themes usually linking known cursor names to cursors defined in
the theme, or alternatively, picking alternative cursors as defined in a
fallback table.

It fixes the w-resize fallback changing it to left_side and replaces
v-scroll and h-scroll (introduced in [1]) with all-scroll, as they are
only available on Windows.

[0]: https://crrev.com/c/1998353
[1]: https://crrev.com/c/1638924

Bug: 1029142
Change-Id: If50698d5305135be43cda4eeb48532d23816754f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2245704
Commit-Queue: Henrique Ferreiro <hferreiro@igalia.com>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#780495}
parent 914928cc
......@@ -16,136 +16,6 @@
namespace ui {
namespace {
// Load a cursor with a list of css names or shapes in order of decreasing
// priority.
::Cursor LoadFontCursor() {
return x11::None;
}
template <typename... Ts>
::Cursor LoadFontCursor(int shape, Ts... ts);
template <typename... Ts>
::Cursor LoadFontCursor(const char* name, Ts... ts) {
::Cursor cursor = XcursorLibraryLoadCursor(gfx::GetXDisplay(), name);
if (cursor != x11::None)
return cursor;
return LoadFontCursor(ts...);
}
template <typename... Ts>
::Cursor LoadFontCursor(int shape, Ts... ts) {
::Cursor cursor = XCreateFontCursor(gfx::GetXDisplay(), shape);
if (cursor != x11::None)
return cursor;
return LoadFontCursor(ts...);
}
::Cursor LoadFontCursorForCursorType(mojom::CursorType id) {
switch (id) {
case mojom::CursorType::kMiddlePanning:
return LoadFontCursor("all-scroll", XC_fleur);
case mojom::CursorType::kMiddlePanningVertical:
return LoadFontCursor("v-scroll");
case mojom::CursorType::kMiddlePanningHorizontal:
return LoadFontCursor("h-scroll");
case mojom::CursorType::kNone:
return LoadFontCursor("none");
case mojom::CursorType::kGrab:
return LoadFontCursor("openhand", "grab");
case mojom::CursorType::kGrabbing:
return LoadFontCursor("closedhand", "grabbing", XC_hand2);
case mojom::CursorType::kNull:
case mojom::CursorType::kPointer:
return LoadFontCursor("left_ptr", XC_left_ptr);
case mojom::CursorType::kMove:
return LoadFontCursor("all-scroll", XC_fleur);
case mojom::CursorType::kCross:
return LoadFontCursor("crosshair", XC_cross);
case mojom::CursorType::kHand:
return LoadFontCursor("pointer", "hand", XC_hand2);
case mojom::CursorType::kIBeam:
return LoadFontCursor("text", XC_xterm);
case mojom::CursorType::kProgress:
return LoadFontCursor("progress", "left_ptr_watch", XC_watch);
case mojom::CursorType::kWait:
return LoadFontCursor("wait", XC_watch);
case mojom::CursorType::kHelp:
return LoadFontCursor("help");
case mojom::CursorType::kEastResize:
case mojom::CursorType::kEastPanning:
return LoadFontCursor("e-resize", XC_right_side);
case mojom::CursorType::kNorthResize:
case mojom::CursorType::kNorthPanning:
return LoadFontCursor("n-resize", XC_top_side);
case mojom::CursorType::kNorthEastResize:
case mojom::CursorType::kNorthEastPanning:
return LoadFontCursor("ne-resize", XC_top_right_corner);
case mojom::CursorType::kNorthWestResize:
case mojom::CursorType::kNorthWestPanning:
return LoadFontCursor("nw-resize", XC_top_left_corner);
case mojom::CursorType::kSouthResize:
case mojom::CursorType::kSouthPanning:
return LoadFontCursor("s-resize", XC_bottom_side);
case mojom::CursorType::kSouthEastResize:
case mojom::CursorType::kSouthEastPanning:
return LoadFontCursor("se-resize", XC_bottom_right_corner);
case mojom::CursorType::kSouthWestResize:
case mojom::CursorType::kSouthWestPanning:
return LoadFontCursor("sw-resize", XC_bottom_left_corner);
case mojom::CursorType::kWestResize:
case mojom::CursorType::kWestPanning:
return LoadFontCursor("w-resize", XC_right_side);
case mojom::CursorType::kNorthSouthResize:
return LoadFontCursor(XC_sb_v_double_arrow, "ns-resize");
case mojom::CursorType::kEastWestResize:
return LoadFontCursor(XC_sb_h_double_arrow, "ew-resize");
case mojom::CursorType::kColumnResize:
return LoadFontCursor("col-resize", XC_sb_h_double_arrow);
case mojom::CursorType::kRowResize:
return LoadFontCursor("row-resize", XC_sb_v_double_arrow);
case mojom::CursorType::kNorthEastSouthWestResize:
return LoadFontCursor("size_bdiag", "nesw-resize", "fd_double_arrow");
case mojom::CursorType::kNorthWestSouthEastResize:
return LoadFontCursor("size_fdiag", "nwse-resize", "bd_double_arrow");
case mojom::CursorType::kVerticalText:
return LoadFontCursor("vertical-text");
case mojom::CursorType::kZoomIn:
return LoadFontCursor("zoom-in");
case mojom::CursorType::kZoomOut:
return LoadFontCursor("zoom-out");
case mojom::CursorType::kCell:
return LoadFontCursor("cell", XC_plus);
case mojom::CursorType::kContextMenu:
return LoadFontCursor("context-menu");
case mojom::CursorType::kAlias:
return LoadFontCursor("alias");
case mojom::CursorType::kNoDrop:
return LoadFontCursor("no-drop");
case mojom::CursorType::kCopy:
return LoadFontCursor("copy");
case mojom::CursorType::kNotAllowed:
return LoadFontCursor("not-allowed", "crossed_circle");
case mojom::CursorType::kDndNone:
return LoadFontCursor("dnd-none", XC_hand2);
case mojom::CursorType::kDndMove:
return LoadFontCursor("dnd-move", XC_hand2);
case mojom::CursorType::kDndCopy:
return LoadFontCursor("dnd-copy", XC_hand2);
case mojom::CursorType::kDndLink:
return LoadFontCursor("dnd-link", XC_hand2);
case mojom::CursorType::kCustom:
NOTREACHED();
return LoadFontCursor();
}
NOTREACHED() << "Case not handled for " << static_cast<int>(id);
return LoadFontCursor();
}
} // namespace
CursorLoader* CursorLoader::Create() {
return new CursorLoaderX11;
}
......@@ -270,7 +140,7 @@ bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) {
}
// First try to load the cursor directly.
::Cursor cursor = LoadFontCursorForCursorType(id);
::Cursor cursor = LoadCursorFromType(id);
if (cursor != x11::None) {
font_cursors_[id] = cursor;
return cursor;
......
......@@ -23,6 +23,7 @@
#endif
namespace ui {
namespace {
struct HotPoint {
......@@ -283,120 +284,6 @@ bool SearchTable(const CursorData* table,
} // namespace
const char* CursorCssNameFromId(mojom::CursorType id) {
switch (id) {
case mojom::CursorType::kMiddlePanning:
return "all-scroll";
case mojom::CursorType::kMiddlePanningVertical:
return "v-scroll";
case mojom::CursorType::kMiddlePanningHorizontal:
return "h-scroll";
case mojom::CursorType::kEastPanning:
return "e-resize";
case mojom::CursorType::kNorthPanning:
return "n-resize";
case mojom::CursorType::kNorthEastPanning:
return "ne-resize";
case mojom::CursorType::kNorthWestPanning:
return "nw-resize";
case mojom::CursorType::kSouthPanning:
return "s-resize";
case mojom::CursorType::kSouthEastPanning:
return "se-resize";
case mojom::CursorType::kSouthWestPanning:
return "sw-resize";
case mojom::CursorType::kWestPanning:
return "w-resize";
case mojom::CursorType::kNone:
return "none";
case mojom::CursorType::kGrab:
return "grab";
case mojom::CursorType::kGrabbing:
return "grabbing";
case mojom::CursorType::kNull:
return "left_ptr";
case mojom::CursorType::kPointer:
return "left_ptr";
case mojom::CursorType::kMove:
// Returning "move" is the correct thing here, but Blink doesn't
// make a distinction between move and all-scroll. Other
// platforms use a cursor more consistent with all-scroll, so
// use that.
return "all-scroll";
case mojom::CursorType::kCross:
return "crosshair";
case mojom::CursorType::kHand:
return "pointer";
case mojom::CursorType::kIBeam:
return "text";
case mojom::CursorType::kProgress:
return "progress";
case mojom::CursorType::kWait:
return "wait";
case mojom::CursorType::kHelp:
return "help";
case mojom::CursorType::kEastResize:
return "e-resize";
case mojom::CursorType::kNorthResize:
return "n-resize";
case mojom::CursorType::kNorthEastResize:
return "ne-resize";
case mojom::CursorType::kNorthWestResize:
return "nw-resize";
case mojom::CursorType::kSouthResize:
return "s-resize";
case mojom::CursorType::kSouthEastResize:
return "se-resize";
case mojom::CursorType::kSouthWestResize:
return "sw-resize";
case mojom::CursorType::kWestResize:
return "w-resize";
case mojom::CursorType::kNorthSouthResize:
return "ns-resize";
case mojom::CursorType::kEastWestResize:
return "ew-resize";
case mojom::CursorType::kColumnResize:
return "col-resize";
case mojom::CursorType::kRowResize:
return "row-resize";
case mojom::CursorType::kNorthEastSouthWestResize:
return "nesw-resize";
case mojom::CursorType::kNorthWestSouthEastResize:
return "nwse-resize";
case mojom::CursorType::kVerticalText:
return "vertical-text";
case mojom::CursorType::kZoomIn:
return "zoom-in";
case mojom::CursorType::kZoomOut:
return "zoom-out";
case mojom::CursorType::kCell:
return "cell";
case mojom::CursorType::kContextMenu:
return "context-menu";
case mojom::CursorType::kAlias:
return "alias";
case mojom::CursorType::kNoDrop:
return "no-drop";
case mojom::CursorType::kCopy:
return "copy";
case mojom::CursorType::kNotAllowed:
return "not-allowed";
case mojom::CursorType::kDndNone:
return "dnd-none";
case mojom::CursorType::kDndMove:
return "dnd-move";
case mojom::CursorType::kDndCopy:
return "dnd-copy";
case mojom::CursorType::kDndLink:
return "dnd-link";
case mojom::CursorType::kCustom:
NOTREACHED();
return "left_ptr";
}
NOTREACHED() << "Case not handled for " << static_cast<int>(id);
return "left_ptr";
}
bool GetCursorDataFor(CursorSize cursor_size,
mojom::CursorType id,
float scale_factor,
......
......@@ -20,10 +20,6 @@ enum class CursorSize;
const int kAnimatedCursorFrameDelayMs = 25;
// Returns CSS cursor name from an Aura cursor ID.
COMPONENT_EXPORT(UI_BASE_CURSOR)
const char* CursorCssNameFromId(mojom::CursorType id);
// Returns data about |id|, where id is a cursor constant like
// ui::mojom::CursorType::kHelp. The IDR will be placed in |resource_id| and
// the hotspots for the different DPIs will be placed in |hot_1x| and
......
......@@ -74,6 +74,7 @@ jumbo_component("x") {
"//ui/base:hit_test",
"//ui/base:wm_role_names",
"//ui/base/clipboard:clipboard_types",
"//ui/base/cursor/mojom:cursor_type",
"//ui/base/dragdrop/file_info",
"//ui/display/util",
"//ui/events",
......
......@@ -21,12 +21,14 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/message_loop/message_loop_current.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
......@@ -42,6 +44,7 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkTypes.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/base/x/x11_menu_list.h"
#include "ui/base/x/x11_util_internal.h"
#include "ui/events/devices/x11/device_data_manager_x11.h"
......@@ -259,6 +262,119 @@ SkBitmap ConvertSkBitmapToUnpremul(const SkBitmap& bitmap) {
return converted_bitmap;
}
// Returns a cursor name, compatible with either X11 or the FreeDesktop.org
// cursor spec
// (https://www.x.org/releases/current/doc/libX11/libX11/libX11.html#x_font_cursors
// and https://www.freedesktop.org/wiki/Specifications/cursor-spec/), followed
// by fallbacks that can work as replacements in some environments where the
// original may not be available (e.g. desktop environments other than
// GNOME and KDE).
// TODO(hferreiro): each list starts with the FreeDesktop.org icon name but
// "ns-resize", "ew-resize", "nesw-resize", "nwse-resize", "grab", "grabbing",
// which were not available in older versions of Breeze, the default KDE theme.
std::vector<const char*> CursorNamesFromType(mojom::CursorType type) {
switch (type) {
case mojom::CursorType::kMove:
// Returning "move" is the correct thing here, but Blink doesn't make a
// distinction between move and all-scroll. Other platforms use a cursor
// more consistent with all-scroll, so use that.
case mojom::CursorType::kMiddlePanning:
case mojom::CursorType::kMiddlePanningVertical:
case mojom::CursorType::kMiddlePanningHorizontal:
return {"all-scroll", "fleur"};
case mojom::CursorType::kEastPanning:
case mojom::CursorType::kEastResize:
return {"e-resize", "right_side"};
case mojom::CursorType::kNorthPanning:
case mojom::CursorType::kNorthResize:
return {"n-resize", "top_side"};
case mojom::CursorType::kNorthEastPanning:
case mojom::CursorType::kNorthEastResize:
return {"ne-resize", "top_right_corner"};
case mojom::CursorType::kNorthWestPanning:
case mojom::CursorType::kNorthWestResize:
return {"nw-resize", "top_left_corner"};
case mojom::CursorType::kSouthPanning:
case mojom::CursorType::kSouthResize:
return {"s-resize", "bottom_side"};
case mojom::CursorType::kSouthEastPanning:
case mojom::CursorType::kSouthEastResize:
return {"se-resize", "bottom_right_corner"};
case mojom::CursorType::kSouthWestPanning:
case mojom::CursorType::kSouthWestResize:
return {"sw-resize", "bottom_left_corner"};
case mojom::CursorType::kWestPanning:
case mojom::CursorType::kWestResize:
return {"w-resize", "left_side"};
case mojom::CursorType::kNone:
return {"none"};
case mojom::CursorType::kGrab:
return {"openhand", "grab"};
case mojom::CursorType::kGrabbing:
return {"closedhand", "grabbing", "hand2"};
case mojom::CursorType::kCross:
return {"crosshair", "cross"};
case mojom::CursorType::kHand:
return {"pointer", "hand", "hand2"};
case mojom::CursorType::kIBeam:
return {"text", "xterm"};
case mojom::CursorType::kProgress:
return {"progress", "left_ptr_watch", "watch"};
case mojom::CursorType::kWait:
return {"wait", "watch"};
case mojom::CursorType::kHelp:
return {"help"};
case mojom::CursorType::kNorthSouthResize:
return {"sb_v_double_arrow", "ns-resize"};
case mojom::CursorType::kEastWestResize:
return {"sb_h_double_arrow", "ew-resize"};
case mojom::CursorType::kColumnResize:
return {"col-resize", "sb_h_double_arrow"};
case mojom::CursorType::kRowResize:
return {"row-resize", "sb_v_double_arrow"};
case mojom::CursorType::kNorthEastSouthWestResize:
return {"size_bdiag", "nesw-resize", "fd_double_arrow"};
case mojom::CursorType::kNorthWestSouthEastResize:
return {"size_fdiag", "nwse-resize", "bd_double_arrow"};
case mojom::CursorType::kVerticalText:
return {"vertical-text"};
case mojom::CursorType::kZoomIn:
return {"zoom-in"};
case mojom::CursorType::kZoomOut:
return {"zoom-out"};
case mojom::CursorType::kCell:
return {"cell", "plus"};
case mojom::CursorType::kContextMenu:
return {"context-menu"};
case mojom::CursorType::kAlias:
return {"alias"};
case mojom::CursorType::kNoDrop:
return {"no-drop"};
case mojom::CursorType::kCopy:
return {"copy"};
case mojom::CursorType::kNotAllowed:
return {"not-allowed", "crossed_circle"};
case mojom::CursorType::kDndNone:
return {"dnd-none", "hand2"};
case mojom::CursorType::kDndMove:
return {"dnd-move", "hand2"};
case mojom::CursorType::kDndCopy:
return {"dnd-copy", "hand2"};
case mojom::CursorType::kDndLink:
return {"dnd-link", "hand2"};
case mojom::CursorType::kCustom:
// kCustom is for custom image cursors. The platform cursor will be set
// at WebCursor::GetPlatformCursor().
NOTREACHED();
FALLTHROUGH;
case mojom::CursorType::kNull:
case mojom::CursorType::kPointer:
return {"left_ptr"};
}
NOTREACHED();
return {"left_ptr"};
}
} // namespace
void DeleteProperty(x11::Window window, x11::Atom name) {
......@@ -354,6 +470,15 @@ XcursorImage* SkBitmapToXcursorImage(const SkBitmap& cursor_image,
return image;
}
::Cursor LoadCursorFromType(mojom::CursorType type) {
for (auto* name : CursorNamesFromType(type)) {
::Cursor cursor = XcursorLibraryLoadCursor(gfx::GetXDisplay(), name);
if (cursor != x11::None)
return cursor;
}
return x11::None;
}
int CoalescePendingMotionEvents(const x11::Event* x11_event,
x11::Event* last_event) {
const XEvent* xev = &x11_event->xlib_event();
......
......@@ -21,6 +21,7 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/platform_event.h"
......@@ -145,6 +146,11 @@ COMPONENT_EXPORT(UI_BASE_X)
XcursorImage* SkBitmapToXcursorImage(const SkBitmap& bitmap,
const gfx::Point& hotspot);
// Loads and returns an X11 cursor, trying to find one that matches |type|. If
// unavailable, x11::None is returned.
COMPONENT_EXPORT(UI_BASE_X)
::Cursor LoadCursorFromType(mojom::CursorType type);
// 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|.
......
......@@ -37,6 +37,7 @@ source_set("x11") {
public_deps = [
"//ui/base/cursor:cursor_base",
"//ui/base/cursor/mojom:cursor_type",
"//ui/base/x",
]
deps = [
......@@ -50,7 +51,6 @@ source_set("x11") {
"//ui/base/clipboard:clipboard_types",
"//ui/base/cursor",
"//ui/base/ime",
"//ui/base/x",
"//ui/base/x:gl",
"//ui/display/fake",
"//ui/events",
......
......@@ -8,6 +8,7 @@
#include "ui/base/cursor/cursor_lookup.h"
#include "ui/base/cursor/cursors_aura.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/geometry/point.h"
namespace ui {
......@@ -91,16 +92,16 @@ scoped_refptr<X11CursorOzone> X11CursorFactoryOzone::GetDefaultCursorInternal(
if (!default_cursors_.count(type)) {
// First try to load a predefined X11 cursor.
auto cursor =
base::MakeRefCounted<X11CursorOzone>(CursorCssNameFromId(type));
if (cursor->xcursor() != x11::None) {
::Cursor xcursor = LoadCursorFromType(type);
if (xcursor != x11::None) {
auto cursor = base::MakeRefCounted<X11CursorOzone>(xcursor);
default_cursors_[type] = cursor;
return cursor;
}
// Loads the default aura cursor bitmap for cursor type. Falls back on
// pointer cursor then invisible cursor if this fails.
cursor = CreateAuraX11Cursor(type);
auto cursor = CreateAuraX11Cursor(type);
if (!cursor.get()) {
if (type != mojom::CursorType::kPointer) {
cursor = GetDefaultCursorInternal(mojom::CursorType::kPointer);
......
......@@ -8,7 +8,6 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/x/x11.h"
namespace ui {
......@@ -36,19 +35,13 @@ X11CursorOzone::X11CursorOzone(const std::vector<SkBitmap>& bitmaps,
XcursorImagesDestroy(images);
}
X11CursorOzone::X11CursorOzone(const char* name) {
xcursor_ = XcursorLibraryLoadCursor(gfx::GetXDisplay(), name);
}
X11CursorOzone::X11CursorOzone(::Cursor xcursor) : xcursor_(xcursor) {}
// static
scoped_refptr<X11CursorOzone> X11CursorOzone::CreateInvisible() {
scoped_refptr<X11CursorOzone> invisible_ = new X11CursorOzone();
invisible_->xcursor_ = CreateInvisibleCursor();
return invisible_;
return base::MakeRefCounted<X11CursorOzone>(CreateInvisibleCursor());
}
X11CursorOzone::X11CursorOzone() {}
X11CursorOzone::~X11CursorOzone() {
XFreeCursor(gfx::GetXDisplay(), xcursor_);
}
......
......@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "ui/base/cursor/cursor.h"
#include "ui/gfx/x/x11.h"
......@@ -29,23 +30,20 @@ class X11CursorOzone : public base::RefCounted<X11CursorOzone> {
X11CursorOzone(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& hotspot,
int frame_delay_ms);
// Loads an X11 cursor named |name| by calling XcursorLibraryLoadCursor().
// May end up wrapping an x11::None so validity must be checked after using
// this constructor.
explicit X11CursorOzone(const char* name);
// Wraps an X11 cursor |xcursor|.
explicit X11CursorOzone(::Cursor xcursor);
// Creates a new cursor that is invisible.
static scoped_refptr<X11CursorOzone> CreateInvisible();
XID xcursor() const { return xcursor_; }
::Cursor xcursor() const { return xcursor_; }
private:
friend class base::RefCounted<X11CursorOzone>;
X11CursorOzone();
~X11CursorOzone();
XID xcursor_ = x11::None;
::Cursor xcursor_ = x11::None;
DISALLOW_COPY_AND_ASSIGN(X11CursorOzone);
};
......
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