From 6aa8b1b975466d6d47e38e5152af0d60cda130e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net>
Date: Mon, 5 Jun 2023 02:57:17 -0400
Subject: [PATCH] More rabidly comply with ICCM and EWMH

While we're hacking on that, make a first attempt at a generic
Atom access framework.

The only actual visible change that should occur here is that the
window will not resize larger than will fit on the current desktop
between various WM widgets (panels and menus).  I've been considering
this change for a while, but now that fullscreen support is present,
it doesn't really take anything away.
---
 src/conio/x_events.c    | 346 ++++++++++++++++++++++++++++++++--------
 src/conio/x_events.h    |   6 -
 src/syncterm/syncterm.c |   1 +
 3 files changed, 277 insertions(+), 76 deletions(-)

diff --git a/src/conio/x_events.c b/src/conio/x_events.c
index dde918a190..bab34f536c 100644
--- a/src/conio/x_events.c
+++ b/src/conio/x_events.c
@@ -52,10 +52,10 @@ sem_t	mode_set;
 int x11_window_xpos;
 int x11_window_ypos;
 int x11_initialized=0;
-sem_t	event_thread_complete;
-int	terminate = 0;
+static sem_t	event_thread_complete;
+static int	terminate = 0;
 Atom	copybuf_format;
-Atom	pastebuf_format;
+static Atom	pastebuf_format;
 bool xrender_found;
 bool xinerama_found;
 bool xrandr_found;
@@ -65,16 +65,82 @@ bool x_internal_scaling = true;
  * Local variables
  */
 
+enum UsedAtom {
+	// UTF8_STRING: https://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text
+	ATOM_UTF8_STRING,
+	// ICCM: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html
+	ATOM_TARGETS,
+	ATOM_WM_CLASS,
+	ATOM_WM_DELETE_WINDOW,
+	// EWMH: https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html
+	ATOM__NET_FRAME_EXTENTS,
+	ATOM__NET_SUPPORTED,
+	ATOM__NET_SUPPORTING_WM_CHECK,
+	ATOM__NET_WM_DESKTOP,
+	ATOM__NET_WM_ICON,
+	ATOM__NET_WM_ICON_NAME,
+	ATOM__NET_WM_NAME,
+	ATOM__NET_WM_PID,
+	ATOM__NET_WM_PING,
+	ATOM__NET_WM_STATE,
+	ATOM__NET_WM_STATE_FULLSCREEN,
+	ATOM__NET_WM_STATE_MAXIMIZED_VERT,
+	ATOM__NET_WM_STATE_MAXIMIZED_HORZ,
+	ATOM__NET_WM_WINDOW_TYPE,
+	ATOM__NET_WM_WINDOW_TYPE_NORMAL,
+	ATOM__NET_WORKAREA,
+	ATOMCOUNT
+};
+
+enum AtomStandard {
+	UTF8_ATOM,
+	ICCM_ATOM,
+	EWMH_ATOM
+};
+
+static uint32_t supported_standards;
+
+#define XA_UTF8_STRING (0x10000000UL)
+
+static struct AtomDef {
+	const char * const name;
+	const enum AtomStandard standard;
+	Atom req_type;
+	const int format;
+	Atom atom;
+	bool supported;
+} SupportedAtoms[ATOMCOUNT] = {
+	// UTF8_STRING: https://www.pps.jussieu.fr/~jch/software/UTF8_STRING/UTF8_STRING.text
+	{"UTF8_STRING", UTF8_ATOM, None, 0, None, false},
+	// ICCM: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html
+	{"TARGETS", ICCM_ATOM, XA_ATOM, 32, None, false},
+	{"WM_CLASS", ICCM_ATOM, XA_STRING, 8, None, false},
+	{"WM_DELETE_WINDOW", ICCM_ATOM, None, 0, None, false},
+	// EWMH: https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html
+	{"_NET_FRAME_EXTENTS", EWMH_ATOM, XA_CARDINAL, 32, None, false},
+	{"_NET_SUPPORTED", EWMH_ATOM, XA_ATOM, 32, None, false},
+	{"_NET_SUPPORTING_WM_CHECK", EWMH_ATOM, XA_WINDOW, 32, None, false},
+	{"_NET_WM_DESKTOP", EWMH_ATOM, XA_CARDINAL, 32, None, false},
+	{"_NET_WM_ICON", EWMH_ATOM, XA_CARDINAL, 32, None, false},
+	{"_NET_WM_ICON_NAME", EWMH_ATOM, XA_UTF8_STRING, 8, None, false},
+	{"_NET_WM_NAME", EWMH_ATOM, XA_UTF8_STRING, 8, None, false},
+	{"_NET_WM_PID", EWMH_ATOM, XA_CARDINAL, 32, None, false},
+	{"_NET_WM_PING", EWMH_ATOM, None, 0, None, false},
+	{"_NET_WM_STATE", EWMH_ATOM, XA_ATOM, 32, None, false},
+	{"_NET_WM_STATE_FULLSCREEN", EWMH_ATOM, None, 0, None, false},
+	{"_NET_WM_STATE_MAXIMIZED_VERT", EWMH_ATOM, None, 0, None, false},
+	{"_NET_WM_STATE_MAXIMIZED_HORZ", EWMH_ATOM, None, 0, None, false},
+	{"_NET_WM_WINDOW_TYPE", EWMH_ATOM, XA_ATOM, 32, None, false},
+	{"_NET_WM_WINDOW_TYPE_NORMAL", EWMH_ATOM, None, 0, None, false},
+	{"_NET_WORKAREA", EWMH_ATOM, XA_CARDINAL, 4, None, false},
+};
+
+#define A(name) SupportedAtoms[ATOM_ ## name].atom
+
 /* Sets the atom to be used for copy/paste operations */
 #define CONSOLE_CLIPBOARD	XA_PRIMARY
