Browse Source

Use XCB and SelectSelectionInput instead of GTK+

As it happens, there is no real need to constantly poll for changes,
since XFixes can inform us of updates as they happen.

With GTK+ gone we've got dependencies and error handling under control.
XCB is a truly awful thing to learn, though.

Our method will never work on Wayland or Windows, so we don't miss out
on anything by abandoning the huge toolkit.
Přemysl Janouch 2 months ago
parent
commit
942bda7db4
Signed by: Přemysl Janouch <p@janouch.name> GPG Key ID: A0420B94F92B9493
5 changed files with 257 additions and 120 deletions
  1. 12
    13
      CMakeLists.txt
  2. 1
    1
      LICENSE
  3. 4
    4
      README.adoc
  4. 1
    1
      config.h.in
  5. 239
    101
      src/sdtui.c

+ 12
- 13
CMakeLists.txt View File

@@ -74,19 +74,18 @@ else (USE_SYSTEM_TERMO)
74 74
 	set (Termo_LIBRARIES termo-static)
75 75
 endif (USE_SYSTEM_TERMO)
76 76
 
77
-# We actually don't care about the specific version
78
-pkg_search_module (gtk gtk+-3.0 gtk+-2.0)
79
-option (WITH_GTK "Compile with GTK+ support" ${gtk_FOUND})
80
-
81
-if (WITH_GTK)
82
-	if (NOT gtk_FOUND)
83
-		message (FATAL_ERROR "GTK+ library not found")
84
-	endif (NOT gtk_FOUND)
85
-
86
-	list (APPEND dependencies_INCLUDE_DIRS ${gtk_INCLUDE_DIRS})
87
-	list (APPEND dependencies_LIBRARY_DIRS ${gtk_LIBRARY_DIRS})
88
-	list (APPEND dependencies_LIBRARIES ${gtk_LIBRARIES})
89
-endif (WITH_GTK)
77
+pkg_check_modules (xcb xcb xcb-xfixes)
78
+option (WITH_X11 "Compile with X11 selection support using XCB" ${xcb_FOUND})
79
+
80
+if (WITH_X11)
81
+	if (NOT xcb_FOUND)
82
+		message (FATAL_ERROR "XCB not found")
83
+	endif (NOT xcb_FOUND)
84
+
85
+	list (APPEND dependencies_INCLUDE_DIRS ${xcb_INCLUDE_DIRS})
86
+	list (APPEND dependencies_LIBRARY_DIRS ${xcb_LIBRARY_DIRS})
87
+	list (APPEND dependencies_LIBRARIES ${xcb_LIBRARIES})
88
+endif (WITH_X11)
90 89
 
91 90
 link_directories (${dependencies_LIBRARY_DIRS})
