From aaccacf4b2a410ebe89944b2fce50eb4a6046f1d Mon Sep 17 00:00:00 2001
From: deuce <>
Date: Wed, 31 Jan 2018 00:19:02 +0000
Subject: [PATCH] Add support for setpalette(uint32_t index, uint16_t r, g, b)

This sets a specific palette entry to the 48-bit colour specified.
Psychadelic palette shifting is now possible (X11 mode only so far).
---
 src/conio/ciolib.c   | 10 +++++++
 src/conio/ciolib.h   |  4 +++
 src/conio/x_cio.c    | 17 ++++++++++++
 src/conio/x_cio.h    |  1 +
 src/conio/x_events.c | 63 +++++++++++++++++++++++++++++++++++++++++++-
 src/conio/x_events.h | 12 ++++++++-
 6 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/src/conio/ciolib.c b/src/conio/ciolib.c
index 3e0345e4c8..2348ee0900 100644
--- a/src/conio/ciolib.c
+++ b/src/conio/ciolib.c
@@ -118,6 +118,7 @@ CIOLIBEXPORT char * CIOLIBCALL ciolib_getcliptext(void);
 CIOLIBEXPORT int CIOLIBCALL ciolib_get_window_info(int *width, int *height, int *xpos, int *ypos);
 CIOLIBEXPORT void CIOLIBCALL ciolib_setscaling(int new_value);
 CIOLIBEXPORT int CIOLIBCALL ciolib_getscaling(void);
+CIOLIBEXPORT int CIOLIBCALL ciolib_setpalette(uint32_t entry, uint16_t r, uint16_t g, uint16_t b);
 
 #if defined(WITH_SDL) || defined(WITH_SDL_AUDIO)
 int sdl_video_initialized = 0;
@@ -209,6 +210,7 @@ int try_x_init(int mode)
 		cio_api.get_window_info=x_get_window_info;
 		cio_api.setscaling=bitmap_setscaling;
 		cio_api.getscaling=bitmap_getscaling;
+		cio_api.setpalette=x_setpalette;
 		return(1);
 	}
 	return(0);
@@ -1574,3 +1576,11 @@ CIOLIBEXPORT int CIOLIBCALL ciolib_getscaling(void)
 		return(cio_api.getscaling());
 	return(1);
 }
+
+/* Optional */
+CIOLIBEXPORT int CIOLIBCALL ciolib_setpalette(uint32_t entry, uint16_t r, uint16_t g, uint16_t b)
+{
+	if(cio_api.setpalette)
+		return(cio_api.setpalette(entry, r, g, b));
+	return(1);
+}
diff --git a/src/conio/ciolib.h b/src/conio/ciolib.h
index 93cc89947f..7c089aace6 100644
--- a/src/conio/ciolib.h
+++ b/src/conio/ciolib.h
@@ -35,6 +35,7 @@
 #define _CIOLIB_H_
 
 #include <string.h>	/* size_t */
+#include "gen_defs.h"
 
 #ifdef CIOLIBEXPORT
         #undef CIOLIBEXPORT
@@ -311,6 +312,7 @@ typedef struct {
 	void	(*setscaling)	(int new_value);
 	int		(*getscaling)	(void);
 	int		*ESCDELAY;
+	int		(*setpalette)	(uint32_t entry, uint16_t r, uint16_t g, uint16_t b);
 } cioapi_t;
 
 CIOLIBEXPORTVAR cioapi_t cio_api;
@@ -379,6 +381,7 @@ CIOLIBEXPORT void CIOLIBCALL ciolib_setvideoflags(int flags);
 CIOLIBEXPORT int CIOLIBCALL ciolib_getvideoflags(void);
 CIOLIBEXPORT void CIOLIBCALL ciolib_setscaling(int flags);
 CIOLIBEXPORT int CIOLIBCALL ciolib_getscaling(void);
+CIOLIBEXPORT int CIOLIBCALL ciolib_setpalette(uint32_t entry, uint16_t r, uint16_t g, uint16_t b);
 
 /* DoorWay specific stuff that's only applicable to ANSI mode. */
 CIOLIBEXPORT void CIOLIBCALL ansi_ciolib_setdoorway(int enable);
