"Fossies" - the Fresh Open Source Software Archive

Member "putty-0.73/unix/gtkcomm.c" (22 Sep 2019, 6191 Bytes) of package /linux/misc/putty-0.73.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gtkcomm.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.72_vs_0.73.

    1 /*
    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,
    5  * uxsel etc.)
    6  */
    7 
    8 #define _GNU_SOURCE
    9 
   10 #include <string.h>
   11 #include <assert.h>
   12 #include <stdlib.h>
   13 #include <string.h>
   14 #include <signal.h>
   15 #include <stdio.h>
   16 #include <time.h>
   17 #include <errno.h>
   18 #include <locale.h>
   19 #include <fcntl.h>
   20 #include <unistd.h>
   21 #include <sys/types.h>
   22 #include <sys/wait.h>
   23 #include <gtk/gtk.h>
   24 #if !GTK_CHECK_VERSION(3,0,0)
   25 #include <gdk/gdkkeysyms.h>
   26 #endif
   27 
   28 #if GTK_CHECK_VERSION(2,0,0)
   29 #include <gtk/gtkimmodule.h>
   30 #endif
   31 
   32 #define MAY_REFER_TO_GTK_IN_HEADERS
   33 
   34 #include "putty.h"
   35 #include "terminal.h"
   36 #include "gtkcompat.h"
   37 #include "gtkfont.h"
   38 #include "gtkmisc.h"
   39 
   40 #ifndef NOT_X_WINDOWS
   41 #include <gdk/gdkx.h>
   42 #include <X11/Xlib.h>
   43 #include <X11/Xutil.h>
   44 #include <X11/Xatom.h>
   45 #endif
   46 
   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)}
   50 
   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)
   55 #else /* Gtk 1.2 */
   56 ASSERT(sizeof(long) <= sizeof(gpointer));
   57 #define LONG_TO_GPOINTER(l) ((gpointer)(long)(l))
   58 #define GPOINTER_TO_LONG(p) ((long)(p))
   59 #endif
   60 
   61 /* ----------------------------------------------------------------------
   62  * File descriptors and uxsel.
   63  */
   64 
   65 struct uxsel_id {
   66 #if GTK_CHECK_VERSION(2,0,0)
   67     GIOChannel *chan;
   68     guint watch_id;
   69 #else
   70     int id;
   71 #endif
   72 };
   73 
   74 #if GTK_CHECK_VERSION(2,0,0)
   75 gboolean fd_input_func(GIOChannel *source, GIOCondition condition,
   76                        gpointer data)
   77 {
   78     int sourcefd = g_io_channel_unix_get_fd(source);
   79     /*
   80      * We must process exceptional notifications before ordinary
   81      * readability ones, or we may go straight past the urgent
   82      * marker.
   83      */
   84     if (condition & G_IO_PRI)
   85         select_result(sourcefd, SELECT_X);
   86     if (condition & (G_IO_IN | G_IO_HUP))
   87         select_result(sourcefd, SELECT_R);
   88     if (condition & G_IO_OUT)
   89         select_result(sourcefd, SELECT_W);
   90 
   91     return true;
   92 }
   93 #else
   94 void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
   95 {
   96     if (condition & GDK_INPUT_EXCEPTION)
   97         select_result(sourcefd, SELECT_X);
   98     if (condition & GDK_INPUT_READ)
   99         select_result(sourcefd, SELECT_R);
  100     if (condition & GDK_INPUT_WRITE)
  101         select_result(sourcefd, SELECT_W);
  102 }
  103 #endif
  104 
  105 uxsel_id *uxsel_input_add(int fd, int rwx) {
  106     uxsel_id *id = snew(uxsel_id);
  107 
  108 #if GTK_CHECK_VERSION(2,0,0)
  109     int flags = 0;
  110     if (rwx & SELECT_R) flags |= G_IO_IN | G_IO_HUP;
  111     if (rwx & SELECT_W) flags |= G_IO_OUT;
  112     if (rwx & SELECT_X) 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);
  117 #else
  118     int flags = 0;
  119     if (rwx & SELECT_R) flags |= GDK_INPUT_READ;
  120     if (rwx & SELECT_W) flags |= GDK_INPUT_WRITE;
  121     if (rwx & SELECT_X) flags |= GDK_INPUT_EXCEPTION;
  122     assert(flags);
  123     id->id = gdk_input_add(fd, flags, fd_input_func, NULL);
  124 #endif
  125 
  126     return id;
  127 }
  128 
  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);
  133 #else
  134     gdk_input_remove(id->id);
  135 #endif
  136     sfree(id);
  137 }
  138 
  139 /* ----------------------------------------------------------------------
  140  * Timers.
  141  */
  142 
  143 static guint timer_id = 0;
  144 
  145 static gint timer_trigger(gpointer data)
  146 {
  147     unsigned long now = GPOINTER_TO_LONG(data);
  148     unsigned long next, then;
  149     long ticks;
  150 
  151     /*
  152      * Destroy the timer we got here on.
  153      */
  154     if (timer_id) {
  155         g_source_remove(timer_id);
  156         timer_id = 0;
  157     }
  158 
  159     /*
  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.
  164      */
  165     if (run_timers(now, &next) && !timer_id) {
  166         then = now;
  167         now = GETTICKCOUNT();
  168         if (now - then > next - then)
  169             ticks = 0;
  170         else
  171             ticks = next - now;
  172         timer_id = g_timeout_add(ticks, timer_trigger, LONG_TO_GPOINTER(next));
  173     }
  174 
  175     /*
  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.
  179      */
  180     return false;
  181 }
  182 
  183 void timer_change_notify(unsigned long next)
  184 {
  185     long ticks;
  186 
  187     if (timer_id)
  188         g_source_remove(timer_id);
  189 
  190     ticks = next - GETTICKCOUNT();
  191     if (ticks <= 0)
  192         ticks = 1;                     /* just in case */
  193 
  194     timer_id = g_timeout_add(ticks, timer_trigger, LONG_TO_GPOINTER(next));
  195 }
  196 
  197 /* ----------------------------------------------------------------------
  198  * Toplevel callbacks.
  199  */
  200 
  201 static guint toplevel_callback_idle_id;
  202 static bool idle_fn_scheduled;
  203 
  204 static void notify_toplevel_callback(void *);
  205 
  206 static gint idle_toplevel_callback_func(gpointer data)
  207 {
  208     run_toplevel_callbacks();
  209 
  210     /*
  211      * If we've emptied our toplevel callback queue, unschedule
  212      * ourself. Otherwise, leave ourselves pending so we'll be called
  213      * again to deal with more callbacks after another round of the
  214      * event loop.
  215      */
  216     if (!toplevel_callback_pending() && idle_fn_scheduled) {
  217         g_source_remove(toplevel_callback_idle_id);
  218         idle_fn_scheduled = false;
  219     }
  220 
  221     return true;
  222 }
  223 
  224 static void notify_toplevel_callback(void *vctx)
  225 {
  226     if (!idle_fn_scheduled) {
  227         toplevel_callback_idle_id =
  228             g_idle_add(idle_toplevel_callback_func, NULL);
  229         idle_fn_scheduled = true;
  230     }
  231 }
  232 
  233 /* ----------------------------------------------------------------------
  234  * Setup function. The real main program must call this.
  235  */
  236 
  237 void gtkcomm_setup(void)
  238 {
  239     uxsel_init();
  240     request_callback_notifications(notify_toplevel_callback, NULL);
  241 }