92 91
 include_directories (${ZLIB_INCLUDE_DIRS} ${icu_INCLUDE_DIRS}

+ 1
- 1
LICENSE View File

@@ -1,4 +1,4 @@
1
-Copyright (c) 2013 - 2016, Přemysl Janouch <p@janouch.name>
1
+Copyright (c) 2013 - 2018, Přemysl Janouch <p@janouch.name>
2 2
 
3 3
 Permission to use, copy, modify, and/or distribute this software for any
4 4
 purpose with or without fee is hereby granted.

+ 4
- 4
README.adoc View File

@@ -7,7 +7,7 @@ dictionary software of this kind, GUI or not, and thus decided to write my own.
7 7
 
8 8
 The project is covered by a permissive license, unlike vast majority of other
9 9
 similar projects, and can serve as a base for implementing other dictionary
10
-software.  I wasn't able to reuse _anything_.
10
+software.  I wasn't able to reuse _anything_ for StarDict.
11 11
 
12 12
 Further Development
13 13
 -------------------
@@ -32,12 +32,12 @@ Building and Running
32 32
 --------------------
33 33
 Build dependencies: CMake, pkg-config, xsltproc, docbook-xsl +
34 34
 Runtime dependencies: ncursesw, zlib, ICU, termo (included),
35
-                      glib-2.0, pango, gtk+ (optional, any version)
35
+                      glib-2.0, pango, xcb and xcb-xfixes (optional)
36 36
 
37 37
  $ git clone --recursive https://git.janouch.name/p/sdtui.git
38 38
  $ mkdir sdtui/build
39 39
  $ cd sdtui/build
40
- $ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DWITH_GTK=ON
40
+ $ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug -DWITH_X11=ON
41 41
  $ make
42 42
 
43 43
 To install the application, you can do either the usual:
@@ -85,7 +85,7 @@ odd = 16 255
85 85
 
86 86
 The `watch-selection` option makes the application watch the X11 primary
87 87
 selection for changes and automatically search for selected text.
88
-This feature requires GTK+ and it will never work on Wayland by its design.
88
+This feature requires XCB and it will never work on Wayland by its design.
89 89
 
90 90
 You can also set up some dictionaries to be loaded at startup automatically:
91 91
 

+ 1
- 1
config.h.in View File

@@ -8,7 +8,7 @@
8 8
 #define GETTEXT_PACKAGE PROJECT_NAME
9 9
 #define GETTEXT_DIRNAME "${CMAKE_INSTALL_PREFIX}/share/locale"
10 10
 
11
-#cmakedefine WITH_GTK
11
+#cmakedefine WITH_X11
12 12
 #cmakedefine HAVE_RESIZETERM
13 13
 
14 14
 #endif  // ! CONFIG_H

+ 239
- 101
src/sdtui.c View File

@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * StarDict terminal UI
3 3
  *
4
- * Copyright (c) 2013 - 2016, Přemysl Janouch <p@janouch.name>
4
+ * Copyright (c) 2013 - 2018, Přemysl Janouch <p@janouch.name>
5 5
  *
6 6
  * Permission to use, copy, modify, and/or distribute this software for any
7 7
  * purpose with or without fee is hereby granted.
@@ -43,10 +43,6 @@
43 43
 #include "stardict.h"
44 44
 #include "utils.h"
45 45
 
46
-#ifdef WITH_GTK
47
-#include <gtk/gtk.h>
48
-#endif  // WITH_GTK
49
-
50 46
 #define CTRL_KEY(x)  ((x) - 'A' + 1)
51 47
 
52 48
 #define TOP_BAR_CUTOFF  2               ///< How many lines are reserved on top
@@ -213,6 +209,7 @@ struct application
213 209
 	guint           center_search : 1;  ///< Whether to center the search
214 210
 	guint           underline_last : 1; ///< Underline the last definition
215 211
 	guint           hl_prefix : 1;      ///< Highlight the common prefix
212
+	guint           watch_x11_sel : 1;  ///< Requested X11 selection watcher
216 213
 
217 214
 	guint32         top_position;       ///< Index of the topmost dict. entry
218 215
 	guint           top_offset;         ///< Offset into the top entry
@@ -226,10 +223,6 @@ struct application
226 223
 
227 224
 	gfloat          division;           ///< Position of the division column
228 225
 
229
-	guint           selection_timer;    ///< Selection watcher timeout timer
230
-	gint            selection_interval; ///< Selection watcher timer interval
231
-	gchar         * selection_contents; ///< Selection contents
232
-
233 226
 	struct attrs    attrs[ATTRIBUTE_COUNT];
234 227
 };
235 228
 
@@ -398,18 +391,6 @@ app_reload_view (Application *self)
398 391
 	g_object_unref (iterator);
399 392
 }
400 393
 
401
-#ifdef WITH_GTK
402
-static gboolean on_selection_timer (gpointer data);
403
-
404
-static void
405
-rearm_selection_watcher (Application *self)
406
-{
407
-	if (self->selection_interval > 0)
408
-		self->selection_timer = g_timeout_add
409
-			(self->selection_interval, on_selection_timer, self);
410
-}
411
-#endif  // WITH_GTK
412
-
413 394
 /// Load configuration for a color using a subset of git config colors.
414 395
 static void
415 396
 app_load_color (Application *self, GKeyFile *kf, const gchar *name, int id)
@@ -468,14 +449,8 @@ app_load_config_values (Application *self, GKeyFile *kf)
468 449
 		app_load_bool (kf, "underline-last", self->underline_last);
469 450
 	self->hl_prefix =
470 451
 		app_load_bool (kf, "hl-common-prefix", self->hl_prefix);