@@ -440,6 +443,7 @@ CIOLIBEXPORT void CIOLIBCALL ansi_ciolib_setdoorway(int enable);
 	#define getvideoflags()			ciolib_getvideoflags()
 	#define setscaling(a)			ciolib_setscaling(a)
 	#define getscaling()			ciolib_getscaling()
+	#define setpalette(e,r,g,b)		ciolib_setpalette(e,r,g,b)
 #endif
 
 #ifdef WITH_SDL
diff --git a/src/conio/x_cio.c b/src/conio/x_cio.c
index 12baa80636..b95dd6fd2f 100644
--- a/src/conio/x_cio.c
+++ b/src/conio/x_cio.c
@@ -152,6 +152,19 @@ int x_get_window_info(int *width, int *height, int *xpos, int *ypos)
 	return(0);
 }
 
+int x_setpalette(uint32_t entry, uint16_t r, uint16_t g, uint16_t b)
+{
+	struct x11_local_event ev;
+
+	ev.type=X11_LOCAL_SETPALETTE;
+	ev.data.palette.index = entry;
+	ev.data.palette.r = r;
+	ev.data.palette.g = g;
+	ev.data.palette.b = b;
+	while(write(local_pipe[1], &ev, sizeof(ev))==-1);
+	return(0);
+}
+
 /* Mouse event/keyboard thread */
 void x11_mouse_thread(void *data)
 {
@@ -360,6 +373,10 @@ int x_init(void)
 		xp_dlclose(dl);
 		return(-1);
 	}
