source: neercs/trunk/src/screens.c @ 3969

Last change on this file since 3969 was 3969, checked in by Jean-Yves Lamoureux, 11 years ago
  • Massive indentation pass, could insert odd things, blame pterjan, he doesn't care.
  • Property svn:keywords set to Id
File size: 8.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: screens.c 3969 2009-11-19 16:26:53Z 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 <sys/types.h>
22#include <signal.h>
23#include <sys/wait.h>
24#include <errno.h>
25#include <unistd.h>
26
27#include <caca.h>
28#include <caca.h>
29
30#include "neercs.h"
31
32struct screen *create_screen_grab(int w, int h, int pid)
33{
34    struct screen *s = (struct screen *)malloc(sizeof(struct screen));
35
36    s->cv = caca_create_canvas(w, h);
37    caca_set_color_ansi(s->cv, CACA_BLACK, CACA_BLACK);
38    caca_clear_canvas(s->cv);
39    s->init = 0;
40
41    s->buf = NULL;
42    s->title = NULL;
43    s->total = 0;
44    s->w = w;
45    s->h = h;
46    s->bell = 0;
47
48    s->fd = create_pty_grab(pid, w, h, &s->pid);
49
50    if (s->fd < 0)
51    {
52        caca_free_canvas(s->cv);
53        free(s);
54        return NULL;
55    }
56    return s;
57}
58
59struct screen *create_screen(int w, int h, char *command)
60{
61    struct screen *s = (struct screen *)malloc(sizeof(struct screen));
62
63    s->cv = caca_create_canvas(w, h);
64    caca_set_color_ansi(s->cv, CACA_BLACK, CACA_BLACK);
65    caca_clear_canvas(s->cv);
66    s->init = 0;
67
68    s->buf = NULL;
69    s->title = NULL;
70    s->total = 0;
71    s->w = w;
72    s->h = h;
73    s->bell = 0;
74    s->visible = 1;
75    s->scroll = 0;
76    s->fd = create_pty(command, w, h, &s->pid);
77
78    s->orig_w = s->w;
79    s->orig_h = s->h;
80    s->orig_x = s->x;
81    s->orig_y = s->y;
82
83
84    if (s->fd < 0)
85    {
86        caca_free_canvas(s->cv);
87        free(s);
88        return NULL;
89    }
90    return s;
91}
92
93int destroy_screen(struct screen *s)
94{
95    if (s->fd >= 0)
96        close(s->fd);
97    if (s->buf)
98        free(s->buf);
99    if (s->title)
100        free(s->title);
101    s->buf = NULL;
102    if (s->cv)
103        caca_free_canvas(s->cv);
104    s->cv = NULL;
105    free(s);
106    return 1;
107}
108
109int add_screen(struct screen_list *list, struct screen *s)
110{
111    if (list == NULL || s == NULL)
112        return -1;
113
114    else
115    {
116        list->screen = (struct screen **)realloc(list->screen,
117                                                 sizeof(sizeof
118                                                        (struct screen *)) *
119                                                 (list->count + 1));
120        if (!list->screen)
121            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
122                    __LINE__);
123        list->screen[list->count] = s;
124        list->count++;
125    }
126
127    list->changed = 1;
128
129    return list->count - 1;
130}
131
132int remove_screen(struct screen_list *list, int n, int please_kill)
133{
134
135    if (n >= list->count)
136        return -1;
137
138    if (please_kill)
139    {
140        int status = 0;
141        int ret = 0;
142        /* FIXME */
143        close(list->screen[n]->fd);
144        list->screen[n]->fd = -1;
145        kill(list->screen[n]->pid, SIGINT);
146        ret = waitpid(list->screen[n]->pid, &status,
147                      WNOHANG | WUNTRACED | WCONTINUED);
148        if (!ret)
149            kill(list->screen[n]->pid, SIGQUIT);
150        ret = waitpid(list->screen[n]->pid, &status,
151                      WNOHANG | WUNTRACED | WCONTINUED);
152        if (!ret)
153            kill(list->screen[n]->pid, SIGABRT);
154        ret = waitpid(list->screen[n]->pid, &status,
155                      WNOHANG | WUNTRACED | WCONTINUED);
156        if (!ret)
157            kill(list->screen[n]->pid, SIGKILL);
158
159    }
160    destroy_screen(list->screen[n]);
161
162    memmove(&list->screen[n],
163            &list->screen[n + 1],
164            sizeof(struct screen *) * (list->count - (n + 1)));
165
166    list->screen = (struct screen **)realloc(list->screen,
167                                             sizeof(sizeof(struct screen *))
168                                             * (list->count));
169    if (!list->screen)
170        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
171                __LINE__);
172
173
174
175    list->count--;
176    list->changed = 1;
177    return 1;
178}
179
180
181
182void refresh_screens(struct screen_list *screen_list)
183{
184    int i;
185
186    if (!screen_list->count)
187        return;
188
189
190    debug("Current pty is %d\n", screen_list->pty);
191
192    screen_list->width = caca_get_canvas_width(screen_list->cv);
193    screen_list->height =
194        caca_get_canvas_height(screen_list->cv) - (screen_list->mini * 6) -
195        screen_list->status;
196
197    if (!screen_list->dont_update_coords)
198    {
199        update_windows_props(screen_list);
200    }
201
202    if (screen_list->changed)
203    {
204        caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_DEFAULT);
205        caca_clear_canvas(screen_list->cv);
206    }
207    caca_set_color_ansi(screen_list->cv, CACA_LIGHTRED, CACA_BLACK);
208
209    wm_refresh(screen_list);
210
211    caca_gotoxy(screen_list->cv,
212                screen_list->screen[screen_list->pty]->x +
213                caca_get_cursor_x(screen_list->screen[screen_list->pty]->cv),
214                screen_list->screen[screen_list->pty]->y +
215                caca_get_cursor_y(screen_list->screen[screen_list->pty]->cv));
216
217
218    if (screen_list->mini)
219    {
220        draw_thumbnails(screen_list);
221    }
222    if (screen_list->status)
223    {
224        draw_status(screen_list);
225    }
226    if (screen_list->help)
227    {
228        draw_help(screen_list);
229    }
230    if (screen_list->window_list)
231    {
232        draw_list(screen_list);
233    }
234    screen_list->changed = 0;
235    for (i = screen_list->count - 1; i >= 0; i--)
236        screen_list->screen[i]->changed = 0;
237}
238
239
240int update_screens_contents(struct screen_list *screen_list)
241{
242    int i, refresh = 0;
243    int maxfd = 0;
244    struct timeval tv;
245    fd_set fdset;
246    int ret;
247
248    /* Read data, if any */
249    FD_ZERO(&fdset);
250    for (i = 0; i < screen_list->count; i++)
251    {
252        if (screen_list->screen[i]->fd >= 0)
253            FD_SET(screen_list->screen[i]->fd, &fdset);
254        if (screen_list->screen[i]->fd > maxfd)
255            maxfd = screen_list->screen[i]->fd;
256    }
257    tv.tv_sec = 0;
258    tv.tv_usec = 50000;
259    ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
260
261    if (ret < 0)
262    {
263        if (errno == EINTR)
264            ;                   /* We probably got a SIGWINCH, ignore it */
265        else
266        {
267            /* FIXME: Useless since break will mean that we return 0 But I
268               don't know what was the purpose of this code */
269            for (i = 0; i < screen_list->count; i++)
270                if (screen_list->screen[i]->total)
271                    break;
272            if (i == screen_list->count)
273                return 0;
274        }
275    }
276    else if (ret)
277    {
278
279        for (i = 0; i < screen_list->count; i++)
280        {
281            /* FIXME: try a new strategy: read all filedescriptors until each
282               of them starved at least once. */
283
284            if (screen_list->screen[i]->fd < 0 ||
285                !FD_ISSET(screen_list->screen[i]->fd, &fdset))
286                continue;
287
288            for (;;)
289            {
290                ssize_t nr;
291
292                screen_list->screen[i]->buf =
293                    realloc(screen_list->screen[i]->buf,
294                            screen_list->screen[i]->total + 1024);
295                if (!screen_list->screen[i]->buf)
296                    fprintf(stderr, "Can't allocate memory at %s:%d\n",
297                            __FUNCTION__, __LINE__);
298
299                nr = read(screen_list->screen[i]->fd,
300                          screen_list->screen[i]->buf +
301                          screen_list->screen[i]->total, 1024);
302
303                if (nr > 0)
304                {
305                    screen_list->screen[i]->total += nr;
306                    continue;
307                }
308
309                if (nr == 0 || errno != EWOULDBLOCK)
310                {
311                    remove_screen(screen_list, i, 0);
312                    if (i < screen_list->prevpty)
313                        screen_list->prevpty--;
314                    if (i == screen_list->pty)
315                    {
316                        screen_list->pty = screen_list->prevpty;
317                        screen_list->prevpty = 0;
318                    }
319                    if (i < (screen_list->pty))
320                        (screen_list->pty)--;
321                    /* Don't skip the element which is now at position i */
322                    i--;
323                    refresh = 1;
324                }
325
326                break;
327            }
328        }
329    }
330    return refresh;
331}
Note: See TracBrowser for help on using the repository browser.