source: neercs/trunk/src/main.c @ 2458

Last change on this file since 2458 was 2458, checked in by Pascal Terjan, 13 years ago
  • Support detaching (NOT ATTACHING)
  • Property svn:keywords set to Id
File size: 14.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 *                All Rights Reserved
6 *
7 *  $Id: main.c 2458 2008-06-19 21:50:29Z pterjan $
8 *
9 *  This program is free software. It comes without any warranty, to
10 *  the extent permitted by applicable law. You can redistribute it
11 *  and/or modify it under the terms of the Do What The Fuck You Want
12 *  To Public License, Version 2, as published by Sam Hocevar. See
13 *  http://sam.zoy.org/wtfpl/COPYING for more details.
14 */
15
16#include "config.h"
17
18#include <stdio.h>
19#include <string.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <signal.h>
24#include <sys/ioctl.h>
25#include <sys/types.h>
26#include <sys/wait.h>
27#include <sys/time.h>
28#include <time.h>
29
30#if defined HAVE_PTY_H
31#   include <pty.h>  /* for openpty and forkpty */
32#else
33#   include <util.h> /* for OS X */
34#endif
35#if !defined HAVE_GETOPT_LONG
36#   include "mygetopt.h"
37#elif defined HAVE_GETOPT_H
38#   include <getopt.h>
39#endif
40#if defined HAVE_GETOPT_LONG
41#   define mygetopt getopt_long
42#   define myoptind optind
43#   define myoptarg optarg
44#   define myoption option
45#endif
46#include <errno.h>
47#include <cucul.h>
48#include <caca.h>
49
50#include "neercs.h"
51
52
53void version(void)
54{
55    printf("%s\n", PACKAGE_STRING);
56    printf("Copyright (C) 2006, 2008 Sam Hocevar <sam@zoy.org>\n");
57    printf("                         Jean-Yves Lamoureux <jylam@lnxscene.org>\n\n");
58    printf("This is free software.  You may redistribute copies of it under the\n");
59    printf("terms of the Do What The Fuck You Want To Public License, Version 2\n");
60    printf("<http://sam.zoy.org/wtfpl/>.\n");
61    printf("There is NO WARRANTY, to the extent permitted by law.\n");
62    printf("\n");
63    printf("For more informations, visit http://libcaca.zoy.org/wiki/neercs\n");
64}
65
66
67int main(int argc, char **argv)
68{
69    static cucul_canvas_t *cv;
70    static caca_display_t *dp;
71    struct screen_list *screen_list = NULL;
72    struct recurrent_list *recurrent_list = NULL;
73    char *default_shell = NULL;
74    int i, w, h, args, s=0;
75    int eof = 0, refresh = 1, command = 0;
76    long long unsigned int last_key_time = 0;
77    int lock_offset = 0;
78
79    default_shell = getenv("SHELL");
80
81    args = argc -1;
82    if(default_shell == NULL  && args <= 0)
83    {
84        fprintf(stderr, "Environment variable SHELL not set and no arguments given. kthxbye.\n");
85        return -1;
86    }
87
88    if(args==0)
89        args = 1;
90
91    /* Create main canvas and associated caca window */
92    cv = cucul_create_canvas(0, 0);
93    dp = caca_create_display(cv);
94    if(!dp)
95        return 1;
96    caca_set_cursor(dp, 1);
97
98    w = cucul_get_canvas_width(cv);
99    h = cucul_get_canvas_height(cv);
100
101
102    /* Create screen list */
103    screen_list = (struct screen_list*)     malloc(sizeof(struct screen_list));
104    if(!screen_list)
105    {
106        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
107        return -1;
108    }
109    screen_list->screen = (struct screen**) malloc(sizeof(sizeof(struct screen*)));
110    if(!screen_list->screen)
111    {
112        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
113        return -1;
114    }
115    screen_list->count = 0;
116    screen_list->width  = cucul_get_canvas_width(cv);
117    screen_list->mini = 1;
118    screen_list->help = 0;
119    screen_list->status = 1;
120    screen_list->height = cucul_get_canvas_height(cv) - ((screen_list->mini*6) + (screen_list->status));
121    screen_list->wm_type = WM_VSPLIT;
122    screen_list->in_bell = 0;
123    screen_list->pty = screen_list->prevpty = 0;
124    screen_list->dont_update_coords = 0;
125    screen_list->screensaver_timeout = (60) * 1000000;
126    screen_list->screensaver_data = NULL;
127    screen_list->in_screensaver = 0;
128    screen_list->locked = 0;
129    screen_list->attached = 1;
130    memset(screen_list->lockmsg, 0, 1024);
131    memset(screen_list->lockpass, 0, 1024);
132
133    recurrent_list = (struct recurrent_list*) malloc(sizeof(struct recurrent_list));
134    recurrent_list->recurrent = (struct recurrent**) malloc(sizeof(struct recurrent*));
135    if(!recurrent_list->recurrent)
136    {
137        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
138        return -1;
139    }
140    recurrent_list->count = 0;
141
142    for(;;)
143    {
144        int option_index = 0;
145        static struct myoption long_options[] =
146        {
147#if defined USE_GRAB
148            { "pid",         1, NULL, 'P' },
149#endif
150            { "help",        0, NULL, 'h' },
151            { "version",     0, NULL, 'v' },
152        };
153#if defined USE_GRAB
154        int c = mygetopt(argc, argv, "P:hv", long_options, &option_index);
155#else
156        int c = mygetopt(argc, argv, "hv", long_options, &option_index);
157#endif
158        if(c == -1)
159            break;
160
161        switch(c)
162        {
163        case 'P': /* --pid */
164            add_screen(screen_list,create_screen_grab(w, h, atoi(myoptarg)));
165            s+=2;
166            break;
167        case 'h': /* --help */
168            //   usage(argc, argv);
169            return 0;
170            break;
171        case 'v': /* --version */
172            version();
173            goto end;
174            break;
175        default:
176            fprintf(stderr, "Unknow argument #%d\n", myoptind);
177            return -1;
178            break;
179        }
180    }
181
182
183    if(s == 0 && argc<2)
184    {
185        add_screen(screen_list, create_screen(w, h, default_shell));
186    }
187
188    /* Launch command line processes */
189    for(i=0; i<(argc-1) - s; i++)
190    {
191        add_screen(screen_list, create_screen(w, h, argv[i+s+1]));
192    }
193
194
195    /* Windows are in a temporary state, resize them to the right dimensions */
196    update_windows_props(cv, screen_list);
197
198    last_key_time = get_ms();
199
200    /* Refresh */
201    caca_refresh_display(dp);
202
203    for(;;)
204    {
205        caca_event_t ev;
206        int ret = 0;
207
208        refresh |= update_screens_contents(screen_list);
209
210        /* No more screens, exit */
211        if(!screen_list->count) break;
212
213        /* Update each screen canvas  */
214        refresh |= update_terms(screen_list);
215
216        /* Get events, if any */
217        if(screen_list->attached)
218            ret = caca_get_event(dp, CACA_EVENT_ANY, &ev, 0);
219        else
220            sleep(1);
221
222        if(ret && (caca_get_event_type(&ev) & CACA_EVENT_KEY_PRESS))
223        {
224            unsigned int c = caca_get_event_key_ch(&ev);
225            if(command)
226            {
227                command = 0;
228
229                switch(c)
230                {
231                case 0x01: //CACA_KEY_CTRL_A:
232                    screen_list->pty ^= screen_list->prevpty;
233                    screen_list->prevpty ^= screen_list->pty;
234                    screen_list->pty ^= screen_list->prevpty;
235                    refresh = 1;
236                    break;
237                case 'm':
238                case 0x0d: //CACA_KEY_CTRL_M:
239                    screen_list->mini = !screen_list->mini;
240                    refresh = 1;
241                    break;
242                case 'n':
243                case ' ':
244                case '\0':
245                case 0x0e: //CACA_KEY_CTRL_N:
246                    screen_list->prevpty = screen_list->pty;
247                    screen_list->pty = (screen_list->pty + 1) % screen_list->count;
248                    refresh = 1;
249                    break;
250                case 'p':
251                case 0x10: //CACA_KEY_CTRL_P:
252                    screen_list->prevpty = screen_list->pty;
253                    screen_list->pty = (screen_list->pty + screen_list->count - 1) % screen_list->count;
254                    refresh = 1;
255                    break;
256                case 'c':
257                case 0x03: //CACA_KEY_CTRL_C:
258                    screen_list->prevpty = screen_list->pty;
259                    screen_list->pty =
260                        add_screen(screen_list, create_screen(w, h, default_shell));
261                    refresh = 1;
262                    break;
263                case 'w':
264                case 0x17: //CACA_KEY_CTRL_W:
265                    screen_list->wm_type = (screen_list->wm_type==(WM_MAX-1)?
266                                            screen_list->wm_type=0:
267                                            screen_list->wm_type+1);
268                    refresh = 1;
269                    break;
270                case 0x0b: //CACA_KEY_CTRL_K:
271                    add_recurrent(recurrent_list, close_screen_recurrent, cv);
272                    refresh = 1;
273                    break;
274                case 'x':
275                case 0x18: //CACA_KEY_CTRL_X:
276                    memset(screen_list->lockpass, 0, 1024);
277                    screen_list->locked = 1;
278                    lock_offset = 0;
279                    refresh = 1;
280                    break;
281                case 'h':
282                case 0x08: //CACA_KEY_CTRL_H:
283                    screen_list->help = !screen_list->help;
284                    refresh = 1;
285                    break;
286                case 'd':
287                case 0x04: //CACA_KEY_CTRL_D:
288                    detach(screen_list, dp);
289                    break;
290                }
291            }
292            else
293            {
294
295                last_key_time = get_ms();
296                caca_set_cursor(dp, 1);
297
298                if(screen_list->in_screensaver)
299                {
300                    screensaver_kill(cv, dp, screen_list);
301                    screen_list->in_screensaver = 0;
302                    refresh = 1;
303                    continue;
304                }
305                else if(screen_list->locked)
306                {
307                    if(c==0x08)
308                    {
309                        if(lock_offset)
310                        {
311                            screen_list->lockpass[lock_offset-1] = 0;
312                            lock_offset--;
313                        }
314                    }
315                    else if(c==0x0d) // RETURN
316                    {
317                        memset(screen_list->lockmsg, 0, 1024);
318                        if(validate_lock(screen_list, getenv("USER"), screen_list->lockpass))
319                        {
320                            memset(screen_list->lockpass, 0, 1024);
321                            screen_list->locked = 0;
322                            lock_offset = 0;
323                            refresh = 1;
324                        }
325                        else
326                        {
327                            memset(screen_list->lockpass, 0, 1024);
328                            lock_offset = 0;
329                            refresh = 1;
330                        }
331                    }
332                    else
333                    {
334                        if(lock_offset < 1023)
335                        {
336                            screen_list->lockpass[lock_offset++] = c;
337                            screen_list->lockpass[lock_offset]   = 0;
338                        }
339                    }
340                }
341                else
342                {
343                    switch(c)
344                    {
345                    case 0x01: //CACA_KEY_CTRL_A:
346                        command = 1; break;
347                    case CACA_KEY_UP:
348                        write(screen_list->screen[screen_list->pty]->fd, "\x1b[A", 3); break;
349                    case CACA_KEY_DOWN:
350                        write(screen_list->screen[screen_list->pty]->fd, "\x1b[B", 3); break;
351                    case CACA_KEY_RIGHT:
352                        write(screen_list->screen[screen_list->pty]->fd, "\x1b[C", 3); break;
353                    case CACA_KEY_LEFT:
354                        write(screen_list->screen[screen_list->pty]->fd, "\x1b[D", 3); break;
355                    case CACA_KEY_ESCAPE:
356                        if(screen_list->help)
357                        {
358                            screen_list->help = 0;
359                            refresh = 1;
360                            break;
361                        }
362                    default:
363                        write(screen_list->screen[screen_list->pty]->fd, &c, 1); break;
364                    }
365                }
366            }
367        }
368        else if(ret && (caca_get_event_type(&ev) & CACA_EVENT_RESIZE))
369        {
370            update_windows_props(cv, screen_list);
371            cucul_clear_canvas(cv);
372            refresh = 1;
373        }
374        else if(ret && (caca_get_event_type(&ev) & CACA_EVENT_QUIT))
375        {
376            break;
377        }
378
379        /* Recurrent functions */
380        for(i=0; i<recurrent_list->count; i++)
381        {
382            if(recurrent_list->recurrent[i]->function)
383            {
384                refresh |= recurrent_list->recurrent[i]->function(screen_list,
385                                                                  recurrent_list->recurrent[i],
386                                                                  recurrent_list->recurrent[i]->user,
387                                                                  get_ms());
388            }
389        }
390       /* Delete recurrent functions */
391        for(i=0; i<recurrent_list->count; i++)
392        {
393            if(recurrent_list->recurrent[i]->kill_me)
394            {
395                remove_recurrent(recurrent_list, i);
396                i = 0;
397            }
398        }
399
400        /* Resfresh screen */
401
402        if(!screen_list->attached)
403        {
404            /* No need to refresh */
405        }
406        else if(screen_list->locked)
407        {
408            draw_lock(cv, screen_list);
409            caca_refresh_display(dp);
410        }
411        else
412        {
413
414            if((refresh || screen_list->in_bell) &&
415               (get_ms() - last_key_time < screen_list->screensaver_timeout))
416            {
417                refresh = 0;
418                refresh_screens(cv, dp, screen_list);
419            }
420
421            if((get_ms() - last_key_time > screen_list->screensaver_timeout))
422            {
423                if(!screen_list->in_screensaver)
424                    screensaver_init(cv, dp, screen_list);
425                screen_list->in_screensaver = 1;
426
427                caca_set_cursor(dp, 0);
428                draw_screensaver(cv, dp, screen_list);
429                caca_refresh_display(dp);
430            }
431        }
432
433        eof = 1;
434        for(i=0; i < screen_list->count; i++)
435            if(screen_list->screen[i]->fd >= 0)
436                eof = 0;
437        if(eof)
438            break;
439    }
440
441end:
442    /* Clean up */
443    caca_free_display(dp);
444    cucul_free_canvas(cv);
445    for(i = 0; i < screen_list->count; i++)
446    {
447        destroy_screen(screen_list->screen[i]);
448    }
449
450    free(screen_list->screen);
451    free(screen_list);
452
453
454    for(i=0; i<recurrent_list->count; i++)
455    {
456        remove_recurrent(recurrent_list, i);
457        i = 0;
458    }
459
460    free(recurrent_list->recurrent);
461    free(recurrent_list);
462
463
464    return 0;
465}
466
467
468
469long long get_ms(void)
470{
471    struct timeval tv;
472    gettimeofday(&tv, NULL);
473
474
475    return (tv.tv_sec*(1000000) + tv.tv_usec);
476}
Note: See TracBrowser for help on using the repository browser.