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

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