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

Last change on this file since 2623 was 2623, checked in by Pascal Terjan, 13 years ago
  • No need to reize windows until we now the size of the client
  • Property svn:eol-style set to native
File size: 11.9 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->socket[SOCK_CLIENT])
41        connect_socket(screen_list, SOCK_CLIENT);
42    debug("Sending message (%s) to client on socket %d", msg, screen_list->socket[SOCK_CLIENT]);
43    if(!screen_list->socket[SOCK_CLIENT])
44        ret = -1;
45    else
46        ret = write(screen_list->socket[SOCK_CLIENT], msg, strlen(msg));
47    if(ret < 0 && errno != EAGAIN)
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->socket[SOCK_CLIENT])
87        connect_socket(screen_list, SOCK_CLIENT);
88    if(screen_list->socket[SOCK_CLIENT])
89        if(write(screen_list->socket[SOCK_CLIENT], buf2, bytes+8) <= 0 && errno != EAGAIN)
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->socket[SOCK_CLIENT])
100    {
101        send_to_client("DETACH", screen_list);
102        close(screen_list->socket[SOCK_CLIENT]);
103        screen_list->socket[SOCK_CLIENT] = 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_socket(screen_list, SOCK_SERVER);
119
120    /* Connect to the client */
121    connect_socket(screen_list, SOCK_CLIENT);
122
123    screen_list->width = screen_list->height = 10;
124
125    /* Create main canvas */
126    screen_list->cv = cucul_create_canvas(screen_list->width,
127                                          screen_list->height
128                                          + screen_list->mini*6
129                                          + screen_list->status);
130
131    if(!to_grab && !to_start)
132    {
133        add_screen(screen_list,
134                   create_screen(screen_list->width,
135                                 screen_list->height,
136                                 screen_list->default_shell));
137    }
138
139    /* Attach processes */
140    if(to_grab)
141    {
142        for(i=0; to_grab[i]; i++)
143        {
144            add_screen(screen_list,
145                       create_screen_grab(screen_list->width,
146                                          screen_list->height,
147                                          to_grab[i]));
148        }
149        free(to_grab);
150    }
151
152    /* Launch command line processes */
153    if(to_start)
154    {
155        for(i=0; to_start[i]; i++)
156        {
157            add_screen(screen_list,
158                       create_screen(screen_list->width,
159                                     screen_list->height,
160                                     to_start[i]));
161        }
162        free(to_start);
163    }
164
165    last_key_time = get_us();
166
167    for(;;)
168    {
169        int quit = 0;
170        ssize_t n;
171        char buf[4097];
172
173        /* Read program output */
174        refresh |= update_screens_contents(screen_list);
175
176        /* Check if we got something from the client */
177        while (screen_list->socket[SOCK_SERVER] && (n = read(screen_list->socket[SOCK_SERVER], buf, sizeof(buf)-1)) > 0)
178        {
179            buf[n] = 0;
180            debug("Received command %s", buf);
181            if(!strncmp("ATTACH ", buf, 7))
182            {
183                screen_list->attached = 1;
184                cucul_free_canvas(screen_list->cv);
185                screen_list->cv = cucul_create_canvas(atoi(buf+7), atoi(buf+18));
186                screen_list->width  = cucul_get_canvas_width(screen_list->cv);
187                screen_list->height = cucul_get_canvas_height(screen_list->cv) - ((screen_list->mini*6) + (screen_list->status));
188                update_windows_props(screen_list);
189                cucul_clear_canvas(screen_list->cv);
190                refresh = 1;
191            }
192            else if(!strncmp("QUIT", buf, 4))
193            {
194                quit = 1;
195            }
196            else if(!strncmp("RESIZE ", buf, 7))
197            {
198                cucul_free_canvas(screen_list->cv);
199                screen_list->cv = cucul_create_canvas(atoi(buf+7), atoi(buf+18));
200                screen_list->width  = cucul_get_canvas_width(screen_list->cv);
201                screen_list->height = cucul_get_canvas_height(screen_list->cv) - ((screen_list->mini*6) + (screen_list->status));
202                update_windows_props(screen_list);
203                cucul_clear_canvas(screen_list->cv);
204                refresh = 1;
205            }
206            else if(!strncmp("KEY ", buf, 4))
207            {
208                unsigned int c = atoi(buf+4);
209                char *str = NULL;
210                int size = 0;
211                /* CTRL-A has been pressed before, handle this as a
212                 * command, except that CTRL-A a sends literal CTRL-A */
213                if(command && (c != 'a'))
214                {
215                    command = 0;
216                    refresh |= handle_command_input(screen_list, c);
217                }
218                else
219                {
220                    /* Not in command mode */
221                    last_key_time = get_us();
222                    set_cursor(1, screen_list);
223
224                    /* Kill screensaver */
225                    if(screen_list->in_screensaver)
226                    {
227                        screensaver_kill(screen_list);
228                        screen_list->in_screensaver = 0;
229                        refresh = 1;
230                        continue;
231                    }
232                    /* Handle lock window */
233                    if(screen_list->locked)
234                        refresh |= update_lock(c, screen_list);
235                    else
236                    {
237                        switch(c)
238                        {
239                        case 0x01: //CACA_KEY_CTRL_A:
240                            command = 1; break;
241                        case CACA_KEY_ESCAPE:
242                            if(screen_list->help)
243                            {
244                                screen_list->help = 0;
245                                refresh = 1;
246                                break;
247                            }
248                        default:
249                            /* CTRL-A a sends literal CTRL-A */
250                            if (command && (c == 'a'))
251                            {
252                                c = 0x01;
253                            }
254                            /* Normal key, convert it if needed */
255                            str = convert_input_ansi(&c, &size);
256                            write(screen_list->screen[screen_list->pty]->fd, str, size);
257                            break;
258                        }
259                    }
260                }
261            }
262            else
263            {
264                fprintf(stderr, "Unknown command received: %s\n", buf);
265            }
266        }
267
268        /* No more screens, exit */
269        if(!screen_list->count) break;
270
271        /* User requested to exit */
272        if(quit) break;
273
274        /* Update each screen canvas  */
275        refresh |= update_terms(screen_list);
276
277        /* Launch reccurents if any */
278        refresh |= handle_recurrents(screen_list);
279
280        /* Resfresh screen */
281        if(!screen_list->attached)
282        {
283            /* No need to refresh
284             * Don't use the CPU too much
285             * Would be better to select on terms + socket
286             */
287            sleep(1);
288        }
289        /* Draw lock window */
290        else if(screen_list->locked)
291        {
292            draw_lock(screen_list);
293            refresh = 1;
294        }
295        else
296        {
297            if((refresh || screen_list->in_bell) &&
298               (get_us() - last_key_time < screen_list->screensaver_timeout))
299            {
300                refresh_screens(screen_list);
301                if(screen_list->attached)
302                {
303                    if(screen_list->pty < screen_list->count &&
304                       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->socket_path[SOCK_SERVER])
358    {
359        unlink(screen_list->socket_path[SOCK_SERVER]);
360        free(screen_list->socket_path[SOCK_SERVER]);
361    }
362
363    if(screen_list->socket_path[SOCK_CLIENT])
364        free(screen_list->socket_path[SOCK_CLIENT]);
365
366    if(screen_list->socket[SOCK_SERVER])
367        close(screen_list->socket[SOCK_SERVER]);
368
369    if(screen_list->socket[SOCK_CLIENT])
370        close(screen_list->socket[SOCK_CLIENT]);
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.