1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "webkit/glue/webcursor.h" 6 7 #include <gdk/gdk.h> 8 #include <gtk/gtk.h> 9 10 #include "base/logging.h" 11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" 12 #include "ui/gfx/gtk_util.h" 13 14 using WebKit::WebCursorInfo; 15 16 namespace { 17 18 // webcursor_gtk_data.h is taken directly from WebKit's CursorGtk.h. 19 #include "webkit/glue/webcursor_gtk_data.h" 20 21 // This helper function is taken directly from WebKit's CursorGtk.cpp. 22 // It attempts to create a custom cursor from the data inlined in 23 // webcursor_gtk_data.h. 24 GdkCursor* GetInlineCustomCursor(CustomCursorType type) { 25 static GdkCursor* CustomCursorsGdk[G_N_ELEMENTS(CustomCursors)]; 26 GdkCursor* cursor = CustomCursorsGdk[type]; 27 if (cursor) 28 return cursor; 29 const CustomCursor& custom = CustomCursors[type]; 30 cursor = gdk_cursor_new_from_name(gdk_display_get_default(), custom.name); 31 if (!cursor) { 32 const GdkColor fg = { 0, 0, 0, 0 }; 33 const GdkColor bg = { 65535, 65535, 65535, 65535 }; 34 GdkPixmap* source = gdk_bitmap_create_from_data(NULL, custom.bits, 35 32, 32); 36 GdkPixmap* mask = gdk_bitmap_create_from_data(NULL, custom.mask_bits, 37 32, 32); 38 cursor = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 39 custom.hot_x, custom.hot_y); 40 g_object_unref(source); 41 g_object_unref(mask); 42 } 43 CustomCursorsGdk[type] = cursor; 44 return cursor; 45 } 46 47 // For GTK 2.16 and beyond, GDK_BLANK_CURSOR is available. Before, we have to 48 // use a custom cursor. 49 #if !GTK_CHECK_VERSION(2, 16, 0) 50 // Get/create a custom cursor which is invisible. 51 GdkCursor* GetInvisibleCustomCursor() { 52 static GdkCursor* cursor = NULL; 53 if (cursor) 54 return cursor; 55 const char bits[] = { 0 }; 56 const GdkColor color = { 0, 0, 0, 0 }; 57 GdkPixmap* bitmap = gdk_bitmap_create_from_data(NULL, bits, 1, 1); 58 cursor = gdk_cursor_new_from_pixmap(bitmap, bitmap, &color, &color, 0, 0); 59 g_object_unref(bitmap); 60 return cursor; 61 } 62 #endif 63 64 } // end anonymous namespace 65 66 int WebCursor::GetCursorType() const { 67 // http://library.gnome.org/devel/gdk/2.12/gdk-Cursors.html has images 68 // of the default X theme, but beware that the user's cursor theme can 69 // change everything. 70 switch (type_) { 71 case WebCursorInfo::TypePointer: 72 return GDK_LAST_CURSOR; 73 case WebCursorInfo::TypeCross: 74 return GDK_CROSS; 75 case WebCursorInfo::TypeHand: 76 return GDK_HAND2; 77 case WebCursorInfo::TypeIBeam: 78 return GDK_XTERM; 79 case WebCursorInfo::TypeWait: 80 return GDK_WATCH; 81 case WebCursorInfo::TypeHelp: 82 return GDK_QUESTION_ARROW; 83 case WebCursorInfo::TypeEastResize: 84 return GDK_RIGHT_SIDE; 85 case WebCursorInfo::TypeNorthResize: 86 return GDK_TOP_SIDE; 87 case WebCursorInfo::TypeNorthEastResize: 88 return GDK_TOP_RIGHT_CORNER; 89 case WebCursorInfo::TypeNorthWestResize: 90 return GDK_TOP_LEFT_CORNER; 91 case WebCursorInfo::TypeSouthResize: 92 return GDK_BOTTOM_SIDE; 93 case WebCursorInfo::TypeSouthEastResize: 94 return GDK_BOTTOM_RIGHT_CORNER; 95 case WebCursorInfo::TypeSouthWestResize: 96 return GDK_BOTTOM_LEFT_CORNER; 97 case WebCursorInfo::TypeWestResize: 98 return GDK_LEFT_SIDE; 99 case WebCursorInfo::TypeNorthSouthResize: 100 return GDK_SB_V_DOUBLE_ARROW; 101 case WebCursorInfo::TypeEastWestResize: 102 return GDK_SB_H_DOUBLE_ARROW; 103 case WebCursorInfo::TypeNorthEastSouthWestResize: 104 case WebCursorInfo::TypeNorthWestSouthEastResize: 105 // There isn't really a useful cursor available for these. 106 NOTIMPLEMENTED(); return GDK_LAST_CURSOR; 107 case WebCursorInfo::TypeColumnResize: 108 return GDK_SB_H_DOUBLE_ARROW; // TODO(evanm): is this correct? 109 case WebCursorInfo::TypeRowResize: 110 return GDK_SB_V_DOUBLE_ARROW; // TODO(evanm): is this correct? 111 case WebCursorInfo::TypeMiddlePanning: 112 return GDK_FLEUR; 113 case WebCursorInfo::TypeEastPanning: 114 return GDK_SB_RIGHT_ARROW; 115 case WebCursorInfo::TypeNorthPanning: 116 return GDK_SB_UP_ARROW; 117 case WebCursorInfo::TypeNorthEastPanning: 118 return GDK_TOP_RIGHT_CORNER; 119 case WebCursorInfo::TypeNorthWestPanning: 120 return GDK_TOP_LEFT_CORNER; 121 case WebCursorInfo::TypeSouthPanning: 122 return GDK_SB_DOWN_ARROW; 123 case WebCursorInfo::TypeSouthEastPanning: 124 return GDK_BOTTOM_RIGHT_CORNER; 125 case WebCursorInfo::TypeSouthWestPanning: 126 return GDK_BOTTOM_LEFT_CORNER; 127 case WebCursorInfo::TypeWestPanning: 128 return GDK_SB_LEFT_ARROW; 129 case WebCursorInfo::TypeMove: 130 return GDK_FLEUR; 131 case WebCursorInfo::TypeVerticalText: 132 NOTIMPLEMENTED(); return GDK_LAST_CURSOR; 133 case WebCursorInfo::TypeCell: 134 NOTIMPLEMENTED(); return GDK_LAST_CURSOR; 135 case WebCursorInfo::TypeContextMenu: 136 NOTIMPLEMENTED(); return GDK_LAST_CURSOR; 137 case WebCursorInfo::TypeAlias: 138 NOTIMPLEMENTED(); return GDK_LAST_CURSOR; 139 case WebCursorInfo::TypeProgress: 140 return GDK_WATCH; 141 case WebCursorInfo::TypeNoDrop: 142 NOTIMPLEMENTED(); return GDK_LAST_CURSOR; 143 case WebCursorInfo::TypeCopy: 144 NOTIMPLEMENTED(); return GDK_LAST_CURSOR; 145 case WebCursorInfo::TypeNone: 146 // See comment above |GetInvisibleCustomCursor()|. 147 #if !GTK_CHECK_VERSION(2, 16, 0) 148 return GDK_CURSOR_IS_PIXMAP; 149 #else 150 return GDK_BLANK_CURSOR; 151 #endif 152 case WebCursorInfo::TypeNotAllowed: 153 NOTIMPLEMENTED(); return GDK_LAST_CURSOR; 154 case WebCursorInfo::TypeZoomIn: 155 case WebCursorInfo::TypeZoomOut: 156 case WebCursorInfo::TypeGrab: 157 case WebCursorInfo::TypeGrabbing: 158 case WebCursorInfo::TypeCustom: 159 return GDK_CURSOR_IS_PIXMAP; 160 } 161 NOTREACHED(); 162 return GDK_LAST_CURSOR; 163 } 164 165 gfx::NativeCursor WebCursor::GetNativeCursor() { 166 int type = GetCursorType(); 167 if (type == GDK_CURSOR_IS_PIXMAP) 168 return GetCustomCursor(); 169 return gfx::GetCursor(type); 170 } 171 172 GdkCursor* WebCursor::GetCustomCursor() { 173 switch (type_) { 174 // See comment above |GetInvisibleCustomCursor()|. 175 #if !GTK_CHECK_VERSION(2, 16, 0) 176 case WebCursorInfo::TypeNone: 177 return GetInvisibleCustomCursor(); 178 #endif 179 case WebCursorInfo::TypeZoomIn: 180 return GetInlineCustomCursor(CustomCursorZoomIn); 181 case WebCursorInfo::TypeZoomOut: 182 return GetInlineCustomCursor(CustomCursorZoomOut); 183 case WebCursorInfo::TypeGrab: 184 return GetInlineCustomCursor(CustomCursorGrab); 185 case WebCursorInfo::TypeGrabbing: 186 return GetInlineCustomCursor(CustomCursorGrabbing); 187 } 188 189 if (type_ != WebCursorInfo::TypeCustom) { 190 NOTREACHED(); 191 return NULL; 192 } 193 194 SkBitmap bitmap; 195 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 196 custom_size_.width(), custom_size_.height()); 197 bitmap.allocPixels(); 198 memcpy(bitmap.getAddr32(0, 0), custom_data_.data(), custom_data_.size()); 199 200 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap); 201 GdkCursor* cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), 202 pixbuf, 203 hotspot_.x(), 204 hotspot_.y()); 205 206 gdk_pixbuf_unref(pixbuf); 207 208 if (unref_) 209 gdk_cursor_unref(unref_); 210 unref_ = cursor; 211 return cursor; 212 } 213 214 void WebCursor::InitPlatformData() { 215 unref_ = NULL; 216 return; 217 } 218 219 bool WebCursor::SerializePlatformData(Pickle* pickle) const { 220 return true; 221 } 222 223 bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) { 224 return true; 225 } 226 227 bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const { 228 return true; 229 } 230 231 void WebCursor::CleanupPlatformData() { 232 if (unref_) { 233 gdk_cursor_unref(unref_); 234 unref_ = NULL; 235 } 236 return; 237 } 238 239 void WebCursor::CopyPlatformData(const WebCursor& other) { 240 if (other.unref_) 241 unref_ = gdk_cursor_ref(other.unref_); 242 return; 243 } 244