-static Atom WM_DELETE_WINDOW = None;
-static Atom _NET_WM_PING = None;
-static Atom _NET_WM_STATE = None;
 static const long _NET_WM_STATE_REMOVE = 0;
 static const long _NET_WM_STATE_ADD = 1;
-static Atom _NET_WM_STATE_FULLSCREEN = None;
-static Atom _NET_WM_STATE_MAXIMIZED_VERT = None;
-static Atom _NET_WM_STATE_MAXIMIZED_HORZ = None;
 
 static Display *dpy=NULL;
 static Window win;
@@ -226,6 +292,124 @@ static struct {
     {	0x8600, 0x5888, 0x8a00, 0x8c00 }, /* key 88 - F12 */
 };
 
+static struct AtomDef *
+get_atom_def(Atom atom)
+{
+	enum UsedAtom a;
+
+	for (a = 0; a < ATOMCOUNT; a++) {
+		if (SupportedAtoms[a].atom == atom)
+			return &SupportedAtoms[a];
+	}
+
+	return NULL;
+}
+
+static void
+initialize_atoms(void)
+{
+	enum UsedAtom a;
+	Atom atr;
+	int afr;
+	unsigned long nir;
+	unsigned long bytes_left = 4;
+	unsigned char *prop = NULL;
+	Window w;
+	Atom atom;
+	struct AtomDef *ad;
+	long offset;
+
+	supported_standards |= (1 << UTF8_ATOM);
+	supported_standards |= (1 << ICCM_ATOM);
+
+	for (a = 0; a < ATOMCOUNT; a++) {
+		SupportedAtoms[a].atom = x11.XInternAtom(dpy, (char *)SupportedAtoms[a].name, False);
+	}
+
+	if (A(UTF8_STRING) == None)
+		supported_standards &= ~(1 << UTF8_ATOM);
+
+	if (supported_standards & (1 << UTF8_ATOM)) {
+		if (x11.XGetWindowProperty(dpy, root, A(_NET_SUPPORTING_WM_CHECK), 0, 1, False, XA_WINDOW, &atr, &afr, &nir, &bytes_left, &prop) == Success) {
+			if (atr == XA_WINDOW) {
+				if (nir == 1) {
+					w = *(Window *)prop;
+					x11.XFree(prop);
+					prop = NULL;
+					if (x11.XGetWindowProperty(dpy, w, A(_NET_SUPPORTING_WM_CHECK), 0, 1, False, XA_WINDOW, &atr, &afr, &nir, &bytes_left, &prop) == Success) {
+						if (atr == XA_WINDOW) {
+							if (nir == 1) {
+								if (w == *(Window *)prop) {
+									supported_standards |= (1 << EWMH_ATOM);
+								}
+							}
+						}
+					}
+				}
+			}
+			if (prop != NULL)
+				x11.XFree(prop);
+		}
+	}
+
+	if (!(supported_standards & (1 << EWMH_ATOM))) {
+		for (a = 0; a < ATOMCOUNT; a++) {
+			if (SupportedAtoms[a].standard == EWMH_ATOM)
+				SupportedAtoms[a].atom = None;
+		}
+	}
+	else {
+		for (offset = 0, bytes_left = 1; bytes_left; offset += nir) {
+			if (x11.XGetWindowProperty(dpy, root, A(_NET_SUPPORTED), offset, 1, False, XA_ATOM, &atr, &afr, &nir, &bytes_left, &prop) != Success)
+				break;
+			if (atr != XA_ATOM) {
+				x11.XFree(prop);
+				break;
+			}
+			atom = *(Atom *)prop;
+			x11.XFree(prop);
+			if (atom != None) {
+				ad = get_atom_def(atom);
+				if (ad != NULL)
+					ad->supported = true;
+			}
+		}
+		for (a = 0; a < ATOMCOUNT; a++) {
+			if (SupportedAtoms[a].atom != None) {
+				if (SupportedAtoms[a].standard != EWMH_ATOM)
+					SupportedAtoms[a].supported = true;
+				if (!SupportedAtoms[a].supported) {
+					SupportedAtoms[a].atom = None;
+				}
+			}
+		}
+	}
+
+	for (a = 0; a < ATOMCOUNT; a++) {
+		if (SupportedAtoms[a].req_type == XA_UTF8_STRING) {
+			if (A(UTF8_STRING) == None) {
+				SupportedAtoms[a].supported = false;
+				SupportedAtoms[a].atom = None;
+			}
+			else {
+				SupportedAtoms[a].req_type = A(UTF8_STRING);
+			}
+		}
+	}
+}
+
+static bool
+set_win_property(enum UsedAtom atom, Atom type, int format, int action, const void *value, int count)
+{
+	struct AtomDef *ad = &SupportedAtoms[atom];
+
+	if (ad->atom == None)
+		return false;
+	if (!(supported_standards & (1 << ad->standard)))
+		return false;
+	return (x11.XChangeProperty(dpy, win, ad->atom, type, format, action, (unsigned char *)value, count) != 0);
+}
+
 static bool
 fullscreen_geometry(int *x_org, int *y_org, int *width, int *height)
 {
@@ -358,8 +542,9 @@ x11_get_maxsize(int *w, int *h)
 	int afr;
 	long *ret;
 	unsigned long nir;
-	unsigned long bytes_left = 4;
+	unsigned long bytes_left;
 	unsigned char *prop;
+	long desktop = -1;
 
 	if (dpy == NULL)
 		return false;
@@ -369,31 +554,56 @@ x11_get_maxsize(int *w, int *h)
 	}
 	else {
 		// First, try to get _NET_WORKAREA...
-		if (x11.workarea == None) {
-			x11.workarea = x11.XInternAtom(dpy, "_NET_WORKAREA", True);
+		if (A(_NET_WM_DESKTOP) != None && win != 0) {
+			if (x11.XGetWindowProperty(dpy, win, A(_NET_WM_DESKTOP), 0, 1, False, XA_CARDINAL, &atr, &afr, &nir, &bytes_left, &prop) == Success) {
+				if (atr == XA_CARDINAL && afr == 32 && nir > 0) {
+					desktop = *(long *)prop;
+				}
+				x11.XFree(prop);
+			}
 		}
-		if (x11.workarea != None) {
-			for (i = 0, offset = 0; bytes_left; i++) {
-				if (x11.XGetWindowProperty(dpy, root, x11.workarea, offset, 4, False, XA_CARDINAL, &atr, &afr, &nir, &bytes_left, &prop) != Success)
+		if (A(_NET_WORKAREA) != None) {
+			for (i = 0, offset = 0, bytes_left = 1; bytes_left; i++, offset += nir) {
+				if (x11.XGetWindowProperty(dpy, root, A(_NET_WORKAREA), offset, 4, False, XA_CARDINAL, &atr, &afr, &nir, &bytes_left, &prop) != Success)
 					break;
 				if (atr != XA_CARDINAL) {
 					x11.XFree(prop);
 					break;
 				}
-				if (nir > 0)
-					offset += nir;
 				ret = (long *)prop;
-				if (nir >= 3) {
-					if (ret[2] > maxw)
-						maxw = ret[2];
+				if (desktop == -1) {
+					if (nir >= 3) {
+						if (ret[2] > maxw)
+							maxw = ret[2];
+					}
+					if (nir >= 4) {
+						if (ret[3] > maxh)
+							maxh = ret[3];
+					}
 				}
-				if (nir >= 4) {
-					if (ret[3] > maxh)
+				else if (desktop == i) {
+					if (nir >= 3)
+						maxw = ret[2];
+					if (nir >= 4)
 						maxh = ret[3];
+					x11.XFree(prop);
+					break;
 				}
 				x11.XFree(prop);
 			}
 		}
+		if (maxw > 0 && maxh > 0) {
+			if (A(_NET_FRAME_EXTENTS) != None && win != 0) {
+				if (x11.XGetWindowProperty(dpy, win, A(_NET_FRAME_EXTENTS), 0, 4, False, XA_CARDINAL, &atr, &afr, &nir, &bytes_left, &prop) == Success) {
+					if (atr == XA_CARDINAL && afr == 32 && nir == 4) {
+						ret = (long *)prop;
+						maxw -= ret[0] + ret[1];
+						maxh -= ret[2] + ret[3];
+					}
+					x11.XFree(prop);
+				}
+			}
+		}
 	}
 
 	// Couldn't get work area, get size of screen instead. :(
@@ -659,11 +869,14 @@ static int init_window()
 	int mw, mh;
 	int screen;
 	int major, minor;
+	unsigned long pid_l;
+	Atom a;
 
 	dpy = x11.XOpenDisplay(NULL);
 	if (dpy == NULL) {
 		return(-1);
 	}
+	root = DefaultRootWindow(dpy);
 	x11.XSynchronize(dpy, False);
 
 #ifdef WITH_XRENDER
@@ -680,9 +893,7 @@ static int init_window()
 #endif
 
 	xfd = ConnectionNumber(dpy);
-	x11.utf8 = x11.XInternAtom(dpy, "UTF8_STRING", False);
-	x11.targets = x11.XInternAtom(dpy, "TARGETS", False);
-	x11.workarea = x11.XInternAtom(dpy, "_NET_WORKAREA", True);
+	initialize_atoms();
 
 	screen = DefaultScreen(dpy);
 #ifdef DefaultVisual
@@ -709,9 +920,8 @@ static int init_window()
 	black=BlackPixel(dpy, DefaultScreen(dpy));
 	white=WhitePixel(dpy, DefaultScreen(dpy));
 
-    /* Create window, but defer setting a size and GC. */
+	/* Create window, but defer setting a size and GC. */
 	XSetWindowAttributes wa = {0};
-	root = DefaultRootWindow(dpy);
 	parent = root;
 	wincmap = x11.XCreateColormap(dpy, root, visual, AllocNone);
 	x11.XInstallColormap(dpy, wincmap);
@@ -743,12 +953,13 @@ static int init_window()
 		x11.XSetWMProperties(dpy, win, NULL, NULL, 0, 0, NULL, wmhints, classhints);
 		x11.XFree(wmhints);
 	}
+	set_win_property(A(_NET_WM_ICON), XA_CARDINAL, 32, PropModeReplace, ciolib_initial_icon, ciolib_initial_icon_width * ciolib_initial_icon_width);
 
-	Atom pid_atom = x11.XInternAtom(dpy, "_NET_WM_PID", False);
-	if (pid_atom != None) {
-		unsigned long pid_l = getpid();
-		x11.XChangeProperty(dpy, win, pid_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid_l, 1);
-	}
+	pid_l = getpid();
+	set_win_property(ATOM__NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, &pid_l, 1);
+	a = A(_NET_WM_WINDOW_TYPE_NORMAL);
+	if (a != None)
+		set_win_property(ATOM__NET_WM_WINDOW_TYPE, XA_ATOM, 32, PropModeReplace, &a, 1);
 
 	im = x11.XOpenIM(dpy, NULL, "CIOLIB", "CIOLIB");
 	if (im != NULL) {
@@ -760,13 +971,6 @@ static int init_window()
 	if (classhints)
 		x11.XFree(classhints);
 
-	WM_DELETE_WINDOW = x11.XInternAtom(dpy, "WM_DELETE_WINDOW", False);
-	_NET_WM_PING = x11.XInternAtom(dpy, "_NET_WM_PING", False);
-	_NET_WM_STATE = x11.XInternAtom(dpy, "_NET_WM_STATE", False);
-	_NET_WM_STATE_FULLSCREEN = x11.XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
-	_NET_WM_STATE_MAXIMIZED_VERT = x11.XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);
-	_NET_WM_STATE_MAXIMIZED_HORZ = x11.XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
-
 	gcv.function = GXcopy;
 	gcv.foreground = black | 0xff000000;
 	gcv.background = white;
@@ -780,10 +984,10 @@ static int init_window()
 	x11.XStoreName(dpy, win, "SyncConsole");
 	Atom protos[2];
 	int i = 0;
-	if (WM_DELETE_WINDOW != None)
-		protos[i++] = WM_DELETE_WINDOW;
-	if (_NET_WM_PING != None)
-		protos[i++] = _NET_WM_PING;
+	if (A(WM_DELETE_WINDOW) != None)
+		protos[i++] = A(WM_DELETE_WINDOW);
+	if (A(_NET_WM_PING) != None)
+		protos[i++] = A(_NET_WM_PING);
 	if (i)
 		x11.XSetWMProtocols(dpy, win, protos, i);
 
@@ -797,18 +1001,18 @@ send_fullscreen(bool set)
 	XEvent ev = {0};
 	bool ret = false;
 
-	if (_NET_WM_STATE != None && _NET_WM_STATE_FULLSCREEN != None) {
+	if (A(_NET_WM_STATE) != None && A(_NET_WM_STATE_FULLSCREEN) != None) {
 		if (last != set) {
 			ev.xclient.type = ClientMessage;
 			ev.xclient.serial = 0; // Populated by XSendEvent
 			ev.xclient.send_event = True; // Populated by XSendEvent
 			ev.xclient.display = dpy;
 			ev.xclient.window = win;
-			ev.xclient.message_type = _NET_WM_STATE;
+			ev.xclient.message_type = A(_NET_WM_STATE);
 			ev.xclient.format = 32;
 			memset(&ev.xclient.data.l, 0, sizeof(ev.xclient.data.l));
 			ev.xclient.data.l[0] = set ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
-			ev.xclient.data.l[1] = _NET_WM_STATE_FULLSCREEN;
+			ev.xclient.data.l[1] = A(_NET_WM_STATE_FULLSCREEN);
 			ev.xclient.data.l[3] = 1;
 			ret = x11.XSendEvent(dpy, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &ev) != 0;
 			if (ret) {
@@ -1257,16 +1461,16 @@ is_maximized(void)
 	unsigned char *prop;
 	size_t offset;
 
-	if (_NET_WM_STATE != None) {
+	if (A(_NET_WM_STATE) != None) {
 		for (offset = 0; bytes_left; offset += nir) {
-			if (x11.XGetWindowProperty(dpy, win, _NET_WM_STATE, offset, 1, False, XA_ATOM, &atr, &afr, &nir, &bytes_left, &prop) != Success)
+			if (x11.XGetWindowProperty(dpy, win, A(_NET_WM_STATE), offset, 1, False, XA_ATOM, &atr, &afr, &nir, &bytes_left, &prop) != Success)
 				break;
 			if (atr != XA_ATOM) {
 				x11.XFree(prop);
 				break;
 			}
 			ret = (Atom *)prop;
-			if (*ret == _NET_WM_STATE_MAXIMIZED_VERT || *ret == _NET_WM_STATE_MAXIMIZED_HORZ)
+			if (*ret == A(_NET_WM_STATE_MAXIMIZED_VERT) || *ret == A(_NET_WM_STATE_MAXIMIZED_HORZ))
 				is = true;
 			x11.XFree(prop);
 			if (is)
@@ -1285,15 +1489,22 @@ static int x11_event(XEvent *ev)
 			parent = ev->xreparent.parent;
 			break;
 		case ClientMessage:
-			if (ev->xclient.format == 32 && ev->xclient.data.l[0] == WM_DELETE_WINDOW && WM_DELETE_WINDOW != None) {
+			if (ev->xclient.format == 32 && ev->xclient.data.l[0] == A(WM_DELETE_WINDOW) && A(WM_DELETE_WINDOW) != None) {
 				uint16_t key=CIO_KEY_QUIT;
 				write(key_pipe[1], &key, 2);
 			}
-			else if(ev->xclient.format == 32 && ev->xclient.data.l[0] == _NET_WM_PING && _NET_WM_PING != None) {
+			else if(ev->xclient.format == 32 && ev->xclient.data.l[0] == A(_NET_WM_PING) && A(_NET_WM_PING) != None) {
 				ev->xclient.window = root;
 				x11.XSendEvent(dpy, ev->xclient.window, False, SubstructureNotifyMask | SubstructureRedirectMask, ev);
 			}
 			break;
+		case PropertyNotify:
+			if (A(_NET_FRAME_EXTENTS) != None) {
+				if (ev->xproperty.atom != A(_NET_FRAME_EXTENTS))
+					break;
+				map_window();
+			}
+			break;
 		/* Graphics related events */
 		case ConfigureNotify: {
 			bool resize = false;
@@ -1360,7 +1571,7 @@ static int x11_event(XEvent *ev)
 					x11.XGetWindowProperty(dpy, win, ev->xselection.property, 0, 0, True, AnyPropertyType, &pastebuf_format, &format, &len, &bytes_left, (unsigned char **)(&pastebuf));
 					if(bytes_left > 0 && format==8) {
 						x11.XGetWindowProperty(dpy, win, ev->xselection.property, 0, bytes_left, True, AnyPropertyType, &pastebuf_format, &format, &len, &dummy, (unsigned char **)&pastebuf);
-						if (x11.utf8 && pastebuf_format == x11.utf8) {
+						if (A(UTF8_STRING) && pastebuf_format == A(UTF8_STRING)) {
 							char *opb = pastebuf;
 							pastebuf = (char *)utf8_to_cp(CIOLIB_ISO_8859_1, (uint8_t *)pastebuf, '?', strlen(pastebuf), NULL);
 							if (pastebuf == NULL)
@@ -1378,7 +1589,7 @@ static int x11_event(XEvent *ev)
 				/* Set paste buffer */
 				sem_post(&pastebuf_set);
 				sem_wait(&pastebuf_used);
-				if (x11.utf8 && pastebuf_format == x11.utf8)
+				if (A(UTF8_STRING) && pastebuf_format == A(UTF8_STRING))
 					free(pastebuf);
 				else
 					x11.XFree(pastebuf);
@@ -1394,8 +1605,6 @@ static int x11_event(XEvent *ev)
 
 				req=&(ev->xselectionrequest);
 				pthread_mutex_lock(&copybuf_mutex);
-				if (x11.targets == 0)
-					x11.targets = x11.XInternAtom(dpy, "TARGETS", False);
 				respond.xselection.property=None;
 				if(copybuf!=NULL) {
 					if(req->target==XA_STRING) {
@@ -1406,18 +1615,15 @@ static int x11_event(XEvent *ev)
 							free(cpstr);
 						}
 					}
-					else if(req->target == x11.utf8) {
-						x11.XChangeProperty(dpy, req->requestor, req->property, x11.utf8, 8, PropModeReplace, (uint8_t *)copybuf, strlen((char *)copybuf));
+					else if(req->target == A(UTF8_STRING)) {
+						x11.XChangeProperty(dpy, req->requestor, req->property, A(UTF8_STRING), 8, PropModeReplace, (uint8_t *)copybuf, strlen((char *)copybuf));
 						respond.xselection.property=req->property;
 					}
-					else if(req->target == x11.targets) {
-						if (x11.utf8 == 0)
-							x11.utf8 = x11.XInternAtom(dpy, "UTF8_STRING", False);
-
-						supported[count++] = x11.targets;
+					else if(req->target == A(TARGETS)) {
+						supported[count++] = A(TARGETS);
 						supported[count++] = XA_STRING;
-						if (x11.utf8)
-							supported[count++] = x11.utf8;
+						if (A(UTF8_STRING))
+							supported[count++] = A(UTF8_STRING);
 						x11.XChangeProperty(dpy, req->requestor, req->property, XA_ATOM, 32, PropModeReplace, (unsigned char *)supported, count);
 						respond.xselection.property=req->property;
 					}
@@ -1867,10 +2073,12 @@ void x11_event_thread(void *args)
 							break;
 						case X11_LOCAL_SETNAME:
 							x11.XSetIconName(dpy, win, lev.data.name);
+							set_win_property(A(_NET_WM_ICON_NAME), A(UTF8_STRING), 8, PropModeReplace, lev.data.name, strlen(lev.data.name));
 							x11.XFlush(dpy);
 							break;
 						case X11_LOCAL_SETTITLE:
 							x11.XStoreName(dpy, win, lev.data.title);
+							set_win_property(A(_NET_WM_NAME), A(UTF8_STRING), 8, PropModeReplace, lev.data.name, strlen(lev.data.name));
 							x11.XFlush(dpy);
 							break;
 						case X11_LOCAL_COPY:
@@ -1895,7 +2103,7 @@ void x11_event_thread(void *args)
 									FREE_AND_NULL(pastebuf);
 								}
 								else if(sowner!=None) {
-									x11.XConvertSelection(dpy, CONSOLE_CLIPBOARD, x11.utf8 ? x11.utf8 : XA_STRING, x11.utf8 ? x11.utf8 : XA_STRING, win, CurrentTime);
+									x11.XConvertSelection(dpy, CONSOLE_CLIPBOARD, A(UTF8_STRING) ? A(UTF8_STRING) : XA_STRING, A(UTF8_STRING) ? A(UTF8_STRING) : XA_STRING, win, CurrentTime);
 								}
 								else {
 									/* Set paste buffer */
@@ -1915,12 +2123,10 @@ void x11_event_thread(void *args)
 							x11.XBell(dpy, 100);
 							break;
 						case X11_LOCAL_SETICON: {
-							Atom wmicon = x11.XInternAtom(dpy, "_NET_WM_ICON", False);
-							if (wmicon) {
-								x11.XChangeProperty(dpy, win, wmicon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)lev.data.icon_data, lev.data.icon_data[0] * lev.data.icon_data[1] + 2);
-								x11.XFlush(dpy);
-							}
+							// TODO: set_icon() is obsolete... delete
 							set_icon(&lev.data.icon_data[2], lev.data.icon_data[0], NULL);
+							set_win_property(A(_NET_WM_ICON), XA_CARDINAL, 32, PropModeReplace, lev.data.icon_data, lev.data.icon_data[0] * lev.data.icon_data[1] + 2);
+							x11.XFlush(dpy);
 							free(lev.data.icon_data);
 							break;
 						}
diff --git a/src/conio/x_events.h b/src/conio/x_events.h
index 2f3d7f9bd0..2e6aaaead0 100644
--- a/src/conio/x_events.h
+++ b/src/conio/x_events.h
@@ -143,9 +143,6 @@ struct x11 {
 	void (*XRRFreeCrtcInfo)(XRRCrtcInfo *crtcInfo);
 	void (*XRRFreeScreenResources)(XRRScreenResources *resources);
 #endif
-	Atom utf8;
-	Atom targets;
-	Atom workarea;
 };
 
 extern int local_pipe[2];			/* Used for passing local events */
@@ -159,11 +156,8 @@ extern char 	*pastebuf;
 extern sem_t	pastebuf_set;
 extern sem_t	pastebuf_used;
 extern Atom	copybuf_format;
-extern Atom	pastebuf_format;
 extern sem_t	init_complete;
 extern sem_t	mode_set;
-extern sem_t	event_thread_complete;
-extern int terminate;
 extern int x11_window_xpos;
 extern int x11_window_ypos;
 extern int x11_initialized;
diff --git a/src/syncterm/syncterm.c b/src/syncterm/syncterm.c
index f3d3b9fbd4..259f765801 100644
--- a/src/syncterm/syncterm.c
+++ b/src/syncterm/syncterm.c
@@ -1723,6 +1723,7 @@ main(int argc, char **argv)
 #endif
 	if (initciolib(ciolib_mode))
 		return 1;
+	setname("SyncTERM");
 	if (settings.blocky)
 		cio_api.options |= CONIO_OPT_BLOCKY_SCALING;
 	else
-- 
GitLab