diff --git a/src/sp-cursor.cpp b/src/sp-cursor.cpp
index b60d481b872c0086589e455fcdcd6980db7cc845..cc52f3c97288943753117a1de91e512d52d1e77f 100644 (file)
--- a/src/sp-cursor.cpp
+++ b/src/sp-cursor.cpp
-#define __SP_CURSOR_C__
-
/*
- * Use a pixmap to make a cursor.
+ * Some convenience stuff
*
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
- * James ----
+ * Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
+ * Jon A. Cruz <jon@joncruz.org>
*
- * Copyright (C) 1999-2006 authors
+ * Copyright (C) 1999-2002 authors
* Copyright (C) 2001-2002 Ximian, Inc.
+ * Copyright (C) 2010 Jasper van de Gronde
+ * Copyright (C) 2010 Jon A. Cruz
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <cstdio>
-#include <string.h>
+#include <cstring>
+#include <string>
#include <ctype.h>
+#include <map>
+#include "color.h"
#include "sp-cursor.h"
-GdkCursor *sp_cursor_new (GdkDisplay *display, GdkPixbuf *pixbuf, gchar **xpm, gint hot_x, gint hot_y)
+void sp_cursor_bitmap_and_mask_from_xpm(GdkBitmap **bitmap, GdkBitmap **mask, gchar const *const *xpm)
{
- GdkCursor *new_cursor=NULL;
+ int height = 0;
+ int width = 0;
+ int colors = 0;
+ int pix = 0;
+ sscanf(xpm[0], "%d %d %d %d", &height, &width, &colors, &pix);
+
+ g_return_if_fail(height == 32);
+ g_return_if_fail(width == 32);
+ g_return_if_fail(colors >= 3);
+
+ int transparent_color = ' ';
+ std::string black_colors;
+
+ char pixmap_buffer[(32 * 32) / 8] = {0};
+ char mask_buffer[(32 * 32) / 8] = {0};
+
+ for (int i = 0; i < colors; i++) {
+
+ char const *p = xpm[1 + i];
+ char const ccode = *p;
+
+ p++;
+ while (isspace(*p)) {
+ p++;
+ }
+ p++;
+ while (isspace(*p)) {
+ p++;
+ }
+
+ if (strcmp(p, "None") == 0) {
+ transparent_color = ccode;
+ }
+
+ if (strcmp(p, "Stroke") == 0) {
+ black_colors.push_back(ccode);
+ }
- if ((!pixbuf && xpm) || !gdk_display_supports_cursor_alpha(display))
- //if there is no pixbuf, but there is xpm data, or the display
- //doesn't support alpha, use bitmap cursor.
- {
- pixbuf=gdk_pixbuf_new_from_xpm_data((const char**)xpm);
+ if (strcmp(p, "#000000") == 0) {
+ black_colors.push_back(ccode);
+ }
}
- if(pixbuf) {
- new_cursor = gdk_cursor_new_from_pixbuf(display,pixbuf,hot_x,hot_y);
+
+ for (int y = 0; y < 32; y++) {
+ for (int x = 0; x < 32; ) {
+ char value = 0;
+ char maskv = 0;
+
+ for (int pix = 0; pix < 8; pix++, x++){
+ if (xpm[1 + colors + y][x] != transparent_color) {
+ maskv |= 1 << pix;
+
+ if (black_colors.find(xpm[1 + colors + y][x]) != std::string::npos) {
+ value |= 1 << pix;
+ }
+ }
+ }
+
+ pixmap_buffer[(y * 4 + x / 8) - 1] = value;
+ mask_buffer[(y * 4 + x / 8) - 1] = maskv;
+ }
}
- return new_cursor;
+
+ *bitmap = gdk_bitmap_create_from_data(NULL, pixmap_buffer, 32, 32);
+ *mask = gdk_bitmap_create_from_data(NULL, mask_buffer, 32, 32);
}
+static void free_cursor_data(guchar *pixels, gpointer data) {
+ delete [] reinterpret_cast<guint32*>(pixels);
+}
+
+struct RGBA {
+ guchar v[4];
+ RGBA() {
+ v[0] = 0;
+ v[1] = 0;
+ v[2] = 0;
+ v[3] = 0;
+ }
-GdkCursor *sp_cursor_new_from_xpm (gchar **xpm, gint hot_x, gint hot_y)
+ 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;
+ }
+};
+
+GdkPixbuf *sp_cursor_pixbuf_from_xpm(gchar const *const *xpm, GdkColor const& black, GdkColor const& white, guint32 fill, guint32 stroke)
{
- GdkDisplay *display=gdk_display_get_default();
- GdkPixbuf *pixbuf=NULL;
- GdkCursor *new_cursor=NULL;
- pixbuf=gdk_pixbuf_new_from_xpm_data((const char**)xpm);
- if (pixbuf != NULL){
- new_cursor = gdk_cursor_new_from_pixbuf(display,pixbuf,hot_x,hot_y);
- g_message("xpm cursor defined\n");
- return new_cursor;
+ int height = 0;
+ int width = 0;
+ int colors = 0;
+ int pix = 0;
+ sscanf(xpm[0], "%d %d %d %d", &height, &width, &colors, &pix);
+
+ //g_return_if_fail (height == 32);
+ //g_return_if_fail (width == 32);
+ //g_return_if_fail (colors >= 3);
+
+ std::map<char, RGBA> colorMap;
+
+ for (int i = 0; i < colors; i++) {
+
+ char const *p = xpm[1 + i];
+ char const ccode = *p;
+
+ p++;
+ while (isspace(*p)) {
+ p++;
+ }
+ p++;
+ while (isspace(*p)) {
+ p++;
+ }
+
+ if (strcmp(p, "None") == 0) {
+ colorMap[ccode] = RGBA();
+ } else 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 (strcmp(p, "#000000") == 0) {
+ colorMap[ccode] = RGBA(black.red, black.green, black.blue, 255);
+ } else if (strcmp(p, "#FFFFFF") == 0) {
+ colorMap[ccode] = RGBA(white.red, white.green, white.blue, 255);
+ } else {
+ colorMap[ccode] = RGBA();
+ }
}
- g_warning("xpm cursor not defined\n");
- return NULL;
-}
+ 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;
+ }
+ }
+ return gdk_pixbuf_new_from_data(reinterpret_cast<guchar*>(pixmap_buffer), GDK_COLORSPACE_RGB, TRUE, 8, width, height, width * sizeof(guint32), free_cursor_data, NULL);
+}
-GdkCursor *sp_cursor_new_from_pixbuf (GdkPixbuf *pixbuf, gint hot_x, gint hot_y)
+GdkCursor *sp_cursor_new_from_xpm(gchar const *const *xpm, gint hot_x, gint hot_y)
{
- GdkDisplay *display=gdk_display_get_default();
- GdkCursor *new_cursor=NULL;
- if (pixbuf) {
- new_cursor = gdk_cursor_new_from_pixbuf(display,pixbuf,hot_x,hot_y);
- g_message("pixbuf cursor defined\n");
- return new_cursor;
- }
- g_warning("pixbuf cursor not defined\n");
- return new_cursor;
- return NULL;
+ GdkCursor *cursor = 0;
+ GdkColor const fg = { 0, 0, 0, 0 };
+ GdkColor const bg = { 0, 65535, 65535, 65535 };
+
+ GdkBitmap *bitmap = 0;
+ GdkBitmap *mask = 0;
+
+ sp_cursor_bitmap_and_mask_from_xpm(&bitmap, &mask, xpm);
+ if ( bitmap && mask ) {
+ cursor = gdk_cursor_new_from_pixmap(bitmap, mask,
+ &fg, &bg,
+ hot_x, hot_y);
+ g_object_unref(bitmap);
+ g_object_unref(mask);
+ }
+
+ return cursor;
}
/*