2 * gtkcomm.c: machinery in the GTK front end which is common to all
3 * programs that run a session in a terminal window, and also common
4 * across all _sessions_ rather than specific to one session. (Timers,
21 #include <sys/types.h>
24 #if !GTK_CHECK_VERSION(3,0,0)
25 #include <gdk/gdkkeysyms.h>
28 #if GTK_CHECK_VERSION(2,0,0)
29 #include <gtk/gtkimmodule.h>
32 #define MAY_REFER_TO_GTK_IN_HEADERS
36 #include "gtkcompat.h"
43 #include <X11/Xutil.h>
44 #include <X11/Xatom.h>
47 #define CAT2(x,y) x ## y
48 #define CAT(x,y) CAT2(x,y)
49 #define ASSERT(x) enum {CAT(assertion_,__LINE__) = 1 / (x)}
51 #if GTK_CHECK_VERSION(2,0,0)
52 ASSERT(sizeof(long) <= sizeof(gsize));
53 #define LONG_TO_GPOINTER(l) GSIZE_TO_POINTER(l)
54 #define GPOINTER_TO_LONG(p) GPOINTER_TO_SIZE(p)
56 ASSERT(sizeof(long) <= sizeof(gpointer));
57 #define LONG_TO_GPOINTER(l) ((gpointer)(long)(l))
58 #define GPOINTER_TO_LONG(p) ((long)(p))
61 /* ----------------------------------------------------------------------
62 * File descriptors and uxsel.
66 #if GTK_CHECK_VERSION(2,0,0)
74 #if GTK_CHECK_VERSION(2,0,0)
75 gboolean fd_input_func(GIOChannel *source, GIOCondition condition,
78 int sourcefd = g_io_channel_unix_get_fd(source);
80 * We must process exceptional notifications before ordinary
81 * readability ones, or we may go straight past the urgent
84 if (condition & G_IO_PRI)
85 select_result(sourcefd, 4);
86 if (condition & G_IO_IN)
87 select_result(sourcefd, 1);
88 if (condition & G_IO_OUT)
89 select_result(sourcefd, 2);
94 void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
96 if (condition & GDK_INPUT_EXCEPTION)
97 select_result(sourcefd, 4);
98 if (condition & GDK_INPUT_READ)
99 select_result(sourcefd, 1);
100 if (condition & GDK_INPUT_WRITE)
101 select_result(sourcefd, 2);
105 uxsel_id *uxsel_input_add(int fd, int rwx) {
106 uxsel_id *id = snew(uxsel_id);
108 #if GTK_CHECK_VERSION(2,0,0)
110 if (rwx & 1) flags |= G_IO_IN;
111 if (rwx & 2) flags |= G_IO_OUT;
112 if (rwx & 4) flags |= G_IO_PRI;
113 id->chan = g_io_channel_unix_new(fd);
114 g_io_channel_set_encoding(id->chan, NULL, NULL);
115 id->watch_id = g_io_add_watch_full(id->chan, GDK_PRIORITY_REDRAW+1, flags,
116 fd_input_func, NULL, NULL);
119 if (rwx & 1) flags |= GDK_INPUT_READ;
120 if (rwx & 2) flags |= GDK_INPUT_WRITE;
121 if (rwx & 4) flags |= GDK_INPUT_EXCEPTION;
123 id->id = gdk_input_add(fd, flags, fd_input_func, NULL);
129 void uxsel_input_remove(uxsel_id *id) {
130 #if GTK_CHECK_VERSION(2,0,0)
131 g_source_remove(id->watch_id);
132 g_io_channel_unref(id->chan);
134 gdk_input_remove(id->id);
139 /* ----------------------------------------------------------------------
143 static guint timer_id = 0;
145 static gint timer_trigger(gpointer data)
147 unsigned long now = GPOINTER_TO_LONG(data);
148 unsigned long next, then;
152 * Destroy the timer we got here on.
155 g_source_remove(timer_id);
160 * run_timers() may cause a call to timer_change_notify, in which
161 * case a new timer will already have been set up and left in
162 * timer_id. If it hasn't, and run_timers reports that some timing
163 * still needs to be done, we do it ourselves.
165 if (run_timers(now, &next) && !timer_id) {
167 now = GETTICKCOUNT();
168 if (now - then > next - then)
172 timer_id = g_timeout_add(ticks, timer_trigger, LONG_TO_GPOINTER(next));
176 * Returning FALSE means 'don't call this timer again', which
177 * _should_ be redundant given that we removed it above, but just
178 * in case, return FALSE anyway.
183 void timer_change_notify(unsigned long next)
188 g_source_remove(timer_id);
190 ticks = next - GETTICKCOUNT();
192 ticks = 1; /* just in case */
194 timer_id = g_timeout_add(ticks, timer_trigger, LONG_TO_GPOINTER(next));
197 /* ----------------------------------------------------------------------
198 * Toplevel callbacks.
201 static guint toplevel_callback_idle_id;
202 static int idle_fn_scheduled;
204 static void notify_toplevel_callback(void *);
207 * Replacement code for the gtk_quit_add() function, which GTK2 - in
208 * their unbounded wisdom - deprecated without providing any usable
209 * replacement, and which we were using to ensure that our idle
210 * function for toplevel callbacks was only run from the outermost
213 * We must make sure that all our subsidiary calls to gtk_main() are
214 * followed by a call to post_main(), so that the idle function can be
215 * re-established when we end up back at the top level.
219 if (gtk_main_level() == 1)
220 notify_toplevel_callback(NULL);
223 static gint idle_toplevel_callback_func(gpointer data)
225 if (gtk_main_level() > 1) {
227 * We don't run callbacks if we're in the middle of a
228 * subsidiary gtk_main. So unschedule this idle function; it
229 * will be rescheduled by post_main() when we come back up a
230 * level, which is the earliest we might actually do
233 if (idle_fn_scheduled) { /* double-check, just in case */
234 g_source_remove(toplevel_callback_idle_id);
235 idle_fn_scheduled = FALSE;
238 run_toplevel_callbacks();
242 * If we've emptied our toplevel callback queue, unschedule
243 * ourself. Otherwise, leave ourselves pending so we'll be called
244 * again to deal with more callbacks after another round of the
247 if (!toplevel_callback_pending() && idle_fn_scheduled) {
248 g_source_remove(toplevel_callback_idle_id);
249 idle_fn_scheduled = FALSE;
255 static void notify_toplevel_callback(void *frontend)
257 if (!idle_fn_scheduled) {
258 toplevel_callback_idle_id =
259 g_idle_add(idle_toplevel_callback_func, NULL);
260 idle_fn_scheduled = TRUE;
264 /* ----------------------------------------------------------------------
265 * Setup function. The real main program must call this.
268 void gtkcomm_setup(void)
271 request_callback_notifications(notify_toplevel_callback, NULL);