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

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