+	if((x11.XFreeColors=xp_dlsym(dl,XFreeColors))==NULL) {
+		xp_dlclose(dl);
+		return(-1);
+	}
 
 	if(sem_init(&pastebuf_set, 0, 0)) {
 		xp_dlclose(dl);
diff --git a/src/conio/x_cio.h b/src/conio/x_cio.h
index d3da2b38b4..af328d7a68 100644
--- a/src/conio/x_cio.h
+++ b/src/conio/x_cio.h
@@ -69,6 +69,7 @@ char *x_getcliptext(void);
 int x_setfont(int font, int force);
 int x_getfont(void);
 int x_loadfont(char *filename);
+int x_setpalette(uint32_t entry, uint16_t r, uint16_t g, uint16_t b);
 int x_get_window_info(int *width, int *height, int *xpos, int *ypos);
 void x11_drawrect(int xoffset,int yoffset,int width,int height,unsigned char *data);
 void x11_flush(void);
diff --git a/src/conio/x_events.c b/src/conio/x_events.c
index 39dc8ce47b..2181ba5085 100644
--- a/src/conio/x_events.c
+++ b/src/conio/x_events.c
@@ -71,7 +71,7 @@ static int old_scaling = 0;
 
 
 /* Array of Graphics Contexts */
-static GC gca[sizeof(dac_default)/sizeof(struct dac_colors)];
+static GC *gca = NULL;
 
 /* Array of pixel values to match all possible colours */
 static unsigned long *pixel = NULL;
@@ -235,6 +235,7 @@ static int init_window()
 
 	if (pixelsz < sizeof(dac_default)/sizeof(struct dac_colors)) {
 		unsigned long *newpixel;
+		GC *newgca;
 		size_t newpixelsz = sizeof(dac_default)/sizeof(struct dac_colors);
 
 		newpixel = realloc(pixel, sizeof(pixel[0])*newpixelsz);
@@ -242,6 +243,10 @@ static int init_window()
 			return -1;
 		pixel = newpixel;
 		pixelsz = newpixelsz;
+		newgca = realloc(gca, sizeof(gca[0])*newpixelsz);
+		if (newgca == NULL)
+			return -1;
+		gca = newgca;
 	}
 	/* Get the pixel and GC values */
 	for(i=0; i<sizeof(dac_default)/sizeof(struct dac_colors); i++) {
@@ -889,6 +894,59 @@ static void x11_terminate_event_thread(void)
 	sem_wait(&event_thread_complete);
 }
 
+static void local_set_palette(struct x11_palette_entry *p)
+{
+	unsigned long *newpixel;
+	struct GC *newgca;
+	size_t i;
+	size_t newpixelsz;
+    XGCValues gcv;
+	XColor color;
+
+	gcv.function = GXcopy;
+    gcv.foreground = white;
+    gcv.background = black;
+	gcv.graphics_exposures = False;
+
+	newpixelsz = p->index + 1;
+	if (pixelsz < newpixelsz) {
+		newpixel = realloc(pixel, sizeof(pixel[0])*newpixelsz);
+		if (newpixel == NULL)
+			// TODO: Handle failure!
+			return;
+		pixel = newpixel;
+		newgca = realloc(gca, sizeof(gca[0])*newpixelsz);
+		if (newgca == NULL)
+			// TODO: Handle failure!
+			return;
+		gca = newgca;
+		/* Set all empty colours to black. */
+		for (i = pixelsz; i < (newpixelsz-1); i++) {
+			color.red=0;
+			color.green=0;
+			color.blue=0;
+			if(x11.XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &color))
+				pixel[i]=color.pixel;
+			gcv.foreground=color.pixel;
+			gca[i]=x11.XCreateGC(dpy, win, GCFunction | GCForeground | GCBackground | GCGraphicsExposures, &gcv);
+		}
+		pixelsz = newpixelsz;
+	}
+	else {
+		/* Free old colour first */
+		x11.XFreeColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &pixel[p->index], 1, 0);
+	}
+	/* Now set new colour */
+	color.red=p->r;
+	color.green=p->g;
+	color.blue=p->b;
+	if(x11.XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &color))
+		pixel[p->index]=color.pixel;
+	gcv.foreground=color.pixel;
+	gca[p->index]=x11.XCreateGC(dpy, win, GCFunction | GCForeground | GCBackground | GCGraphicsExposures, &gcv);
+	expose_rect(0, 0, x11_window_width-1, x11_window_height-1);
+}
+
 void x11_event_thread(void *args)
 {
 	int x;
@@ -1005,6 +1063,9 @@ void x11_event_thread(void *args)
 						case X11_LOCAL_BEEP:
 							x11.XBell(dpy, 100);
 							break;
+						case X11_LOCAL_SETPALETTE:
+							local_set_palette(&lev.data.palette);
+							break;
 					}
 					tv.tv_sec=0;
 					tv.tv_usec=0;
diff --git a/src/conio/x_events.h b/src/conio/x_events.h
index 6e55daf619..1a83ea385e 100644
--- a/src/conio/x_events.h
+++ b/src/conio/x_events.h
@@ -23,6 +23,14 @@ enum x11_local_events {
 	,X11_LOCAL_DRAWRECT
 	,X11_LOCAL_FLUSH
 	,X11_LOCAL_BEEP
+	,X11_LOCAL_SETPALETTE
+};
+
+struct x11_palette_entry {
+	uint32_t	index;
+	uint16_t	r;
+	uint16_t	g;
+	uint16_t	b;
 };
 
 struct x11_local_event {
@@ -31,7 +39,8 @@ struct x11_local_event {
 		int		mode;
 		char	name[81];
 		char	title[81];
-		struct	update_rect rect; 
+		struct	update_rect rect;
+		struct	x11_palette_entry palette;
 	} data;
 };
 
@@ -83,6 +92,7 @@ struct x11 {
 	void	(*XSetWMProperties) (Display*, Window, XTextProperty*, XTextProperty*, char**, int, XSizeHints*, XWMHints*, XClassHint*);
 	Status	(*XSetWMProtocols) (Display*, Window, Atom *, int);
 	Atom	(*XInternAtom) (Display *, char *, Bool);
+	int		(*XFreeColors) (Display*, Colormap, unsigned long *, int, unsigned long);
 };
 
 
-- 
GitLab