summaryrefslogtreecommitdiffstats
path: root/src/sp-cursor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/sp-cursor.cpp')
-rw-r--r--src/sp-cursor.cpp152
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 :