1/* 2 * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com 3 * Copyright (C) 2007 Christian Dywan <christian@twotoasts.de> 4 * Copyright (C) 2010-2012 Igalia S.L. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "CursorGtk.h" 31#include "GtkVersioning.h" 32 33#include "Image.h" 34#include "IntPoint.h" 35#include "RefPtrCairo.h" 36#include <gdk/gdk.h> 37#include <gtk/gtk.h> 38#include <wtf/Assertions.h> 39 40namespace WebCore { 41 42static GRefPtr<GdkCursor> createNamedCursor(CustomCursorType cursorType) 43{ 44 CustomCursor cursor = CustomCursors[cursorType]; 45 GRefPtr<GdkCursor> c = adoptGRef(gdk_cursor_new_from_name(gdk_display_get_default(), cursor.name)); 46 if (c) 47 return c; 48 49 RefPtr<cairo_surface_t> source = adoptRef(cairo_image_surface_create_for_data(const_cast<unsigned char*>(cursor.bits), CAIRO_FORMAT_A1, 32, 32, 4)); 50 RefPtr<cairo_surface_t> mask = adoptRef(cairo_image_surface_create_for_data(const_cast<unsigned char*>(cursor.mask_bits), CAIRO_FORMAT_A1, 32, 32, 4)); 51 52 RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 32, 32)); 53 RefPtr<cairo_t> cr = adoptRef(cairo_create(surface.get())); 54 55 cairo_set_source_rgb(cr.get(), 1, 1, 1); 56 cairo_mask_surface(cr.get(), mask.get(), 0, 0); 57 58 cairo_set_source_surface(cr.get(), source.get(), 0, 0); 59 cairo_paint(cr.get()); 60 61#if GTK_CHECK_VERSION(3, 9, 12) 62 return adoptGRef(gdk_cursor_new_from_surface(gdk_display_get_default(), surface.get(), cursor.hot_x, cursor.hot_y)); 63#else 64 GRefPtr<GdkPixbuf> pixbuf = adoptGRef(gdk_pixbuf_get_from_surface(surface.get(), 0, 0, 32, 32)); 65 return adoptGRef(gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf.get(), cursor.hot_x, cursor.hot_y)); 66#endif 67} 68 69static GRefPtr<GdkCursor> createCustomCursor(Image* image, const IntPoint& hotSpot) 70{ 71 GRefPtr<GdkPixbuf> pixbuf = adoptGRef(image->getGdkPixbuf()); 72 73 if (!image->nativeImageForCurrentFrame() || !pixbuf) 74 return 0; 75 76 IntPoint effectiveHotSpot = determineHotSpot(image, hotSpot); 77 return adoptGRef(gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf.get(), effectiveHotSpot.x(), effectiveHotSpot.y())); 78} 79 80void Cursor::ensurePlatformCursor() const 81{ 82 if (m_platformCursor || m_type == Cursor::Pointer) 83 return; 84 85 switch (m_type) { 86 case Cursor::Pointer: 87 // A null GdkCursor is the default cursor for the window. 88 m_platformCursor = 0; 89 break; 90 case Cursor::Cross: 91 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_CROSS)); 92 break; 93 case Cursor::Hand: 94 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_HAND2)); 95 break; 96 case Cursor::IBeam: 97 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_XTERM)); 98 break; 99 case Cursor::Wait: 100 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_WATCH)); 101 break; 102 case Cursor::Help: 103 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_QUESTION_ARROW)); 104 break; 105 case Cursor::Move: 106 case Cursor::MiddlePanning: 107 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_FLEUR)); 108 break; 109 case Cursor::EastResize: 110 case Cursor::EastPanning: 111 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_RIGHT_SIDE)); 112 break; 113 case Cursor::NorthResize: 114 case Cursor::NorthPanning: 115 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_SIDE)); 116 break; 117 case Cursor::NorthEastResize: 118 case Cursor::NorthEastPanning: 119 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_RIGHT_CORNER)); 120 break; 121 case Cursor::NorthWestResize: 122 case Cursor::NorthWestPanning: 123 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_LEFT_CORNER)); 124 break; 125 case Cursor::SouthResize: 126 case Cursor::SouthPanning: 127 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_BOTTOM_SIDE)); 128 break; 129 case Cursor::SouthEastResize: 130 case Cursor::SouthEastPanning: 131 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER)); 132 break; 133 case Cursor::SouthWestResize: 134 case Cursor::SouthWestPanning: 135 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER)); 136 break; 137 case Cursor::WestResize: 138 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_LEFT_SIDE)); 139 break; 140 case Cursor::NorthSouthResize: 141 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_TEE)); 142 break; 143 case Cursor::EastWestResize: 144 case Cursor::WestPanning: 145 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_LEFT_SIDE)); 146 break; 147 case Cursor::NorthEastSouthWestResize: 148 case Cursor::NorthWestSouthEastResize: 149 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_SIZING)); 150 break; 151 case Cursor::ColumnResize: 152 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW)); 153 break; 154 case Cursor::RowResize: 155 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW)); 156 break; 157 case Cursor::VerticalText: 158 m_platformCursor = createNamedCursor(CustomCursorVerticalText); 159 break; 160 case Cursor::Cell: 161 m_platformCursor = adoptGRef(gdk_cursor_new(GDK_PLUS)); 162 break; 163 case Cursor::ContextMenu: 164 m_platformCursor = createNamedCursor(CustomCursorContextMenu); 165 break; 166 case Cursor::Alias: 167 m_platformCursor = createNamedCursor(CustomCursorAlias); 168 break; 169 case Cursor::Progress: 170 m_platformCursor = createNamedCursor(CustomCursorProgress); 171 break; 172 case Cursor::NoDrop: 173 case Cursor::NotAllowed: 174 m_platformCursor = createNamedCursor(CustomCursorNoDrop); 175 break; 176 case Cursor::Copy: 177 m_platformCursor = createNamedCursor(CustomCursorCopy); 178 break; 179 case Cursor::None: 180 m_platformCursor = createNamedCursor(CustomCursorNone); 181 break; 182 case Cursor::ZoomIn: 183 m_platformCursor = createNamedCursor(CustomCursorZoomIn); 184 break; 185 case Cursor::ZoomOut: 186 m_platformCursor = createNamedCursor(CustomCursorZoomOut); 187 break; 188 case Cursor::Grab: 189 m_platformCursor = createNamedCursor(CustomCursorGrab); 190 break; 191 case Cursor::Grabbing: 192 m_platformCursor = createNamedCursor(CustomCursorGrabbing); 193 break; 194 case Cursor::Custom: 195 m_platformCursor = createCustomCursor(m_image.get(), m_hotSpot); 196 break; 197 } 198} 199 200Cursor::Cursor(const Cursor& other) 201 : m_type(other.m_type) 202 , m_image(other.m_image) 203 , m_hotSpot(other.m_hotSpot) 204 , m_platformCursor(other.m_platformCursor) 205{ 206} 207 208Cursor& Cursor::operator=(const Cursor& other) 209{ 210 m_type = other.m_type; 211 m_image = other.m_image; 212 m_hotSpot = other.m_hotSpot; 213 m_platformCursor = other.m_platformCursor; 214 return *this; 215} 216 217Cursor::~Cursor() 218{ 219} 220 221} 222