Add support for SPICE.
[virt-click.git] / commands.c
1 /* virt-click
2  * Copyright (C) 2011 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <glib/gi18n.h>
27
28 #include "click.h"
29
30 static gboolean click_release (gpointer opaque);
31
32 static int
33 parse_click (self_t *self, gchar **args, guint nr_args)
34 {
35   int b;
36
37   if (nr_args < 3 || nr_args > 4)
38     return -1;
39
40   if (sscanf (args[1], "%d", &self->command.click.x) != 1 ||
41       sscanf (args[2], "%d", &self->command.click.y) != 1)
42     return -1;
43
44   b = 1;
45   if (nr_args == 4) {
46     if (strcasecmp (args[3], "left") == 0)
47       b = 1;
48     else if (strcasecmp (args[3], "middle") == 0)
49       b = 2;
50     else if (strcasecmp (args[3], "right") == 0)
51       b = 3;
52     else if (strcasecmp (args[3], "up") == 0)
53       b = 4;
54     else if (strcasecmp (args[3], "down") == 0)
55       b = 5;
56     else if (strcasecmp (args[3], "scrollleft") == 0)
57       b = 6;
58     else if (strcasecmp (args[3], "scrollright") == 0)
59       b = 7;
60     else if (sscanf (args[3], "%d", &b) != 1)
61       return -1;
62   }
63
64   self->command.click.b = b;
65   self->command.cmd = CMD_CLICK;
66
67   return 0;
68 }
69
70 int
71 vc_parse_command (self_t *self, gchar **args, guint nr_args)
72 {
73   if (strcasecmp (args[0], "click") == 0)
74     return parse_click (self, args, nr_args);
75
76   return -1;
77 }
78
79 #define NOT_SUPPORTED(cmd) \
80   do { \
81     fprintf (stderr, "virt-click: %s: "                                 \
82              "command is not implemented for this connection type\n", cmd); \
83     self->ret = EXIT_FAILURE;                                           \
84     self->callbacks->shutdown (self);                                   \
85     return;                                                             \
86   } while (0)
87
88 void
89 vc_issue_command (self_t *self)
90 {
91   int r = -1;
92
93   switch (self->command.cmd) {
94   case CMD_CLICK:
95     if (verbose)
96       fprintf (stderr, "click x=%d y=%d b=%d\n",
97                self->command.click.x, self->command.click.y,
98                self->command.click.b);
99
100     if (!self->callbacks->click)
101       NOT_SUPPORTED ("click");
102
103     r = self->callbacks->click (self,
104                                 self->command.click.x, self->command.click.y,
105                                 self->command.click.b);
106     if (r == -1)
107       goto out;
108
109     g_timeout_add (100, click_release, self);
110
111     break;
112   }
113
114  out:
115   if (r == -1) {
116     fprintf (stderr, "virt-click: error sending command to remote server\n");
117     self->ret = EXIT_FAILURE;
118     self->callbacks->shutdown (self);
119   }
120 }
121
122 /* To perform a button press in VNC we have to send the button press
123  * event, wait a short period, then send a button release event (ie.
124  * no buttons pressed).
125  */
126 static gboolean
127 click_release (gpointer opaque)
128 {
129   self_t *self = opaque;
130
131   if (verbose)
132     fprintf (stderr, "click release x=%d y=%d\n",
133              self->command.click.x, self->command.click.y);
134
135   self->callbacks->click (self,
136                           self->command.click.x, self->command.click.y,
137                           0);
138   self->callbacks->shutdown (self);
139
140   return FALSE;
141 }