// Copyright (c) 2011 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 "webkit/glue/webcursor.h" #include <gdk/gdk.h> #include <gtk/gtk.h> #include "base/logging.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" #include "ui/gfx/gtk_util.h" using WebKit::WebCursorInfo; namespace { // webcursor_gtk_data.h is taken directly from WebKit's CursorGtk.h. #include "webkit/glue/webcursor_gtk_data.h" // This helper function is taken directly from WebKit's CursorGtk.cpp. // It attempts to create a custom cursor from the data inlined in // webcursor_gtk_data.h. GdkCursor* GetInlineCustomCursor(CustomCursorType type) { static GdkCursor* CustomCursorsGdk[G_N_ELEMENTS(CustomCursors)]; GdkCursor* cursor = CustomCursorsGdk[type]; if (cursor) return cursor; const CustomCursor& custom = CustomCursors[type]; cursor = gdk_cursor_new_from_name(gdk_display_get_default(), custom.name); if (!cursor) { const GdkColor fg = { 0, 0, 0, 0 }; const GdkColor bg = { 65535, 65535, 65535, 65535 }; GdkPixmap* source = gdk_bitmap_create_from_data(NULL, custom.bits, 32, 32); GdkPixmap* mask = gdk_bitmap_create_from_data(NULL, custom.mask_bits, 32, 32); cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, custom.hot_x, custom.hot_y); g_object_unref(source); g_object_unref(mask); } CustomCursorsGdk[type] = cursor; return cursor; } // For GTK 2.16 and beyond, GDK_BLANK_CURSOR is available. Before, we have to // use a custom cursor. #if !GTK_CHECK_VERSION(2, 16, 0) // Get/create a custom cursor which is invisible. GdkCursor* GetInvisibleCustomCursor() { static GdkCursor* cursor = NULL; if (cursor) return cursor; const char bits[] = { 0 }; const GdkColor color = { 0, 0, 0, 0 }; GdkPixmap* bitmap = gdk_bitmap_create_from_data(NULL, bits, 1, 1); cursor = gdk_cursor_new_from_pixmap(bitmap, bitmap, &color, &color, 0, 0); g_object_unref(bitmap); return cursor; } #endif } // end anonymous namespace int WebCursor::GetCursorType() const { // http://library.gnome.org/devel/gdk/2.12/gdk-Cursors.html has images // of the default X theme, but beware that the user's cursor theme can // change everything. switch (type_) { case WebCursorInfo::TypePointer: return GDK_LAST_CURSOR; case WebCursorInfo::TypeCross: return GDK_CROSS; case WebCursorInfo::TypeHand: return GDK_HAND2; case WebCursorInfo::TypeIBeam: return GDK_XTERM; case WebCursorInfo::TypeWait: return GDK_WATCH; case WebCursorInfo::TypeHelp: return GDK_QUESTION_ARROW; case WebCursorInfo::TypeEastResize: return GDK_RIGHT_SIDE; case WebCursorInfo::TypeNorthResize: return GDK_TOP_SIDE; case WebCursorInfo::TypeNorthEastResize: return GDK_TOP_RIGHT_CORNER; case WebCursorInfo::TypeNorthWestResize: return GDK_TOP_LEFT_CORNER; case WebCursorInfo::TypeSouthResize: return GDK_BOTTOM_SIDE; case WebCursorInfo::TypeSouthEastResize: return GDK_BOTTOM_RIGHT_CORNER; case WebCursorInfo::TypeSouthWestResize: return GDK_BOTTOM_LEFT_CORNER; case WebCursorInfo::TypeWestResize: return GDK_LEFT_SIDE; case WebCursorInfo::TypeNorthSouthResize: return GDK_SB_V_DOUBLE_ARROW; case WebCursorInfo::TypeEastWestResize: return GDK_SB_H_DOUBLE_ARROW; case WebCursorInfo::TypeNorthEastSouthWestResize: case WebCursorInfo::TypeNorthWestSouthEastResize: // There isn't really a useful cursor available for these. NOTIMPLEMENTED(); return GDK_LAST_CURSOR; case WebCursorInfo::TypeColumnResize: return GDK_SB_H_DOUBLE_ARROW; // TODO(evanm): is this correct? case WebCursorInfo::TypeRowResize: return GDK_SB_V_DOUBLE_ARROW; // TODO(evanm): is this correct? case WebCursorInfo::TypeMiddlePanning: return GDK_FLEUR; case WebCursorInfo::TypeEastPanning: return GDK_SB_RIGHT_ARROW; case WebCursorInfo::TypeNorthPanning: return GDK_SB_UP_ARROW; case WebCursorInfo::TypeNorthEastPanning: return GDK_TOP_RIGHT_CORNER; case WebCursorInfo::TypeNorthWestPanning: return GDK_TOP_LEFT_CORNER; case WebCursorInfo::TypeSouthPanning: return GDK_SB_DOWN_ARROW; case WebCursorInfo::TypeSouthEastPanning: return GDK_BOTTOM_RIGHT_CORNER; case WebCursorInfo::TypeSouthWestPanning: return GDK_BOTTOM_LEFT_CORNER; case WebCursorInfo::TypeWestPanning: return GDK_SB_LEFT_ARROW; case WebCursorInfo::TypeMove: return GDK_FLEUR; case WebCursorInfo::TypeVerticalText: NOTIMPLEMENTED(); return GDK_LAST_CURSOR; case WebCursorInfo::TypeCell: NOTIMPLEMENTED(); return GDK_LAST_CURSOR; case WebCursorInfo::TypeContextMenu: NOTIMPLEMENTED(); return GDK_LAST_CURSOR; case WebCursorInfo::TypeAlias: NOTIMPLEMENTED(); return GDK_LAST_CURSOR; case WebCursorInfo::TypeProgress: return GDK_WATCH; case WebCursorInfo::TypeNoDrop: NOTIMPLEMENTED(); return GDK_LAST_CURSOR; case WebCursorInfo::TypeCopy: NOTIMPLEMENTED(); return GDK_LAST_CURSOR; case WebCursorInfo::TypeNone: // See comment above |GetInvisibleCustomCursor()|. #if !GTK_CHECK_VERSION(2, 16, 0) return GDK_CURSOR_IS_PIXMAP; #else return GDK_BLANK_CURSOR; #endif case WebCursorInfo::TypeNotAllowed: NOTIMPLEMENTED(); return GDK_LAST_CURSOR; case WebCursorInfo::TypeZoomIn: case WebCursorInfo::TypeZoomOut: case WebCursorInfo::TypeGrab: case WebCursorInfo::TypeGrabbing: case WebCursorInfo::TypeCustom: return GDK_CURSOR_IS_PIXMAP; } NOTREACHED(); return GDK_LAST_CURSOR; } gfx::NativeCursor WebCursor::GetNativeCursor() { int type = GetCursorType(); if (type == GDK_CURSOR_IS_PIXMAP) return GetCustomCursor(); return gfx::GetCursor(type); } GdkCursor* WebCursor::GetCustomCursor() { switch (type_) { // See comment above |GetInvisibleCustomCursor()|. #if !GTK_CHECK_VERSION(2, 16, 0) case WebCursorInfo::TypeNone: return GetInvisibleCustomCursor(); #endif case WebCursorInfo::TypeZoomIn: return GetInlineCustomCursor(CustomCursorZoomIn); case WebCursorInfo::TypeZoomOut: return GetInlineCustomCursor(CustomCursorZoomOut); case WebCursorInfo::TypeGrab: return GetInlineCustomCursor(CustomCursorGrab); case WebCursorInfo::TypeGrabbing: return GetInlineCustomCursor(CustomCursorGrabbing); } if (type_ != WebCursorInfo::TypeCustom) { NOTREACHED(); return NULL; } SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, custom_size_.width(), custom_size_.height()); bitmap.allocPixels(); memcpy(bitmap.getAddr32(0, 0), custom_data_.data(), custom_data_.size()); GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap); GdkCursor* cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf, hotspot_.x(), hotspot_.y()); gdk_pixbuf_unref(pixbuf); if (unref_) gdk_cursor_unref(unref_); unref_ = cursor; return cursor; } void WebCursor::InitPlatformData() { unref_ = NULL; return; } bool WebCursor::SerializePlatformData(Pickle* pickle) const { return true; } bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) { return true; } bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const { return true; } void WebCursor::CleanupPlatformData() { if (unref_) { gdk_cursor_unref(unref_); unref_ = NULL; } return; } void WebCursor::CopyPlatformData(const WebCursor& other) { if (other.unref_) unref_ = gdk_cursor_ref(other.unref_); return; }