Home | History | Annotate | Download | only in glue
      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