source: neercs/trunk/src/client.c @ 4784

Last change on this file since 4784 was 4784, checked in by Sam Hocevar, 9 years ago

test: fix copyright information, courtesy of Mitchel Humpherys. Sorry,
you don't qualify for copyright here :-)

File size: 9.3 KB
Line 
1/*
2 *  neercs        console-based window manager
3 *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
4 *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
5 *                2008-2011 Pascal Terjan <pterjan@linuxfr.org>
6 *                All Rights Reserved
7 *
8 *  This program is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15#include "config.h"
16
17#include <stdio.h>
18#include <string.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <signal.h>
23#include <sys/ioctl.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26#include <sys/time.h>
27#include <time.h>
28#include <pwd.h>
29
30#include <errno.h>
31#include <caca.h>
32
33#include "neercs.h"
34
35#define NEERCS_RECV_BUFSIZE 128*1024
36
37
38int start_client(struct screen_list *screen_list)
39{
40    char *sess = NULL;
41    create_socket(screen_list, SOCK_CLIENT);
42    while ((sess = connect_socket(screen_list, SOCK_SERVER)) == NULL)
43        usleep(100);
44    free(sess);
45
46    /* Create main canvas and associated caca window */
47    screen_list->cv = caca_create_canvas(0, 0);
48    screen_list->dp = caca_create_display(screen_list->cv);
49    screen_list->mouse_button = 0;
50
51    if (!screen_list->dp)
52        return -3;
53
54    caca_set_display_time(screen_list->dp, screen_list->delay * 1000);
55    caca_set_cursor(screen_list->dp, 1);
56
57    request_attach(screen_list);
58
59    return 0;
60}
61
62int send_event(caca_event_t ev, struct screen_list *screen_list)
63{
64    enum caca_event_type t;
65    char buf[64];
66    int bytes = 0;
67
68    t = caca_get_event_type(&ev);
69
70    if (t & CACA_EVENT_KEY_PRESS)
71    {
72        bytes =  snprintf(buf, sizeof(buf) - 1, "KEY %d",
73                          caca_get_event_key_ch(&ev));
74        debug("Sending key press to server: %s", buf);
75    }
76    else if (t & CACA_EVENT_RESIZE)
77    {
78        bytes = snprintf(buf, sizeof(buf) - 1, "RESIZE %10d %10d",
79                         caca_get_event_resize_width(&ev),
80                         caca_get_event_resize_height(&ev));
81    }
82    else if (t & CACA_EVENT_MOUSE_PRESS)
83    {
84        screen_list->mouse_button = caca_get_event_mouse_button(&ev);
85        bytes = snprintf(buf, sizeof(buf) - 1, "MOUSEP %10d %10d %10d",
86                         caca_get_mouse_x(screen_list->dp),
87                         caca_get_mouse_y(screen_list->dp),
88                         screen_list->mouse_button);
89    }
90    else if (t & CACA_EVENT_MOUSE_RELEASE)
91    {
92        bytes = snprintf(buf, sizeof(buf) - 1, "MOUSER %10d %10d %10d",
93                         caca_get_mouse_x(screen_list->dp),
94                         caca_get_mouse_y(screen_list->dp),
95                         screen_list->mouse_button);
96        screen_list->mouse_button = 0;
97    }
98    else if (t & CACA_EVENT_MOUSE_MOTION)
99    {
100        int x = caca_get_mouse_x(screen_list->dp);
101        int y = caca_get_mouse_y(screen_list->dp);
102        int b = screen_list->mouse_button;
103        debug("Mouse motion, button %d", b);
104        if (x != screen_list->old_x || y != screen_list->old_y)
105        {
106            screen_list->old_x = caca_get_mouse_x(screen_list->dp);
107            screen_list->old_y = caca_get_mouse_y(screen_list->dp);
108
109            bytes = snprintf(buf, sizeof(buf) - 1, "MOUSEM %10d %10d %10d",
110                             caca_get_mouse_x(screen_list->dp),
111                             caca_get_mouse_y(screen_list->dp),
112                             b>=0?b:0);
113        }
114    }
115    else if (t & CACA_EVENT_QUIT)
116    {
117        bytes = snprintf(buf, sizeof(buf) - 1, "QUIT");
118    }
119    if (bytes)
120    {
121        ssize_t r;
122        buf[bytes] = '\0';
123        debug("Sending '%s', %d bytes", buf, bytes);
124        r = write(screen_list->comm.socket[SOCK_SERVER], buf, bytes+1);
125        while (r < 0 && errno == EAGAIN)
126        {
127            usleep(20);
128            r = write(screen_list->comm.socket[SOCK_SERVER], buf, bytes+1);
129        }
130        return r < 0;
131    }
132    return 0;
133}
134
135int send_delay(struct screen_list *screen_list)
136{
137    debug("Sending DELAY\n");
138    char buf[18];
139    int bytes;
140    bytes = snprintf(buf, sizeof(buf) - 1, "DELAY %10d", screen_list->delay);
141    buf[bytes] = '\0';
142    return write(screen_list->comm.socket[SOCK_SERVER], buf, strlen(buf)) <= 0;
143}
144
145/** \brief Main client loop.
146 *
147 * This is the main client loop.
148 *
149 * Repeat forever:
150 *  - if data is available on the client socket, read it and interpret it:
151 *    - "DETACH": exit the loop
152 *    - "UPDATE": update screen with the given canvas data
153 *    - "REFRESH": refresh the whole display
154 *    - "CURSOR": set cursor position
155 *    - "TITLE": set window or display title
156 *  - wait for an input event with a 10ms timeout
157 */
158void mainloop(struct screen_list *screen_list)
159{
160    char *buf = NULL;
161
162    screen_list->last_key_time = get_us();
163
164    for (;;)
165    {
166        caca_event_t ev;
167        int ret = 0;
168        ssize_t n;
169        if (!screen_list)
170            goto end;
171        if (!buf)
172            buf = malloc(NEERCS_RECV_BUFSIZE);
173        if (!buf)
174        {
175            debug("Failed to allocate memory");
176            goto end;
177        }
178        if (screen_list->comm.socket[SOCK_CLIENT]
179            && (n =
180                read(screen_list->comm.socket[SOCK_CLIENT], buf,
181                     NEERCS_RECV_BUFSIZE - 1)) > 0)
182        {
183            buf[n] = 0;
184            debug("Received from server: '%s' (%d bytes)", buf, n);
185            if (!strncmp("DETACH", buf, 6))
186            {
187                /* ret = 1; Not used */
188                break;
189            }
190            else if (!strncmp("UPDATE ", buf, 7))
191            {
192                int x, y;
193                ssize_t l2 = 0, lb = 0;
194                char *buf2;
195                size_t l = 0;
196                /* FIXME check the length before calling atoi */
197                x = atoi(buf + 8);
198                y = atoi(buf + 19);
199
200                /* 0 means we have valid data but incomplete, so read the rest
201                 */
202                while (l == 0)
203                {
204                    buf2 = realloc(buf, l2 + NEERCS_RECV_BUFSIZE);
205                    if (!buf2)
206                    {
207                        debug("Failed to allocate memory");
208                        goto end;
209                    }
210                    buf = buf2;
211                    fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, 0);
212                    lb = read(screen_list->comm.socket[SOCK_CLIENT], buf + l2,
213                              NEERCS_RECV_BUFSIZE - 1);
214                    if (lb < 0)
215                    {
216                        debug
217                            ("Failed to read the end of the refresh message (%s)",
218                             strerror(errno));
219                        l = -1;
220                    }
221                    else
222                    {
223                        l2 += lb;
224                        l = caca_import_area_from_memory(screen_list->cv, x, y,
225                                                         buf, l2, "caca");
226                    }
227                }
228                fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL,
229                      O_NONBLOCK);
230            }
231            else if (!strncmp("REFRESH ", buf, 8))
232            {
233                int dt, x, y;
234                /* FIXME check the length before calling atoi */
235                x = atoi(buf + 8);
236                y = atoi(buf + 19);
237                caca_gotoxy(screen_list->cv, x, y);
238                caca_refresh_display(screen_list->dp);
239                dt = caca_get_display_time(screen_list->dp);
240
241                /* Adjust refresh delay so that the server do not compute
242                   useless things */
243                if (dt > 2 * 1000 * screen_list->delay
244                    && screen_list->delay <= 100)
245                {
246                    screen_list->delay *= 2;
247                    send_delay(screen_list);
248                }
249                else if (dt < screen_list->delay * 1000 * 1.2 &&
250                         screen_list->delay >=
251                         3 * screen_list->requested_delay / 2)
252                {
253                    screen_list->delay = 2 * screen_list->delay / 3;
254                    send_delay(screen_list);
255                }
256            }
257            else if (!strncmp("CURSOR ", buf, 7))
258            {
259                caca_set_cursor(screen_list->dp, atoi(buf + 7));
260            }
261            else if (!strncmp("TITLE ", buf, 6))
262            {
263                caca_set_display_title(screen_list->dp, buf + 6);
264                caca_refresh_display(screen_list->dp);
265            }
266            else
267            {
268                debug("Unknown message received from server: %s", buf);
269            }
270        }
271
272        if (ret)
273        {
274            debug("ret1\n");
275            break;
276        }
277        ret = caca_get_event(screen_list->dp,
278                             CACA_EVENT_KEY_PRESS
279                             | CACA_EVENT_MOUSE_PRESS
280                             | CACA_EVENT_MOUSE_RELEASE
281                             | CACA_EVENT_MOUSE_MOTION
282                             | CACA_EVENT_RESIZE
283                             | CACA_EVENT_QUIT, &ev, 10000);
284        if (ret)
285            ret = send_event(ev, screen_list);
286
287        if (ret)
288        {
289            debug("ret2\n");
290            break;
291        }
292    }
293
294  end:
295    if (buf)
296        free(buf);
297
298}
Note: See TracBrowser for help on using the repository browser.