471
-
472
-	guint64 timer;
473
-	const gchar *watch_selection = "watch-selection";
474
-	if (app_load_bool (kf, watch_selection, FALSE))
475
-		self->selection_interval = 500;
476
-	else if ((timer = g_key_file_get_uint64
477
-		(kf, "Settings", watch_selection, NULL)) && timer <= G_MAXINT)
478
-		self->selection_interval = timer;
452
+	self->watch_x11_sel =
453
+		app_load_bool (kf, "watch-selection", self->watch_x11_sel);
479 454
 
480 455
 #define XX(name, config, fg_, bg_, attrs_) \
481 456
 	app_load_color (self, kf, config, ATTRIBUTE_ ## name);
@@ -613,9 +588,6 @@ static void
613 588
 app_init (Application *self, char **filenames)
614 589
 {
615 590
 	self->loop = NULL;
616
-	self->selection_interval = -1;
617
-	self->selection_timer = 0;
618
-	self->selection_contents = NULL;
619 591
 
620 592
 	self->tk = NULL;
621 593
 	self->tk_timer = 0;
@@ -624,6 +596,7 @@ app_init (Application *self, char **filenames)
624 596
 	self->center_search = TRUE;
625 597
 	self->underline_last = TRUE;
626 598
 	self->hl_prefix = TRUE;
599
+	self->watch_x11_sel = FALSE;
627 600
 
628 601
 	self->top_position = 0;
629 602
 	self->top_offset = 0;
@@ -660,18 +633,7 @@ app_init (Application *self, char **filenames)
660 633
 		exit (EXIT_FAILURE);
661 634
 	}
662 635
 
663
-	// Now we have settings for the clipboard watcher, we can arm the timer
664
-#ifdef WITH_GTK
665
-	if (gtk_init_check (0, NULL))
666
-	{
667
-		// So that we set the input only when it actually changes
668
-		GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
669
-		self->selection_contents = gtk_clipboard_wait_for_text (clipboard);
670
-		rearm_selection_watcher (self);
671
-	}
672
-	else
673
-#endif  // WITH_GTK
674
-		self->loop = g_main_loop_new (NULL, FALSE);
636
+	self->loop = g_main_loop_new (NULL, FALSE);
675 637
 
676 638
 	// Dictionaries given on the command line override the configuration
677 639
 	if (*filenames)
@@ -744,10 +706,6 @@ app_destroy (Application *self)
744 706
 	if (self->tk_timer)
745 707
 		g_source_remove (self->tk_timer);
746 708
 
747
-	if (self->selection_timer)
748
-		g_source_remove (self->selection_timer);
749
-	g_free (self->selection_contents);
750
-
751 709
 	g_ptr_array_free (self->entries, TRUE);
752 710
 	g_free (self->search_label);
753 711
 	g_array_free (self->input, TRUE);
@@ -760,24 +718,14 @@ app_destroy (Application *self)
760 718
 static void
761 719
 app_run (Application *self)
762 720
 {
763
-	if (self->loop)
764
-		g_main_loop_run (self->loop);
765
-#ifdef WITH_GTK
766
-	else
767
-		gtk_main ();
768
-#endif  // WITH_GTK
721
+	g_main_loop_run (self->loop);
769 722
 }
770 723
 
771 724
 /// Quit the main event dispatch loop.
772 725
 static void
773 726
 app_quit (Application *self)
774 727
 {
775
-	if (self->loop)
776
-		g_main_loop_quit (self->loop);
777
-#ifdef WITH_GTK
778
-	else
779
-		gtk_main_quit ();
780
-#endif  // WITH_GTK
728
+	g_main_loop_quit (self->loop);
781 729
 }
782 730
 
783 731
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1023,7 +971,7 @@ app_show_help (Application *self)
1023 971
 	{
1024 972
 		PROJECT_NAME " " PROJECT_VERSION,
1025 973
 		_("Terminal UI for StarDict dictionaries"),
1026
-		"Copyright (c) 2013 - 2016, Přemysl Janouch",
974
+		"Copyright (c) 2013 - 2018, Přemysl Janouch",
1027 975
 		"",
1028 976
 		_("Type to search")
1029 977
 	};
@@ -1835,6 +1783,215 @@ install_winch_handler (void)
1835 1783
 	sigaction (SIGWINCH, &act, &oldact);
1836 1784
 }
1837 1785
 
