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

Last change on this file since 2464 was 2464, checked in by Jean-Yves Lamoureux, 12 years ago
  • Last configuration file line was not handled
  • Added 'screensaver_timeout' to configuration file
  • Property svn:keywords set to Id
File size: 15.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 *                All Rights Reserved
6 *
7 *  $Id: main.c 2464 2008-06-20 12:09:15Z jylam $
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
80    default_shell = getenv("SHELL");
81
82    args = argc -1;
83    if(default_shell == NULL  && args <= 0)
84    {
85        fprintf(stderr, "Environment variable SHELL not set and no arguments given. kthxbye.\n");
86        return -1;
87    }
88
89    if(args==0)
90        args = 1;
91
92    /* Create main canvas and associated caca window */
93    cv = cucul_create_canvas(0, 0);
94    dp = caca_create_display(cv);
95    if(!dp)
96        return 1;
97    caca_set_cursor(dp, 1);
98
99    w = cucul_get_canvas_width(cv);
100    h = cucul_get_canvas_height(cv);
101
102
103    /* Create screen list */
104    screen_list = (struct screen_list*)     malloc(sizeof(struct screen_list));
105    if(!screen_list)
106    {
107        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
108        return -1;
109    }
110    screen_list->screen = (struct screen**) malloc(sizeof(sizeof(struct screen*)));
111    if(!screen_list->screen)
112    {
113        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
114        return -1;
115    }
116
117
118    screen_list->count = 0;
119    screen_list->width  = cucul_get_canvas_width(cv);
120    screen_list->mini = 1;
121    screen_list->help = 0;
122    screen_list->status = 1;
123    screen_list->height = cucul_get_canvas_height(cv) - ((screen_list->mini*6) + (screen_list->status));
124    screen_list->wm_type = WM_VSPLIT;
125    screen_list->in_bell = 0;
126    screen_list->pty = screen_list->prevpty = 0;
127    screen_list->dont_update_coords = 0;
128    screen_list->screensaver_timeout = (60) * 1000000;
129    screen_list->screensaver_data = NULL;
130    screen_list->in_screensaver = 0;
131    screen_list->locked = 0;
132    screen_list->attached = 1;
133    memset(screen_list->lockmsg, 0, 1024);
134    memset(screen_list->lockpass, 0, 1024);
135
136
137    if(!read_configuration_file("neercs.ini", screen_list))
138    {
139
140        if(!read_configuration_file("~/neercs.ini", screen_list))
141        {
142                 if(!read_configuration_file("/etc/neercs.ini", screen_list))
143                 {
144                     printf("Failed to read configuration file\n");
145                 }
146        }
147    }
148
149    recurrent_list = (struct recurrent_list*) malloc(sizeof(struct recurrent_list));
150    recurrent_list->recurrent = (struct recurrent**) malloc(sizeof(struct recurrent*));
151    if(!recurrent_list->recurrent)
152    {
153        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__, __LINE__);
154        return -1;
155    }
156    recurrent_list->count = 0;
157
158    for(;;)
159    {
160        int option_index = 0;
161        static struct myoption long_options[] =
162        {
163#if defined USE_GRAB
164            { "pid",         1, NULL, 'P' },
165#endif
166            { "help",        0, NULL, 'h' },
167            { "version",     0, NULL, 'v' },
168        };
169#if defined USE_GRAB
170        int c = mygetopt(argc, argv, "P:hv", long_options, &option_index);
171#else
172        int c = mygetopt(argc, argv, "hv", long_options, &option_index);
173#endif
174        if(c == -1)
175            break;
176
177        switch(c)
178        {
179        case 'P': /* --pid */
180            add_screen(screen_list,create_screen_grab(w, h, atoi(myoptarg)));
181            s+=2;
182            break;
183        case 'h': /* --help */
184            //   usage(argc, argv);
185            return 0;
186            break;
187        case 'v': /* --version */
188            version();
189            goto end;
190            break;
191        default:
192            fprintf(stderr, "Unknow argument #%d\n", myoptind);
193            return -1;
194            break;
195        }
196    }
197
198
199    if(s == 0 && argc<2)
200    {
201        add_screen(screen_list, create_screen(w, h, default_shell));
202    }
203
204    /* Launch command line processes */
205    for(i=0; i<(argc-1) - s; i++)
206    {
207        add_screen(screen_list, create_screen(w, h, argv[i+s+1]));
208    }
209
210
211    /* Windows are in a temporary state, resize them to the right dimensions */
212    update_windows_props(cv, screen_list);
213
214    last_key_time = get_ms();
215
216    /* Refresh */
217    caca_refresh_display(dp);
218
219    for(;;)
220    {
221        caca_event_t ev;
222        int ret = 0;
223
224        refresh |= update_screens_contents(screen_list);
225
226        /* No more screens, exit */
227        if(!screen_list->count) break;
228
229        /* Update each screen canvas  */
230        refresh |= update_terms(screen_list);
231
232        /* Get events, if any */
233        if(screen_list->attached)
234            ret = caca_get_event(dp, CACA_EVENT_ANY, &ev, 0);
235        else
236            sleep(1);
237
238        if(ret && (caca_get_event_type(&ev) & CACA_EVENT_KEY_PRESS))
239        {
240            unsigned int c = caca_get_event_key_ch(&ev);
241            if(command)
242            {
243                command = 0;
244
245                switch(c)
246                {
247                case 0x01: //CACA_KEY_CTRL_A:
248                    screen_list->pty ^= screen_list->prevpty;
249                    screen_list->prevpty ^= screen_list->pty;
250                    screen_list->pty ^= screen_list->prevpty;
251                    refresh = 1;
252                    break;
253                case 'm':
254                case 0x0d: //CACA_KEY_CTRL_M:
255                    screen_list->mini = !screen_list->mini;
256                    refresh = 1;
257                    break;
258                case 'n':
259                case ' ':
260                case '\0':
261                case 0x0e: //CACA_KEY_CTRL_N:
262                    screen_list->prevpty = screen_list->pty;
263                    screen_list->pty = (screen_list->pty + 1) % screen_list->count;
264                    refresh = 1;
265                    break;
266                case 'p':
267                case 0x10: //CACA_KEY_CTRL_P:
268                    screen_list->prevpty = screen_list->pty;
269                    screen_list->pty = (screen_list->pty + screen_list->count - 1) % screen_list->count;
270                    refresh = 1;
271                    break;
272                case 'c':
273                case 0x03: //CACA_KEY_CTRL_C:
274                    screen_list->prevpty = screen_list->pty;
275                    screen_list->pty =
276                        add_screen(screen_list, create_screen(w, h, default_shell));
277                    refresh = 1;
278                    break;
279                case 'w':
280                case 0x17: //CACA_KEY_CTRL_W:
281                    screen_list->wm_type = (screen_list->wm_type==(WM_MAX-1)?
282                                            screen_list->wm_type=0:
283                                            screen_list->wm_type+1);
284                    refresh = 1;
285                    break;
286                case 0x0b: //CACA_KEY_CTRL_K:
287                    add_recurrent(recurrent_list, close_screen_recurrent, cv);
288                    refresh = 1;
289                    break;
290                case 'x':
291                case 0x18: //CACA_KEY_CTRL_X:
292                    memset(screen_list->lockpass, 0, 1024);
293                    screen_list->locked = 1;
294                    lock_offset = 0;
295                    refresh = 1;
296                    break;
297                case 'h':
298                case 0x08: //CACA_KEY_CTRL_H:
299                    screen_list->help = !screen_list->help;
300                    refresh = 1;
301                    break;
302                case 'd':
303                case 0x04: //CACA_KEY_CTRL_D:
304                    detach(screen_list, dp);
305                    break;
306                }
307            }
308            else
309            {
310
311                last_key_time = get_ms();
312                caca_set_cursor(dp, 1);
313
314                if(screen_list->in_screensaver)
315                {
316                    screensaver_kill(cv, dp, screen_list);
317                    screen_list->in_screensaver = 0;
318                    refresh = 1;
319                    continue;
320                }
321                else if(screen_list->locked)
322                {
323                    if(c==0x08)
324                    {
325                        if(lock_offset)
326                        {
327                            screen_list->lockpass[lock_offset-1] = 0;
328                            lock_offset--;
329                        }
330                    }
331                    else if(c==0x0d) // RETURN
332                    {
333                        memset(screen_list->lockmsg, 0, 1024);
334                        if(validate_lock(screen_list, getenv("USER"), screen_list->lockpass))
335                        {
336                            memset(screen_list->lockpass, 0, 1024);
337                            screen_list->locked = 0;
338                            lock_offset = 0;
339                            refresh = 1;
340                        }
341                        else
342                        {
343                            memset(screen_list->lockpass, 0, 1024);
344                            lock_offset = 0;
345                            refresh = 1;
346                        }
347                    }
348                    else
349                    {
350                        if(lock_offset < 1023)
351                        {
352                            screen_list->lockpass[lock_offset++] = c;
353                            screen_list->lockpass[lock_offset]   = 0;
354                        }
355                    }
356                }
357                else
358                {
359                    switch(c)
360                    {
361                    case 0x01: //CACA_KEY_CTRL_A:
362                        command = 1; break;
363                    case CACA_KEY_UP:
364                        write(screen_list->screen[screen_list->pty]->fd, "\x1b[A", 3); break;
365                    case CACA_KEY_DOWN:
366                        write(screen_list->screen[screen_list->pty]->fd, "\x1b[B", 3); break;
367                    case CACA_KEY_RIGHT:
368                        write(screen_list->screen[screen_list->pty]->fd, "\x1b[C", 3); break;
369                    case CACA_KEY_LEFT:
370                        write(screen_list->screen[screen_list->pty]->fd, "\x1b[D", 3); break;
371                    case CACA_KEY_ESCAPE:
372                        if(screen_list->help)
373                        {
374                            screen_list->help = 0;
375                            refresh = 1;
376                            break;
377                        }
378                    default:
379                        write(screen_list->screen[screen_list->pty]->fd, &c, 1); break;
380                    }
381                }
382            }
383        }
384        else if(ret && (caca_get_event_type(&ev) & CACA_EVENT_RESIZE))
385        {
386            update_windows_props(cv, screen_list);
387            cucul_clear_canvas(cv);
388            refresh = 1;
389        }
390        else if(ret && (caca_get_event_type(&ev) & CACA_EVENT_QUIT))
391        {
392            break;
393        }
394
395        /* Recurrent functions */
396        for(i=0; i<recurrent_list->count; i++)
397        {
398            if(recurrent_list->recurrent[i]->function)
399            {
400                refresh |= recurrent_list->recurrent[i]->function(screen_list,
401                                                                  recurrent_list->recurrent[i],
402                                                                  recurrent_list->recurrent[i]->user,
403                                                                  get_ms());
404            }
405        }
406       /* Delete recurrent functions */
407        for(i=0; i<recurrent_list->count; i++)
408        {
409            if(recurrent_list->recurrent[i]->kill_me)
410            {
411                remove_recurrent(recurrent_list, i);
412                i = 0;
413            }
414        }
415
416        /* Resfresh screen */
417
418        if(!screen_list->attached)
419        {
420            /* No need to refresh */
421        }
422        else if(screen_list->locked)
423        {
424            draw_lock(cv, screen_list);
425            caca_refresh_display(dp);
426        }
427        else
428        {
429
430            if((refresh || screen_list->in_bell) &&
431               (get_ms() - last_key_time < screen_list->screensaver_timeout))
432            {
433                refresh = 0;
434                refresh_screens(cv, dp, screen_list);
435            }
436
437            if((get_ms() - last_key_time > screen_list->screensaver_timeout))
438            {
439                if(!screen_list->in_screensaver)
440                    screensaver_init(cv, dp, screen_list);
441                screen_list->in_screensaver = 1;
442
443                caca_set_cursor(dp, 0);
444                draw_screensaver(cv, dp, screen_list);
445                caca_refresh_display(dp);
446            }
447        }
448
449        eof = 1;
450        for(i=0; i < screen_list->count; i++)
451            if(screen_list->screen[i]->fd >= 0)
452                eof = 0;
453        if(eof)
454            break;
455    }
456
457end:
458    /* Clean up */
459    caca_free_display(dp);
460    cucul_free_canvas(cv);
461    for(i = 0; i < screen_list->count; i++)
462    {
463        destroy_screen(screen_list->screen[i]);
464    }
465
466    free(screen_list->screen);
467
468
469    struct option *option = screen_list->config;
470
471
472    while(option)
473    {
474        struct option *kromeugnon = option;
475        option = option->next;
476        free(kromeugnon->key);
477        free(kromeugnon->value);
478        free(kromeugnon);
479    }
480
481    free(screen_list);
482
483
484    for(i=0; i<recurrent_list->count; i++)
485    {
486        remove_recurrent(recurrent_list, i);
487        i = 0;
488    }
489
490    free(recurrent_list->recurrent);
491    free(recurrent_list);
492
493
494    return 0;
495}
496
497
498
499long long get_ms(void)
500{
501    struct timeval tv;
502    gettimeofday(&tv, NULL);
503
504
505    return (tv.tv_sec*(1000000) + tv.tv_usec);
506}
Note: See TracBrowser for help on using the repository browser.