diff options
Diffstat (limited to '')
-rw-r--r-- | src/sp-cursor.cpp | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/sp-cursor.cpp b/src/sp-cursor.cpp new file mode 100644 index 0000000..dd8a300 --- /dev/null +++ b/src/sp-cursor.cpp @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Some convenience stuff + * + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Jasper van de Gronde <th.v.d.gronde@hccnet.nl> + * Jon A. Cruz <jon@joncruz.org> + * Kris De Gussem <Kris.DeGussem@gmail.com> + * + * 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 <cstring> +#include <gdk/gdk.h> +#include <map> +#include <sstream> + +#include "color.h" +#include "sp-cursor.h" + +static void free_cursor_data(unsigned char *pixels, void* /*data*/) { + delete [] reinterpret_cast<guint32*>(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<guint32>(v[0]) << 0) + | (static_cast<guint32>(v[1]) << 8) + | (static_cast<guint32>(v[2]) << 16) + | (static_cast<guint32>(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<char, RGBA> 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<char, RGBA>::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<guchar*>(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 : |