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

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