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

Last change on this file since 2588 was 2588, checked in by Pascal Terjan, 12 years ago
  • Rewrote detach handling, enjoy silent neercs
  • Property svn:eol-style set to native
File size: 9.8 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, int sock)
38{
39    if(strcmp(msg, "REFRESH"))
40        debug("Sending message (%s) to client on socket %d", msg, sock);
41    return 0;
42}
43
44static int set_title(const char * title, int sock)
45{
46    char buf[1024];
47    int bytes;
48
49    bytes = snprintf(buf, sizeof(buf)-1, "TITLE %s", title);
50    buf[bytes] = '\0';
51
52    return send_to_client(buf, sock);
53}
54
55static int set_cursor(int state, int sock)
56{
57    char buf[16];
58    int bytes;
59
60    bytes = snprintf(buf, sizeof(buf)-1, "CURSOR %d", state);
61    buf[bytes] = '\0';
62
63    return send_to_client(buf, sock);
64}
65
66static int request_refresh(int sock)
67{
68    return send_to_client("REFRESH", sock);
69}
70
71int detach(struct screen_list* screen_list)
72{
73    screen_list->attached = 0;
74    return send_to_client("DETACH", screen_list->socket);
75}
76
77int server_main(int *to_grab, char **to_start, struct screen_list *screen_list)
78{
79    int i;
80    int eof = 0, refresh = 1, command = 0;
81    long long unsigned int last_key_time = 0;
82    int mainret = 0;
83
84    screen_list->attached = 0;
85
86    /* Create socket and bind it */
87    create_socket(screen_list);
88
89    screen_list->width = screen_list->height = 10;
90
91    /* Create main canvas */
92    screen_list->cv = cucul_create_canvas(screen_list->width,
93                                          screen_list->height
94                                          + screen_list->mini*6
95                                          + screen_list->status);
96
97    if(!to_grab && !to_start)
98    {
99        add_screen(screen_list,
100                   create_screen(screen_list->width,
101                                 screen_list->height,
102                                 screen_list->default_shell));
103    }
104
105    /* Attach processes */
106    if(to_grab)
107    {
108        for(i=0; to_grab[i]; i++)
109        {
110            add_screen(screen_list,
111                       create_screen_grab(screen_list->width,
112                                          screen_list->height,
113                                          to_grab[i]));
114        }
115        free(to_grab);
116    }
117
118    /* Launch command line processes */
119    if(to_start)
120    {
121        for(i=0; to_start[i]; i++)
122        {
123            add_screen(screen_list,
124                       create_screen(screen_list->width,
125                                     screen_list->height,
126                                     to_start[i]));
127        }
128        free(to_start);
129    }
130
131    /* Windows are in a temporary state, resize them to the right dimensions */
132    update_windows_props(screen_list);/* FIXME after attach */
133
134    last_key_time = get_us();
135
136    for(;;)
137    {
138        caca_event_t ev;
139        int ret = 0;
140        int quit = 0;
141        ssize_t n;
142        char buf[4097];
143
144        /* Read program output */
145        refresh |= update_screens_contents(screen_list);
146
147        /* Check if we got something from the client */
148        while (screen_list->socket && (n = read(screen_list->socket, buf, sizeof(buf)-1)) > 0)
149        {
150            buf[n] = 0;
151            debug("Received command %s", buf);
152            if(!strncmp("ATTACH", buf, 7))
153            {
154                screen_list->attached = 1;
155                refresh = 1;
156            }
157            else if(!strncmp("QUIT", buf, 4))
158            {
159                quit = 1;
160            }
161            else if(!strncmp("RESIZE", buf, 6))
162            {
163                update_windows_props(screen_list);
164                cucul_clear_canvas(screen_list->cv);
165                refresh = 1;
166            }
167            else if(!strncmp("KEY ", buf, 4))
168            {
169                unsigned int c = atoi(buf+4);
170                char *str = NULL;
171                int size = 0;
172                /* CTRL-A has been pressed before, handle this as a
173                 * command, except that CTRL-A a sends literal CTRL-A */
174                if(command && (c != 'a'))
175                {
176                    command = 0;
177                    refresh |= handle_command_input(screen_list, c);
178                }
179                else
180                {
181                    /* Not in command mode */
182                    last_key_time = get_us();
183                    set_cursor(1, screen_list->socket);
184
185                    /* Kill screensaver */
186                    if(screen_list->in_screensaver)
187                    {
188                        screensaver_kill(screen_list);
189                        screen_list->in_screensaver = 0;
190                        refresh = 1;
191                        continue;
192                    }
193                    /* Handle lock window */
194                    if(screen_list->locked)
195                        refresh |= update_lock(c, screen_list);
196                    else
197                    {
198                        switch(c)
199                        {
200                        case 0x01: //CACA_KEY_CTRL_A:
201                            command = 1; break;
202                        case CACA_KEY_ESCAPE:
203                            if(screen_list->help)
204                            {
205                                screen_list->help = 0;
206                                refresh = 1;
207                                break;
208                            }
209                        default:
210                            /* CTRL-A a sends literal CTRL-A */
211                            if (command && (c == 'a'))
212                            {
213                                c = 0x01;
214                            }
215                            /* Normal key, convert it if needed */
216                            str = convert_input_ansi(&c, &size);
217                            write(screen_list->screen[screen_list->pty]->fd, str, size);
218                            break;
219                        }
220                    }
221                }
222            }
223            else
224            {
225                fprintf(stderr, "Unknown command received: %s\n", buf);
226            }
227        }
228
229        /* No more screens, exit */
230        if(!screen_list->count) break;
231
232        /* User requested to exit */
233        if(quit) break;
234
235        /* Update each screen canvas  */
236        refresh |= update_terms(screen_list);
237
238        /* Launch reccurents if any */
239        refresh |= handle_recurrents(screen_list);
240
241        /* Resfresh screen */
242        if(!screen_list->attached)
243        {
244            /* No need to refresh
245             * Don't use the CPU too much
246             * Would be better to select on terms + socket
247             */
248            sleep(1);
249        }
250        /* Draw lock window */
251        else if(screen_list->locked)
252        {
253            draw_lock(screen_list);
254            refresh = 1;
255        }
256        else
257        {
258            if((refresh || screen_list->in_bell) &&
259               (get_us() - last_key_time < screen_list->screensaver_timeout))
260            {
261                refresh_screens(screen_list);
262                if(screen_list->attached)
263                    if(screen_list->screen[screen_list->pty]->title)
264                        set_title(screen_list->screen[screen_list->pty]->title, screen_list->socket);
265                    else
266                        set_title(PACKAGE_STRING, screen_list->socket);
267                refresh = 1;
268
269            }
270            if((get_us() - last_key_time > screen_list->screensaver_timeout))
271            {
272                if(!screen_list->in_screensaver)
273                {
274                    screensaver_init(screen_list);
275                    screen_list->in_screensaver = 1;
276                    set_cursor(0, screen_list->socket);
277                }
278                draw_screensaver(screen_list);
279                refresh = 1;
280            }
281
282            if((get_us() - last_key_time > screen_list->autolock_timeout))
283            {
284                screen_list->locked = 1;
285                refresh = 1;
286            }
287
288        }
289
290        if(refresh)
291        {
292            if(screen_list->attached)
293                request_refresh(screen_list->socket);
294            refresh = 0;
295        }
296
297        eof = 1;
298        for(i=0; i < screen_list->count; i++)
299            if(screen_list->screen[i]->fd >= 0)
300                eof = 0;
301        if(eof)
302            break;
303    }
304
305    detach(screen_list);
306
307    /* Clean up */
308    cucul_free_canvas(screen_list->cv);
309
310    for(i = 0; i < screen_list->count; i++)
311    {
312        destroy_screen(screen_list->screen[i]);
313    }
314
315    if(screen_list->socket_path) {
316        unlink(screen_list->socket_path);
317        free(screen_list->socket_path);
318    }
319
320    if(screen_list->socket)
321        close(screen_list->socket);
322
323    if(screen_list->screen) free(screen_list->screen);
324
325    for(i=0; i<screen_list->recurrent_list->count; i++)
326    {
327        remove_recurrent(screen_list->recurrent_list, i);
328        i = 0;
329    }
330
331    if(screen_list->recurrent_list->recurrent) free(screen_list->recurrent_list->recurrent);
332    if(screen_list->recurrent_list)            free(screen_list->recurrent_list);
333
334    if(screen_list->session_name)
335        free(screen_list->session_name);
336
337    if(screen_list)
338        free(screen_list);
339
340    return mainret;
341}
342
343long long get_us(void)
344{
345    struct timeval tv;
346    gettimeofday(&tv, NULL);
347    return (tv.tv_sec*(1000000) + tv.tv_usec);
348}
Note: See TracBrowser for help on using the repository browser.