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

Last change on this file since 2622 was 2622, checked in by pterjan, 6 years ago
  • Don't use free'd title during the final animation
  • Property svn:eol-style set to native
File size: 12.1 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    /* Windows are in a temporary state, resize them to the right dimensions */
166    update_windows_props(screen_list);/* FIXME after attach */
167
168    last_key_time = get_us();
169
170    for(;;)
171    {
172        int quit = 0;
173        ssize_t n;
174        char buf[4097];
175
176        /* Read program output */
177        refresh |= update_screens_contents(screen_list);
178
179        /* Check if we got something from the client */
180        while (screen_list->socket[SOCK_SERVER] && (n = read(screen_list->socket[SOCK_SERVER], buf, sizeof(buf)-1)) > 0)
181        {
182            buf[n] = 0;
183            debug("Received command %s", buf);
184            if(!strncmp("ATTACH ", buf, 7))
185            {
186                screen_list->attached = 1;
187                cucul_free_canvas(screen_list->cv);
188                screen_list->cv = cucul_create_canvas(atoi(buf+7), atoi(buf+18));
189                screen_list->width  = cucul_get_canvas_width(screen_list->cv);
190                screen_list->height = cucul_get_canvas_height(screen_list->cv) - ((screen_list->mini*6) + (screen_list->status));
191                update_windows_props(screen_list);
192                cucul_clear_canvas(screen_list->cv);
193                refresh = 1;
194            }
195            else if(!strncmp("QUIT", buf, 4))
196            {
197                quit = 1;
198            }
199            else if(!strncmp("RESIZE ", buf, 7))
200            {
201                cucul_free_canvas(screen_list->cv);
202                screen_list->cv = cucul_create_canvas(atoi(buf+7), atoi(buf+18));
203                screen_list->width  = cucul_get_canvas_width(screen_list->cv);
204                screen_list->height = cucul_get_canvas_height(screen_list->cv) - ((screen_list->mini*6) + (screen_list->status));
205                update_windows_props(screen_list);
206                cucul_clear_canvas(screen_list->cv);
207                refresh = 1;
208            }
209            else if(!strncmp("KEY ", buf, 4))
210            {
211                unsigned int c = atoi(buf+4);
212                char *str = NULL;
213                int size = 0;
214                /* CTRL-A has been pressed before, handle this as a
215                 * command, except that CTRL-A a sends literal CTRL-A */
216                if(command && (c != 'a'))
217                {
218                    command = 0;
219                    refresh |= handle_command_input(screen_list, c);
220                }
221                else
222                {
223                    /* Not in command mode */
224                    last_key_time = get_us();
225                    set_cursor(1, screen_list);
226
227                    /* Kill screensaver */
228                    if(screen_list->in_screensaver)
229                    {
230                        screensaver_kill(screen_list);
231                        screen_list->in_screensaver = 0;
232                        refresh = 1;
233                        continue;
234                    }
235                    /* Handle lock window */
236                    if(screen_list->locked)
237                        refresh |= update_lock(c, screen_list);
238                    else
239                    {
240                        switch(c)
241                        {
242                        case 0x01: //CACA_KEY_CTRL_A:
243                            command = 1; break;
244                        case CACA_KEY_ESCAPE:
245                            if(screen_list->help)
246                            {
247                                screen_list->help = 0;
248                                refresh = 1;
249                                break;
250                            }
251                        default:
252                            /* CTRL-A a sends literal CTRL-A */
253                            if (command && (c == 'a'))
254                            {
255                                c = 0x01;
256                            }
257                            /* Normal key, convert it if needed */
258                            str = convert_input_ansi(&c, &size);
259                            write(screen_list->screen[screen_list->pty]->fd, str, size);
260                            break;
261                        }
262                    }
263                }
264            }
265            else
266            {
267                fprintf(stderr, "Unknown command received: %s\n", buf);
268            }
269        }
270
271        /* No more screens, exit */
272        if(!screen_list->count) break;
273
274        /* User requested to exit */
275        if(quit) break;
276
277        /* Update each screen canvas  */
278        refresh |= update_terms(screen_list);
279
280        /* Launch reccurents if any */
281        refresh |= handle_recurrents(screen_list);
282
283        /* Resfresh screen */
284        if(!screen_list->attached)
285        {
286            /* No need to refresh
287             * Don't use the CPU too much
288             * Would be better to select on terms + socket
289             */
290            sleep(1);
291        }
292        /* Draw lock window */
293        else if(screen_list->locked)
294        {
295            draw_lock(screen_list);
296            refresh = 1;
297        }
298        else
299        {
300            if((refresh || screen_list->in_bell) &&
301               (get_us() - last_key_time < screen_list->screensaver_timeout))
302            {
303                refresh_screens(screen_list);
304                if(screen_list->attached)
305                {
306                    if(screen_list->pty < screen_list->count &&
307                       screen_list->screen[screen_list->pty]->title)
308                        set_title(screen_list->screen[screen_list->pty]->title, screen_list);
309                    else
310                        set_title(PACKAGE_STRING, screen_list);
311                }
312                refresh = 1;
313
314            }
315            if((get_us() - last_key_time > screen_list->screensaver_timeout))
316            {
317                if(!screen_list->in_screensaver)
318                {
319                    screensaver_init(screen_list);
320                    screen_list->in_screensaver = 1;
321                    set_cursor(0, screen_list);
322                }
323                draw_screensaver(screen_list);
324                refresh = 1;
325            }
326
327            if((get_us() - last_key_time > screen_list->autolock_timeout))
328            {
329                screen_list->locked = 1;
330                refresh = 1;
331            }
332
333        }
334
335        if(refresh)
336        {
337            if(screen_list->attached)
338                request_refresh(screen_list);
339            refresh = 0;
340        }
341
342        eof = 1;
343        for(i=0; i < screen_list->count; i++)
344            if(screen_list->screen[i]->fd >= 0)
345                eof = 0;
346        if(eof)
347            break;
348    }
349
350    detach(screen_list);
351
352    /* Clean up */
353    cucul_free_canvas(screen_list->cv);
354
355    for(i = 0; i < screen_list->count; i++)
356    {
357        destroy_screen(screen_list->screen[i]);
358    }
359
360    if(screen_list->socket_path[SOCK_SERVER])
361    {
362        unlink(screen_list->socket_path[SOCK_SERVER]);
363        free(screen_list->socket_path[SOCK_SERVER]);
364    }
365
366    if(screen_list->socket_path[SOCK_CLIENT])
367        free(screen_list->socket_path[SOCK_CLIENT]);
368
369    if(screen_list->socket[SOCK_SERVER])
370        close(screen_list->socket[SOCK_SERVER]);
371
372    if(screen_list->socket[SOCK_CLIENT])
373        close(screen_list->socket[SOCK_CLIENT]);
374
375    if(screen_list->screen) free(screen_list->screen);
376
377    for(i=0; i<screen_list->recurrent_list->count; i++)
378    {
379        remove_recurrent(screen_list->recurrent_list, i);
380        i = 0;
381    }
382
383    if(screen_list->recurrent_list->recurrent) free(screen_list->recurrent_list->recurrent);
384    if(screen_list->recurrent_list)            free(screen_list->recurrent_list);
385
386    if(screen_list->session_name)
387        free(screen_list->session_name);
388
389    if(screen_list)
390        free(screen_list);
391
392    return mainret;
393}
394
395long long get_us(void)
396{
397    struct timeval tv;
398    gettimeofday(&tv, NULL);
399    return (tv.tv_sec*(1000000) + tv.tv_usec);
400}
Note: See TracBrowser for help on using the repository browser.