// SPDX-License-Identifier: GPL-2.0-or-later /* * Some convenience stuff * * Authors: * Lauris Kaplinski * Jasper van de Gronde * Jon A. Cruz * Kris De Gussem * * Copyright (C) 1999-2002 authors * Copyright (C) 2001-2002 Ximian, Inc. * Copyright (C) 2010 Jasper van de Gronde * Copyright (C) 2010 Jon A. Cruz * Copyright (C) 2012 Kris De Gussem * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include #include #include #include #include "color.h" #include "sp-cursor.h" static void free_cursor_data(unsigned char *pixels, void* /*data*/) { delete [] reinterpret_cast(pixels); } struct RGBA { guchar v[4]; RGBA() { v[0] = 0; v[1] = 0; v[2] = 0; v[3] = 0; } RGBA(guchar r, guchar g, guchar b, guchar a) { v[0] = r; v[1] = g; v[2] = b; v[3] = a; } operator guint32() const { guint32 result = (static_cast(v[0]) << 0) | (static_cast(v[1]) << 8) | (static_cast(v[2]) << 16) | (static_cast(v[3]) << 24); return result; } }; GdkCursor *sp_cursor_from_xpm(char const *const *xpm, guint32 fill, guint32 stroke) { GdkPixbuf *pixbuf; GdkCursor *cursor = nullptr; GdkDisplay *display = gdk_display_get_default(); int height = 0; int width = 0; int colors = 0; int pix = 0; int hot_x = 0; int hot_y = 0; std::stringstream ss (std::stringstream::in | std::stringstream::out); ss << xpm[0]; ss >> height; ss >> width; ss >> colors; ss >> pix; ss >> hot_x; ss >> hot_y; if (gdk_display_supports_cursor_alpha(display) && gdk_display_supports_cursor_color(display)) { std::map colorMap; for (int i = 0; i < colors; i++) { char const *p = xpm[1 + i]; g_assert(*p >=0); unsigned char const ccode = (guchar) *p; p++; while (isspace(*p)) { p++; } p++; while (isspace(*p)) { p++; } if (strcmp(p, "Fill") == 0) { colorMap[ccode] = RGBA(SP_RGBA32_R_U(fill), SP_RGBA32_G_U(fill), SP_RGBA32_B_U(fill), SP_RGBA32_A_U(fill)); } else if (strcmp(p, "Stroke") == 0) { colorMap[ccode] = RGBA(SP_RGBA32_R_U(stroke), SP_RGBA32_G_U(stroke), SP_RGBA32_B_U(stroke), SP_RGBA32_A_U(stroke)); } else if (p[0] == '#') { GdkRGBA color; if (gdk_rgba_parse(&color, p)) { colorMap[ccode] = RGBA(color.red * 255, color.green * 255, color.blue * 255, color.alpha * 255); } else { colorMap[ccode] = RGBA(); } } else { // Catches 'None' colorMap[ccode] = RGBA(); } } guint32 *pixmap_buffer = new guint32[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { std::map::const_iterator it = colorMap.find(xpm[1 + colors + y][x]); pixmap_buffer[y * width + x] = (it == colorMap.end()) ? 0u : it->second; } } #if G_BYTE_ORDER == G_BIG_ENDIAN for (int i = 0, n = width * height; i < n; i++) { guint32 v = pixmap_buffer[i]; pixmap_buffer[i] = ((v & 0xFF) << 24) | (((v >> 8) & 0xFF) << 16) | (((v >> 16) & 0xFF) << 8) | ((v >> 24) & 0xFF); } #endif pixbuf = gdk_pixbuf_new_from_data(reinterpret_cast(pixmap_buffer), GDK_COLORSPACE_RGB, TRUE, 8, width, height, width * sizeof(guint32), free_cursor_data, nullptr); } else { pixbuf = gdk_pixbuf_new_from_xpm_data((const gchar **)xpm); } if (pixbuf != nullptr) { cursor = gdk_cursor_new_from_pixbuf(display, pixbuf, hot_x, hot_y); g_object_unref(pixbuf); } else { g_warning("Failed to load cursor from xpm!"); } return cursor; } /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :