home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.10 / util-lin / util-linux-1.10 / selection / selection.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-29  |  5.2 KB  |  236 lines

  1. /* implement copying and pasting in Linux virtual consoles */
  2. /* Andrew Haylett, 17th June 1993 */
  3.  
  4. #include <unistd.h>
  5. #include <stdio.h>
  6. #include <termios.h>
  7. #include <fcntl.h>
  8. #include <signal.h>
  9. #include <errno.h>
  10. #include <sys/kd.h>
  11. #include <sys/ioctl.h>
  12. #include <sys/time.h>
  13.  
  14. #include "mouse.h"
  15.  
  16. extern int ms_copy_button, ms_paste_button;
  17.  
  18. static const int SCALE = 10;
  19. static const long CLICK_INTERVAL = 250;    /* msec */
  20. static const char *console = "/dev/tty0";
  21.  
  22. typedef enum { character = 0, word = 1, line = 2 } sel_mode;
  23.  
  24. static int open_console(const int mode);
  25. static void set_sel(const int xs, const int ys, const int xe,
  26.                     const int ye, const sel_mode mode);
  27. static void paste(void);
  28. static long interval(const struct timeval *t1, const struct timeval *t2);
  29. static int check_mode(void);
  30.  
  31. int
  32. main(int argc, char *argv[])
  33. {
  34.     struct ms_event ev;
  35.     struct winsize win;
  36.     struct timeval tv1, tv2;
  37.     int xs, ys, xe, ye, x1, y1, fd, clicks = 0;
  38.     sel_mode mode;
  39.     
  40.     fd = open_console(O_RDONLY);
  41.     ioctl(fd, TIOCGWINSZ, &win);
  42.     close(fd);
  43.     if (! win.ws_col || ! win.ws_row)
  44.     {
  45.         fprintf(stderr, "selection: zero screen dimension, assuming 80x25.\n");
  46.         win.ws_col = 80;
  47.         win.ws_row = 25;
  48.     }
  49.  
  50.     ms_params(argc, argv);
  51.  
  52.     if (ms_init(win.ws_col * SCALE - 1, win.ws_row * SCALE - 1))
  53.     exit(1);
  54.  
  55.     if (fork() > 0)
  56.     exit(0);
  57.     setsid();
  58.  
  59.     gettimeofday(&tv1, (struct timezone *)NULL);
  60.  
  61. restart:
  62.     while (1)
  63.     {
  64.     if (check_mode())
  65.         goto restart;
  66.     if (get_ms_event(&ev))
  67.         exit(1);
  68.     if (ev.ev_butstate == ms_copy_button)
  69.     {
  70.         ++clicks;
  71.         gettimeofday(&tv2, (struct timezone *)NULL);
  72.         xs = ev.ev_x / SCALE + 1;
  73.         ys = ev.ev_y / SCALE + 1;
  74.         if (interval(&tv1, &tv2) < CLICK_INTERVAL && clicks == 1)
  75.         {
  76.             mode = word;
  77.         set_sel(xs, ys, xs, ys, mode);
  78.         }
  79.         else if (interval(&tv1, &tv2) < CLICK_INTERVAL && clicks == 2)
  80.         {
  81.             mode = line;
  82.         set_sel(xs, ys, xs, ys, mode);
  83.         }
  84.         else
  85.         {
  86.             mode = character;
  87.         clicks = 0;
  88.         do    /* wait for left button up */
  89.         {
  90.             if (check_mode())
  91.                 goto restart;
  92.             if (get_ms_event(&ev))
  93.                 exit(1);
  94.         } while (ev.ev_butstate);
  95.         x1 = y1 = 0;
  96.         do    /* track start selection until left button down */
  97.         {
  98.             xs = ev.ev_x / SCALE + 1;
  99.             ys = ev.ev_y / SCALE + 1;
  100.             if (xs != x1 || ys != y1)
  101.             {
  102.             set_sel(xs, ys, xs, ys, mode);
  103.             x1 = xs; y1 = ys;
  104.             }
  105.             if (check_mode())
  106.                 goto restart;
  107.             if (get_ms_event(&ev))
  108.                 exit(1);
  109.         } while (ev.ev_butstate != ms_copy_button);
  110.         }
  111.         x1 = y1 = 0;
  112.         gettimeofday(&tv1, (struct timezone *)NULL);
  113.         do    /* track end selection until left button up */
  114.         {
  115.         xe = ev.ev_x / SCALE + 1;
  116.         ye = ev.ev_y / SCALE + 1;
  117.         if (xe != x1 || ye != y1)
  118.         {
  119.             set_sel(xs, ys, xe, ye, mode);
  120.             x1 = xe; y1 = ye;
  121.         }
  122.         if (check_mode())
  123.             goto restart;
  124.         if (get_ms_event(&ev))
  125.             exit(1);
  126.         } while (ev.ev_butstate == ms_copy_button);
  127.     } else if (ev.ev_butstate == ms_paste_button)
  128.     {    /* paste selection */
  129.         paste();
  130.         do    /* wait for right button up */
  131.         {
  132.             if (check_mode())
  133.                 goto restart;
  134.         if (get_ms_event(&ev))
  135.             exit(1);
  136.         } while (ev.ev_butstate);
  137.         gettimeofday(&tv1, (struct timezone *)NULL);
  138.         clicks = 0;
  139.     }
  140.     }
  141. }
  142.  
  143. /* We have to keep opening and closing the console because (a) /dev/tty0
  144.    changed its behaviour at some point such that the current VC is fixed
  145.    after the open(), rather than being re-evaluated at each write(), and (b)
  146.    because we seem to lose our grip on /dev/tty? after someone logs in if
  147.    this is run from /etc/rc. */
  148.  
  149. static int
  150. open_console(const int mode)
  151. {
  152.     int fd;
  153.  
  154.     if ((fd = open(console, mode)) < 0)
  155.     {
  156.         perror("selection: open_console()");
  157.         exit(1);
  158.     }
  159.     return fd;
  160. }
  161.  
  162. /* mark selected text on screen. */
  163. static void
  164. set_sel(const int xs, const int ys,
  165.         const int xe, const int ye, const sel_mode mode)
  166. {
  167.     unsigned char buf[sizeof(char) + 5 * sizeof(short)];
  168.     unsigned short *arg = (unsigned short *)(buf + 1);
  169.     int fd;
  170.  
  171.     buf[0] = 2;
  172.  
  173.     arg[0] = xs;
  174.     arg[1] = ys;
  175.     arg[2] = xe;
  176.     arg[3] = ye;
  177.     arg[4] = mode;
  178.  
  179.     fd = open_console(O_WRONLY);
  180.     if (ioctl(fd, TIOCLINUX, buf) < 0)
  181.     {
  182.     perror("selection: ioctl(..., TIOCLINUX, ...)");
  183.     exit(1);
  184.     }
  185.     close(fd);
  186. }
  187.  
  188. /* paste contents of selection buffer into console. */
  189. static void
  190. paste(void)
  191. {
  192.     char c = 3;
  193.     int fd;
  194.  
  195.     fd = open_console(O_WRONLY);
  196.     if (ioctl(fd, TIOCLINUX, &c) < 0)
  197.     {
  198.     perror("selection: ioctl(..., TIOCLINUX, ...)");
  199.     exit(1);
  200.     }
  201.     close(fd);
  202. }
  203.  
  204. /* evaluate interval between times. */
  205. static long
  206. interval(const struct timeval *t1, const struct timeval *t2)
  207. {
  208.     return (t2->tv_sec  - t1->tv_sec)  * 1000
  209.          + (t2->tv_usec - t1->tv_usec) / 1000;
  210. }
  211.  
  212. /* Check whether console is in graphics mode; if so, wait until it isn't. */
  213. static int
  214. check_mode(void)
  215. {
  216.     int fd, ch = 0;
  217.     long kd_mode;
  218.  
  219.     do
  220.     {
  221.     fd = open_console(O_RDONLY);
  222.     if (ioctl(fd, KDGETMODE, &kd_mode) < 0)
  223.     {
  224.         perror("selection: ioctl(..., KDGETMODE, ...)");
  225.         exit(1);
  226.     }
  227.     close(fd);
  228.     if (kd_mode != KD_TEXT)
  229.     {
  230.         ++ch;
  231.         sleep(2);
  232.     }
  233.     } while (kd_mode != KD_TEXT);
  234.     return (ch > 0);
  235. }
  236.