source: neercs/trunk/src/server.c @ 2593

Last change on this file since 2593 was 2593, checked in by Pascal Terjan, 12 years ago
  • Disconnect when failing to write to the client
  • Property svn:eol-style set to native
File size: 11.7 KB
Line 
1/*
2 *  neercs        console-based window manager
3 *  Copyright (c) 2006 Sam Hocevar <sam@zoy.org>
4 *                2008 Jean-Yves Lamoureux <jylam@lnxscene.org>
5 *                2008 Pascal Terjan <pterjan@linuxfr.org>
6 *                All Rights Reserved
7 *
8 *  $Id$
9 *
10 *  This program is free software. It comes without any warranty, to
11 *  the extent permitted by applicable law. You can redistribute it
12 *  and/or modify it under the terms of the Do What The Fuck You Want
13 *  To Public License, Version 2, as published by Sam Hocevar. See
14 *  http://sam.zoy.org/wtfpl/COPYING for more details.
15 */
16
17#include "config.h"
18
19#include <stdio.h>
20#include <string.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <fcntl.h>
24#include <signal.h>
25#include <sys/ioctl.h>
26#include <sys/types.h>
27#include <sys/wait.h>
28#include <sys/time.h>
29#include <time.h>
30#include <pwd.h>
31
32#include <errno.h>
33#include <caca.h>
34
35#include "neercs.h"
36
37static int send_to_client(const char * msg, struct screen_list* screen_list)
38{
39    int ret;
40    if(!screen_list->c_socket)
41        connect_client(screen_list);
42    debug("Sending message (%s) to client on socket %d", msg, screen_list->c_socket);
43    if(!screen_list->c_socket)
44        ret = -1;
45    else
46        ret = write(screen_list->c_socket, msg, strlen(msg));
47    if(ret < 0)
48    {
49        fprintf(stderr, "Failed to send message to client: %s\n", strerror(errno));
50        detach(screen_list);
51    }
52    return ret;
53}
54
55static int set_title(const char * title, struct screen_list* screen_list)
56{
57    char buf[1024];
58    int bytes;
59
60    bytes = snprintf(buf, sizeof(buf)-1, "TITLE %s", title);
61    buf[bytes] = '\0';
62
63    return send_to_client(buf, screen_list);
64}
65
66static int set_cursor(int state, struct screen_list* screen_list)
67{
68    char buf[16];
69    int bytes;
70
71    bytes = snprintf(buf, sizeof(buf)-1, "CURSOR %d", state);
72    buf[bytes] = '\0';
73
74    return send_to_client(buf, screen_list);
75}
76
77static int request_refresh(struct screen_list* screen_list)
78{
79    size_t bytes;
80    void *buf;
81    char *buf2;
82    buf = cucul_export_memory (screen_list->cv, "caca", &bytes);
83    buf2 = malloc(bytes+8);
84    memcpy(buf2, "REFRESH ", 8);
85    memcpy(buf2+8, buf, bytes);
86    if(!screen_list->c_socket)
87        connect_client(screen_list);
88    if(screen_list->c_socket)
89        if(write(screen_list->c_socket, buf2, bytes+8) <= 0)
90            detach(screen_list);
91    free(buf);
92    free(buf2);
93    return 0;
94}
95
96int detach(struct screen_list* screen_list)
97{
98    screen_list->attached = 0;
99    if(screen_list->c_socket)
100    {
101        send_to_client("DETACH", screen_list);
102        close(screen_list->c_socket);
103        screen_list->c_socket = 0;
104    }
105    return 0;
106}
107
108int server_main(int *to_grab, char **to_start, struct screen_list *screen_list)
109{
110    int i;
111    int eof = 0, refresh = 1, command = 0;
112    long long unsigned int last_key_time = 0;
113    int mainret = 0;
114
115    screen_list->attached = 0;
116
117    /* Create socket and bind it */
118    create_server_socket(screen_list);
119    connect_client(screen_list);
120
121    screen_list->width = screen_list->height = 10;
122
123    /* Create main canvas */
124    screen_list->cv = cucul_create_canvas(screen_list->width,
125                                          screen_list->height
126                                          + screen_list->mini*6
127                                          + screen_list->status);
128
129    if(!to_grab && !to_start)
130    {
131        add_screen(screen_list,
132                   create_screen(screen_list->width,
133                                 screen_list->height,
134                                 screen_list->default_shell));
135    }
136
137    /* Attach processes */
138    if(to_grab)
139    {
140        for(i=0; to_grab[i]; i++)
141        {
142            add_screen(screen_list,
143                       create_screen_grab(screen_list->width,
144                                          screen_list->height,
145                                          to_grab[i]));
146        }
147        free(to_grab);
148    }
149
150    /* Launch command line processes */
151    if(to_start)
152    {
153        for(i=0; to_start[i]; i++)
154        {
155            add_screen(screen_list,
156                       create_screen(screen_list->width,
157                                     screen_list->height,
158                                     to_start[i]));
159        }
160        free(to_start);
161    }
162
163    /* Windows are in a temporary state, resize them to the right dimensions */
164    update_windows_props(screen_list);/* FIXME after attach */
165
166    last_key_time = get_us();
167
168    for(;;)
169    {
170        int quit = 0;
171        ssize_t n;
172        char buf[4097];
173
174        /* Read program output */
175        refresh |= update_screens_contents(screen_list);
176
177        /* Check if we got something from the client */
178        while (screen_list->s_socket && (n = read(screen_list->s_socket, buf, sizeof(buf)-1)) > 0)
179        {
180            buf[n] = 0;
181            debug("Received command %s", buf);
182            if(!strncmp("ATTACH ", buf, 7))
183            {
184                screen_list->attached = 1;
185                cucul_free_canvas(screen_list->cv);
186                screen_list->cv = cucul_create_canvas(atoi(buf+7), atoi(buf+18));
187                screen_list->width  = cucul_get_canvas_width(screen_list->cv);
188                screen_list->height = cucul_get_canvas_height(screen_list->cv) - ((screen_list->mini*6) + (screen_list->status));
189                update_windows_props(screen_list);
190                cucul_clear_canvas(screen_list->cv);
191                refresh = 1;
192            }
193            else if(!strncmp("QUIT", buf, 4))
194            {
195                quit = 1;
196            }
197            else if(!strncmp("RESIZE ", buf, 7))
198            {
199                cucul_free_canvas(screen_list->cv);
200                screen_list->cv = cucul_create_canvas(atoi(buf+7), atoi(buf+18));
201                screen_list->width  = cucul_get_canvas_width(screen_list->cv);
202                screen_list->height = cucul_get_canvas_height(screen_list->cv) - ((screen_list->mini*6) + (screen_list->status));
203                update_windows_props(screen_list);
204                cucul_clear_canvas(screen_list->cv);
205                refresh = 1;
206            }
207            else if(!strncmp("KEY ", buf, 4))
208            {
209                unsigned int c = atoi(buf+4);
210                char *str = NULL;
211                int size = 0;
212                /* CTRL-A has been pressed before, handle this as a
213                 * command, except that CTRL-A a sends literal CTRL-A */
214                if(command && (c != 'a'))
215                {
216                    command = 0;
217                    refresh |= handle_command_input(screen_list, c);
218                }
219                else
220                {
221                    /* Not in command mode */
222                    last_key_time = get_us();
223                    set_cursor(1, screen_list);
224
225                    /* Kill screensaver */
226                    if(screen_list->in_screensaver)
227                    {
228                        screensaver_kill(screen_list);
229                        screen_list->in_screensaver = 0;
230                        refresh = 1;
231                        continue;
232                    }
233                    /* Handle lock window */
234                    if(screen_list->locked)
235                        refresh |= update_lock(c, screen_list);
236                    else
237                    {
238                        switch(c)
239                        {
240                        case 0x01: //CACA_KEY_CTRL_A:
241                            command = 1; break;
242                        case CACA_KEY_ESCAPE:
243                            if(screen_list->help)
244                            {
245                                screen_list->help = 0;
246                                refresh = 1;
247                                break;
248                            }
249                        default:
250                            /* CTRL-A a sends literal CTRL-A */
251                            if (command && (c == 'a'))
252                            {
253                                c = 0x01;
254                            }
255                            /* Normal key, convert it if needed */
256                            str = convert_input_ansi(&c, &size);
257                            write(screen_list->screen[screen_list->pty]->fd, str, size);
258                            break;
259                        }
260                    }
261                }
262            }
263            else
264            {
265                fprintf(stderr, "Unknown command received: %s\n", buf);
266            }
267        }
268
269        /* No more screens, exit */
270        if(!screen_list->count) break;
271
272        /* User requested to exit */
273        if(quit) break;
274
275        /* Update each screen canvas  */
276        refresh |= update_terms(screen_list);
277
278        /* Launch reccurents if any */
279        refresh |= handle_recurrents(screen_list);
280
281        /* Resfresh screen */
282        if(!screen_list->attached)
283        {
284            /* No need to refresh
285             * Don't use the CPU too much
286             * Would be better to select on terms + socket
287             */
288            sleep(1);
289        }
290        /* Draw lock window */
291        else if(screen_list->locked)
292        {
293            draw_lock(screen_list);
294            refresh = 1;
295        }
296        else
297        {
298            if((refresh || screen_list->in_bell) &&
299               (get_us() - last_key_time < screen_list->screensaver_timeout))
300            {
301                refresh_screens(screen_list);
302                if(screen_list->attached)
303                {
304                    if(screen_list->screen[screen_list->pty]->title)
305                        set_title(screen_list->screen[screen_list->pty]->title, screen_list);
306                    else
307                        set_title(PACKAGE_STRING, screen_list);
308                }
309                refresh = 1;
310
311            }
312            if((get_us() - last_key_time > screen_list->screensaver_timeout))
313            {
314                if(!screen_list->in_screensaver)
315                {
316                    screensaver_init(screen_list);
317                    screen_list->in_screensaver = 1;
318                    set_cursor(0, screen_list);
319                }
320                draw_screensaver(screen_list);
321                refresh = 1;
322            }
323
324            if((get_us() - last_key_time > screen_list->autolock_timeout))
325            {
326                screen_list->locked = 1;
327                refresh = 1;
328            }
329
330        }
331
332        if(refresh)
333        {
334            if(screen_list->attached)
335                request_refresh(screen_list);
336            refresh = 0;
337        }
338
339        eof = 1;
340        for(i=0; i < screen_list->count; i++)
341            if(screen_list->screen[i]->fd >= 0)
342                eof = 0;
343        if(eof)
344            break;
345    }
346
347    detach(screen_list);
348
349    /* Clean up */
350    cucul_free_canvas(screen_list->cv);
351
352    for(i = 0; i < screen_list->count; i++)
353    {
354        destroy_screen(screen_list->screen[i]);
355    }
356
357    if(screen_list->s_socket_path)
358    {
359        unlink(screen_list->s_socket_path);
360        free(screen_list->s_socket_path);
361    }
362
363    if(screen_list->c_socket_path)
364        free(screen_list->c_socket_path);
365
366    if(screen_list->s_socket)
367        close(screen_list->s_socket);
368
369    if(screen_list->c_socket)
370        close(screen_list->c_socket);
371
372    if(screen_list->screen) free(screen_list->screen);
373
374    for(i=0; i<screen_list->recurrent_list->count; i++)
375    {
376        remove_recurrent(screen_list->recurrent_list, i);
377        i = 0;
378    }
379
380    if(screen_list->recurrent_list->recurrent) free(screen_list->recurrent_list->recurrent);
381    if(screen_list->recurrent_list)            free(screen_list->recurrent_list);
382
383    if(screen_list->session_name)
384        free(screen_list->session_name);
385
386    if(screen_list)
387        free(screen_list);
388
389    return mainret;
390}
391
392long long get_us(void)
393{
394    struct timeval tv;
395    gettimeofday(&tv, NULL);
396    return (tv.tv_sec*(1000000) + tv.tv_usec);
397}
Note: See TracBrowser for help on using the repository browser.