From 48941cb9c46c2fdea1064bcaf4524a9071eb4c85 Mon Sep 17 00:00:00 2001
From: Tudor Brindus <me@tbrindus.ca>
Date: Sat, 9 Jan 2021 14:03:52 -0500
Subject: [PATCH] [client] clipboard/wayland: implement better text mimetype
 heuristic

This roughly matches the heuristic that wl-copy uses to detect text.
---
 client/clipboards/Wayland/src/wayland.c | 39 +++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/client/clipboards/Wayland/src/wayland.c b/client/clipboards/Wayland/src/wayland.c
index a9d42aba..52a713af 100644
--- a/client/clipboards/Wayland/src/wayland.c
+++ b/client/clipboards/Wayland/src/wayland.c
@@ -125,9 +125,40 @@ static bool contains_mimetype(const char ** mimetypes,
   return false;
 }
 
-static enum LG_ClipboardData mimetype_to_cb_type(const char * mimetype)
+static bool mimetype_endswith(const char * mimetype, const char * what)
+{
+  size_t mimetype_len = strlen(mimetype);
+  size_t what_len = strlen(what);
+
+  if (mimetype_len < what_len)
+    return false;
+
+  return !strcmp(mimetype + mimetype_len - what_len, what);
+}
+
+static bool is_text_mimetype(const char * mimetype)
 {
   if (contains_mimetype(text_mimetypes, mimetype))
+    return true;
+
+  char * text = "text/";
+  if (!strncmp(mimetype, text, strlen(text)))
+    return true;
+
+  if (mimetype_endswith(mimetype, "script") ||
+      mimetype_endswith(mimetype, "xml") ||
+      mimetype_endswith(mimetype, "yaml"))
+    return true;
+
+  if (strstr(mimetype, "json"))
+    return true;
+
+  return false;
+}
+
+static enum LG_ClipboardData mimetype_to_cb_type(const char * mimetype)
+{
+  if (is_text_mimetype(mimetype))
     return LG_CLIPBOARD_DATA_TEXT;
 
   if (contains_mimetype(png_mimetypes, mimetype))
@@ -256,7 +287,11 @@ static void wl_data_handle_offer(void * data, struct wl_data_offer * offer,
     const char * mimetype)
 {
   enum LG_ClipboardData type = mimetype_to_cb_type(mimetype);
-  if (type != LG_CLIPBOARD_DATA_NONE)
+  // Oftentimes we'll get text/html alongside text/png, but would prefer to send
+  // image/png. In general, prefer images over text content.
+  if (type != LG_CLIPBOARD_DATA_NONE &&
+      (this->stashed_type == LG_CLIPBOARD_DATA_NONE ||
+       this->stashed_type == LG_CLIPBOARD_DATA_TEXT))
   {
     this->stashed_type = type;
     if (this->stashed_mimetype)