1786
+// --- X11 selection watcher ---------------------------------------------------
1787
+
1788
+#ifdef WITH_X11
1789
+
1790
+#include <xcb/xcb.h>
1791
+#include <xcb/xfixes.h>
1792
+
1793
+/// Data relating to one entry within the dictionary.
1794
+typedef struct selection_watch          SelectionWatch;
1795
+
1796
+struct selection_watch
1797
+{
1798
+	Application *app;
1799
+	xcb_connection_t *X;
1800
+	const xcb_query_extension_reply_t *xfixes;
1801
+
1802
+	guint           watch;              ///< X11 connection watcher
1803
+	xcb_window_t    wid;                ///< Withdrawn communications window
1804
+	xcb_atom_t      atom_utf8_string;   ///< UTF8_STRING
1805
+	xcb_timestamp_t in_progress;        ///< Timestamp of last processed event
1806
+};
1807
+
1808
+static gboolean
1809
+is_xcb_ok (xcb_connection_t *X)
1810
+{
1811
+	int xcb_error = xcb_connection_has_error (X);
1812
+	if (xcb_error)
1813
+	{
1814
+		g_warning (_("X11 connection failed (error code %d)"), xcb_error);
1815
+		return FALSE;
1816
+	}
1817
+	return TRUE;
1818
+}
1819
+
1820
+static xcb_atom_t
1821
+resolve_atom (xcb_connection_t *X, const char *atom)
1822
+{
1823
+	xcb_intern_atom_reply_t *iar = xcb_intern_atom_reply (X,
1824
+		xcb_intern_atom (X, false, strlen (atom), atom), NULL);
1825
+	xcb_atom_t result = iar ? iar->atom : XCB_NONE;
1826
+	free (iar);
1827
+	return result;
1828
+}
1829
+
1830
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1831
+
1832
+static void
1833
+app_set_input (Application *self, const gchar *text, gsize text_len);
1834
+
1835
+static void
1836
+on_selection_text_received (SelectionWatch *self, const gchar *text);
1837
+
1838
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1839
+
1840
+static gboolean
1841
+read_utf8_property (SelectionWatch *self, xcb_window_t wid, xcb_atom_t property,
1842
+	GString *buf)
1843
+{
1844
+	guint32 offset = 0;
1845
+	gboolean loop = TRUE, ok = TRUE;
1846
+	while (ok && loop)
1847
+	{
1848
+		xcb_get_property_reply_t *gpr = xcb_get_property_reply (self->X,
1849
+			xcb_get_property (self->X, FALSE /* delete */, wid,
1850
+			property, XCB_GET_PROPERTY_TYPE_ANY, offset, 0x7fff), NULL);
1851
+
1852
+		if (!gpr || gpr->type != self->atom_utf8_string || gpr->format != 8)
1853
+			ok = FALSE;
1854
+		else
1855
+		{
1856
+			int len = xcb_get_property_value_length (gpr);
1857
+			g_string_append_len (buf, xcb_get_property_value (gpr), len);
1858
+			offset += len >> 2;
1859
+			loop = gpr->bytes_after > 0;
1860
+		}
1861
+
1862
+		free (gpr);
1863
+	}
1864
+	return ok;
1865
+}
1866
+
1867
+static void
1868
+process_x11_event (SelectionWatch *self, xcb_generic_event_t *event)
1869
+{
1870
+	xcb_generic_error_t *err = NULL;
1871
+	int event_code = event->response_type & 0x7f;
1872
+	if (event_code == 0)
1873
+	{
1874
+		err = (xcb_generic_error_t *) event;
1875
+		g_warning (_("X11 request error (%d, major %d, minor %d)"),
1876
+			err->error_code, err->major_code, err->minor_code);
1877
+	}
1878
+	else if (event_code ==
1879
+		self->xfixes->first_event + XCB_XFIXES_SELECTION_NOTIFY)
1880
+	{
1881
+		xcb_xfixes_selection_notify_event_t *e =
1882
+			(xcb_xfixes_selection_notify_event_t *) event;
1883
+
1884
+		// Not checking whether we should give up when this interrupts our
1885
+		// current retrieval attempt--the timeout solves this
1886
+		if (e->owner == XCB_NONE)
1887
+			return;
1888
+
1889
+		// Don't try to process two things at once.  Each request gets a few
1890
+		// seconds to finish, then we move on, hoping that a property race
1891
+		// doesn't commence.  Ideally we'd set up a separate queue for these
1892
+		// skipped requests and process them later.
1893
+		if (self->in_progress != 0 && e->timestamp - self->in_progress < 5000)
1894
+			return;
1895
+
1896
+		// ICCCM says we should ensure the named property doesn't exist
1897
+		(void) xcb_delete_property (self->X, self->wid, XCB_ATOM_PRIMARY);
1898
+
1899
+		(void) xcb_convert_selection (self->X, self->wid, e->selection,
1900
+			self->atom_utf8_string, XCB_ATOM_PRIMARY, e->timestamp);
1901
+		self->in_progress = e->timestamp;
1902
+	}
1903
+	else if (event_code == XCB_SELECTION_NOTIFY)
1904
+	{
1905
+		xcb_selection_notify_event_t *e =
1906
+			(xcb_selection_notify_event_t *) event;
1907
+		if (e->time != self->in_progress)
1908
+			return;
1909
+
1910
+		self->in_progress = 0;
1911
+		if (e->property == XCB_ATOM_NONE)
1912
+			return;
1913
+
1914
+		GString *buf = g_string_new (NULL);
1915
+		if (read_utf8_property (self, e->requestor, e->property, buf))
1916
+			on_selection_text_received (self, buf->str);
1917
+		g_string_free (buf, TRUE);
1918
+
1919
+		(void) xcb_delete_property (self->X, self->wid, e->property);
1920
+	}
1921
+}
1922
+
1923
+static gboolean
1924
+process_x11 (G_GNUC_UNUSED GIOChannel *source,
1925
+	G_GNUC_UNUSED GIOCondition condition, gpointer data)
1926
+{
1927
+	SelectionWatch *self = data;
1928
+
1929
+	xcb_generic_event_t *event;
1930
+	while ((event = xcb_poll_for_event (self->X)))
1931
+	{
1932
+		process_x11_event (self, event);
1933
+		free (event);
1934
+	}
1935
+	(void) xcb_flush (self->X);
1936
+	return is_xcb_ok (self->X);
1937
+}
1938
+
1939
+static void
1940
+selection_watch_init (SelectionWatch *self, Application *app)
1941
+{
1942
+	memset (self, 0, sizeof *self);
1943
+	if (!app->watch_x11_sel)
1944
+		return;
1945
+	self->app = app;
1946
+
1947
+	int which_screen = -1;
1948
+	self->X = xcb_connect (NULL, &which_screen);
1949
+	if (!is_xcb_ok (self->X))
1950
+		return;
1951
+
1952
+	// Most modern applications support this, though an XCB_ATOM_STRING
1953
+	// fallback might be good to add (COMPOUND_TEXT is complex)
1954
+	g_return_if_fail
1955
+		((self->atom_utf8_string = resolve_atom (self->X, "UTF8_STRING")));
1956
+
1957
+	self->xfixes = xcb_get_extension_data (self->X, &xcb_xfixes_id);
1958
+	g_return_if_fail (self->xfixes->present);
1959
+
1960
+	(void) xcb_xfixes_query_version_unchecked (self->X,
1961
+		XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION);
1962
+
1963
+	const xcb_setup_t *setup = xcb_get_setup (self->X);
1964
+	xcb_screen_iterator_t setup_iter = xcb_setup_roots_iterator (setup);
1965
+	while (which_screen--)
1966
+		xcb_screen_next (&setup_iter);
1967
+
1968
+	xcb_screen_t *screen = setup_iter.data;
1969
+	self->wid = xcb_generate_id (self->X);
1970
+	(void) xcb_create_window (self->X, screen->root_depth, self->wid,
1971
+		screen->root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
1972
+		screen->root_visual, 0, NULL);
1973
+
1974
+	(void) xcb_xfixes_select_selection_input (self->X, self->wid,
1975
+		XCB_ATOM_PRIMARY, XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
1976
+		XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
1977
+		XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE);
1978
+
1979
+	(void) xcb_flush (self->X);
1980
+	self->watch = g_io_add_watch (g_io_channel_unix_new
1981
+		(xcb_get_file_descriptor (self->X)), G_IO_IN, process_x11, self);
1982
+}
1983
+
1984
+static void
1985
+selection_watch_destroy (SelectionWatch *self)
1986
+{
1987
+	if (self->X)
1988
+		xcb_disconnect (self->X);
1989
+	if (self->watch)
1990
+		g_source_remove (self->watch);
1991
+}
1992
+
1993
+#endif  // WITH_X11
1994
+
1838 1995
 // --- Initialisation, event handling ------------------------------------------
1839 1996
 
1840 1997
 static gboolean on_stdin_input_timeout (gpointer data);
@@ -1903,7 +2060,7 @@ on_terminated (gpointer user_data)
1903 2060
 	return TRUE;
1904 2061
 }
1905 2062
 
1906
-#ifdef WITH_GTK
2063
+#ifdef WITH_X11
1907 2064
 static void
1908 2065
 app_set_input (Application *self, const gchar *text, gsize text_len)
1909 2066
 {
@@ -1935,47 +2092,19 @@ app_set_input (Application *self, const gchar *text, gsize text_len)
1935 2092
 }
1936 2093
 
1937 2094
 static void
1938
-on_selection_text_received (G_GNUC_UNUSED GtkClipboard *clipboard,
1939
-	const gchar *text, gpointer data)
1940
-{
1941
-	Application *app = data;
1942
-	rearm_selection_watcher (app);
1943
-
1944
-	if (text)
1945
-	{
1946
-		// Strip ASCII whitespace: this is compatible with UTF-8
1947
-		while (g_ascii_isspace (*text))
1948
-			text++;
1949
-		gsize text_len = strlen (text);
1950
-		while (text_len && g_ascii_isspace (text[text_len - 1]))
1951
-			text_len--;
1952
-
1953
-		if (app->selection_contents &&
1954
-			!strncmp (app->selection_contents, text, text_len))
1955
-			return;
1956
-
1957
-		g_free (app->selection_contents);
1958
-		app->selection_contents = g_strndup (text, text_len);
1959
-		app_set_input (app, text, text_len);
1960
-	}
1961
-	else if (app->selection_contents)
1962
-	{
1963
-		g_free (app->selection_contents);
1964
-		app->selection_contents = NULL;
1965
-	}
1966
-}
1967
-
1968
-static gboolean
1969
-on_selection_timer (gpointer data)
2095
+on_selection_text_received (SelectionWatch *self, const gchar *text)
1970 2096
 {
1971
-	Application *app = data;
1972
-	GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
1973
-	gtk_clipboard_request_text (clipboard, on_selection_text_received, app);
2097
+	// Strip ASCII whitespace: this is compatible with UTF-8
2098
+	while (g_ascii_isspace (*text))
2099
+		text++;
2100
+	gsize text_len = strlen (text);
2101
+	while (text_len && g_ascii_isspace (text[text_len - 1]))
2102
+		text_len--;
1974 2103
 
1975
-	app->selection_timer = 0;
1976
-	return FALSE;
2104
+	if (text_len)
2105
+		app_set_input (self->app, text, text_len);
1977 2106
 }
1978
-#endif  // WITH_GTK
2107
+#endif  // WITH_X11
1979 2108
 
1980 2109
 static void
1981 2110
 log_handler_curses (Application *self, const gchar *message)
@@ -2091,7 +2220,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
2091 2220
 	// g_unix_signal_add() cannot handle SIGWINCH
2092 2221
 	install_winch_handler ();
2093 2222
 
2094
-	// GtkClipboard can internally issue some rather disruptive warnings
2223
+	// Avoid disruptive warnings
2095 2224
 	g_log_set_default_handler (log_handler, &app);
2096 2225
 
2097 2226
 	// Message loop
@@ -2102,8 +2231,17 @@ G_GNUC_END_IGNORE_DEPRECATIONS
2102 2231
 	guint watch_winch = g_io_add_watch (g_io_channel_unix_new (g_winch_pipe[0]),
2103 2232
 		G_IO_IN, process_winch_input, &app);
2104 2233
 
2234
+#ifdef WITH_X11
2235
+	SelectionWatch sw;
2236
+	selection_watch_init (&sw, &app);
2237
+#endif  // WITH_X11
2238
+
2105 2239
 	app_run (&app);
2106 2240
 
2241
+#ifdef WITH_X11
2242
+	selection_watch_destroy (&sw);
2243
+#endif  // WITH_X11
2244
+
2107 2245
 	g_source_remove (watch_term);
2108 2246
 	g_source_remove (watch_int);
2109 2247
 	g_source_remove (watch_stdin);

Loading…
Cancel
Save