Bug Summary

File:fe-text/textbuffer-view.c
Location:line 414, column 7
Description:Dereference of null pointer.

Annotated Source Code

1/*
2 textbuffer-view.c : Text buffer handling
3
4 Copyright (C) 1999-2001 Timo Sirainen
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20
21#define G_LOG_DOMAIN"TextBufferView" "TextBufferView"
22
23#include "module.h"
24#include "textbuffer-view.h"
25#include "utf8.h"
26
27typedef struct {
28 char *name;
29 LINE_REC *line;
30} BOOKMARK_REC;
31
32/* how often to scan line cache for lines not accessed for a while (ms) */
33#define LINE_CACHE_CHECK_TIME(5*60*1000) (5*60*1000)
34/* how long to keep line cache in memory (seconds) */
35#define LINE_CACHE_KEEP_TIME(10*60) (10*60)
36
37static int linecache_tag;
38static GSList *views;
39
40#define view_is_bottom(view)((view)->ypos >= -1 && (view)->ypos < (view
)->height)
\
41 ((view)->ypos >= -1 && (view)->ypos < (view)->height)
42
43#define view_get_linecount(view, line)textbuffer_view_get_line_cache(view, line)->count \
44 textbuffer_view_get_line_cache(view, line)->count
45
46static GSList *textbuffer_get_views(TEXT_BUFFER_REC *buffer)
47{
48 GSList *tmp, *list;
49
50 for (tmp = views; tmp != NULL((void *)0); tmp = tmp->next) {
51 TEXT_BUFFER_VIEW_REC *view = tmp->data;
52
53 if (view->buffer == buffer) {
54 list = g_slist_copy(view->siblings);
55 return g_slist_prepend(list, view);
56 }
57 }
58
59 return NULL((void *)0);
60}
61
62static TEXT_BUFFER_CACHE_REC *
63textbuffer_cache_get(GSList *views, int width)
64{
65 TEXT_BUFFER_CACHE_REC *cache;
66
67 /* check if there's existing cache with correct width */
68 while (views != NULL((void *)0)) {
69 TEXT_BUFFER_VIEW_REC *view = views->data;
70
71 if (view->width == width) {
72 view->cache->refcount++;
73 return view->cache;
74 }
75 views = views->next;
76 }
77
78 /* create new cache */
79 cache = g_new0(TEXT_BUFFER_CACHE_REC, 1)((TEXT_BUFFER_CACHE_REC *) g_malloc0 (((gsize) sizeof (TEXT_BUFFER_CACHE_REC
)) * ((gsize) (1))))
;
80 cache->refcount = 1;
81 cache->width = width;
82 cache->line_cache = g_hash_table_new((GHashFunc) g_direct_hash,
83 (GCompareFunc) g_direct_equal);
84 return cache;
85}
86
87static int line_cache_destroy(void *key, LINE_CACHE_REC *cache)
88{
89 g_free(cache);
90 return TRUE(!(0));
91}
92
93static void textbuffer_cache_destroy(TEXT_BUFFER_CACHE_REC *cache)
94{
95 g_hash_table_foreach(cache->line_cache,
96 (GHFunc) line_cache_destroy, NULL((void *)0));
97 g_hash_table_destroy(cache->line_cache);
98 g_free(cache);
99}
100
101static void textbuffer_cache_unref(TEXT_BUFFER_CACHE_REC *cache)
102{
103 if (--cache->refcount == 0)
104 textbuffer_cache_destroy(cache);
105}
106
107#define FGATTR((0x1000|0x2000|0x0800|0x0400) | 0x0100 | 0x0f) (ATTR_NOCOLORS(0x1000|0x2000|0x0800|0x0400) | ATTR_RESETFG0x0100 | 0x0f)
108#define BGATTR((0x1000|0x2000|0x0800|0x0400) | 0x0200 | 0xf0) (ATTR_NOCOLORS(0x1000|0x2000|0x0800|0x0400) | ATTR_RESETBG0x0200 | 0xf0)
109
110static void update_cmd_color(unsigned char cmd, int *color)
111{
112 if ((cmd & 0x80) == 0) {
113 if (cmd & LINE_COLOR_BG0x20) {
114 /* set background color */
115 *color &= FGATTR((0x1000|0x2000|0x0800|0x0400) | 0x0100 | 0x0f);
116 if ((cmd & LINE_COLOR_DEFAULT0x10) == 0)
117 *color |= (cmd & 0x0f) << 4;
118 else {
119 *color = (*color & FGATTR((0x1000|0x2000|0x0800|0x0400) | 0x0100 | 0x0f)) | ATTR_RESETBG0x0200;
120 }
121 } else {
122 /* set foreground color */
123 *color &= BGATTR((0x1000|0x2000|0x0800|0x0400) | 0x0200 | 0xf0);
124 if ((cmd & LINE_COLOR_DEFAULT0x10) == 0)
125 *color |= cmd & 0x0f;
126 else {
127 *color = (*color & BGATTR((0x1000|0x2000|0x0800|0x0400) | 0x0200 | 0xf0)) | ATTR_RESETFG0x0100;
128 }
129 }
130 } else switch (cmd) {
131 case LINE_CMD_UNDERLINE:
132 *color ^= ATTR_UNDERLINE0x1000;
133 break;
134 case LINE_CMD_REVERSE:
135 *color ^= ATTR_REVERSE0x2000;
136 break;
137 case LINE_CMD_BLINK:
138 *color ^= ATTR_BLINK0x0800;
139 break;
140 case LINE_CMD_BOLD:
141 *color ^= ATTR_BOLD0x0400;
142 break;
143 case LINE_CMD_COLOR0:
144 *color &= BGATTR((0x1000|0x2000|0x0800|0x0400) | 0x0200 | 0xf0);
145 break;
146 }
147}
148
149static inline unichar read_unichar(const unsigned char *data, const unsigned char **next, int *width)
150{
151 unichar chr = g_utf8_get_char_validated(data, -1);
152
153 if (chr & 0x80000000) {
154 chr = 0xfffd;
155 *next = data + 1;
156 *width = 1;
157 } else {
158 *next = g_utf8_next_char(data)(char *)((data) + g_utf8_skip[*(const guchar *)(data)]);
159 *width = unichar_isprint(chr)(((chr) & ~0x80) >= 32) ? mk_wcwidth(chr) : 1;
160 }
161 return chr;
162}
163
164static LINE_CACHE_REC *
165view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
166{
167 INDENT_FUNC indent_func;
168 LINE_CACHE_REC *rec;
169 LINE_CACHE_SUB_REC *sub;
170 GSList *lines;
171 unsigned char cmd;
172 const unsigned char *ptr, *next_ptr, *last_space_ptr;
173 int xpos, pos, indent_pos, last_space, last_color, color, linecount;
174 int char_width;
175
176 g_return_val_if_fail(line->text != NULL, NULL)do{ if (line->text != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "line->text != NULL"
); return (((void *)0)); }; }while (0)
;
177
178 color = ATTR_RESETFG0x0100 | ATTR_RESETBG0x0200;
179 xpos = 0; indent_pos = view->default_indent;
180 last_space = last_color = 0; last_space_ptr = NULL((void *)0); sub = NULL((void *)0);
181
182 indent_func = view->default_indent_func;
183 linecount = 1;
184 lines = NULL((void *)0);
185 for (ptr = line->text;;) {
186 if (*ptr == '\0') {
187 /* command */
188 ptr++;
189 cmd = *ptr;
190 ptr++;
191
192 if (cmd == LINE_CMD_EOL)
193 break;
194
195 if (cmd == LINE_CMD_CONTINUE) {
196 unsigned char *tmp;
197
198 memcpy(&tmp, ptr, sizeof(char *));
199 ptr = tmp;
200 continue;
201 }
202
203 if (cmd == LINE_CMD_INDENT) {
204 /* set indentation position here - don't do
205 it if we're too close to right border */
206 if (xpos < view->width-5) indent_pos = xpos;
207 } else
208 update_cmd_color(cmd, &color);
209 continue;
210 }
211
212 if (!view->utf8) {
213 /* MH */
214 if (term_type != TERM_TYPE_BIG52 ||
215 ptr[1] == '\0' || !is_big5(ptr[0], ptr[1])((0x81 <= (ptr[0]) && (ptr[0]) <= 0xFE) &&
(((0x40 <= (ptr[1]) && (ptr[1]) <= 0x7E) || (0x80
<= (ptr[1]) && (ptr[1]) <= 0xFE))))
)
216 char_width = 1;
217 else
218 char_width = 2;
219 next_ptr = ptr+char_width;
220 } else {
221 read_unichar(ptr, &next_ptr, &char_width);
222 }
223
224 if (xpos + char_width > view->width && sub != NULL((void *)0) &&
225 (last_space <= indent_pos || last_space <= 10) &&
226 view->longword_noindent) {
227 /* long word, remove the indentation from this line */
228 xpos -= sub->indent;
229 sub->indent = 0;
230 }
231
232 if (xpos + char_width > view->width) {
233 xpos = indent_func == NULL((void *)0) ? indent_pos :
234 indent_func(view, line, -1);
235
236 sub = g_new0(LINE_CACHE_SUB_REC, 1)((LINE_CACHE_SUB_REC *) g_malloc0 (((gsize) sizeof (LINE_CACHE_SUB_REC
)) * ((gsize) (1))))
;
237 if (last_space > indent_pos && last_space > 10) {
238 /* go back to last space */
239 color = last_color;
240 ptr = last_space_ptr;
241 while (*ptr == ' ') ptr++;
242 } else if (view->longword_noindent) {
243 /* long word, no indentation in next line */
244 xpos = 0;
245 sub->continues = TRUE(!(0));
246 }
247
248 sub->start = ptr;
249 sub->indent = xpos;
250 sub->indent_func = indent_func;
251 sub->color = color;
252
253 lines = g_slist_append(lines, sub);
254 linecount++;
255
256 last_space = 0;
257 continue;
258 }
259
260 if (!view->utf8 && char_width > 1) {
261 last_space = xpos;
262 last_space_ptr = next_ptr;
263 last_color = color;
264 } else if (*ptr == ' ') {
265 last_space = xpos;
266 last_space_ptr = ptr;
267 last_color = color;
268 }
269
270 xpos += char_width;
271 ptr = next_ptr;
272 }
273
274 rec = g_malloc(sizeof(LINE_CACHE_REC)-sizeof(LINE_CACHE_SUB_REC) +
275 sizeof(LINE_CACHE_SUB_REC) * (linecount-1));
276 rec->last_access = time(NULL((void *)0));
277 rec->count = linecount;
278
279 if (rec->count > 1) {
280 for (pos = 0; lines != NULL((void *)0); pos++) {
281 void *data = lines->data;
282
283 memcpy(&rec->lines[pos], data,
284 sizeof(LINE_CACHE_SUB_REC));
285
286 lines = g_slist_remove(lines, data);
287 g_free(data);
288 }
289 }
290
291 g_hash_table_insert(view->cache->line_cache, line, rec);
292 return rec;
293}
294
295static void view_remove_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
296 unsigned char update_counter)
297{
298 LINE_CACHE_REC *cache;
299
300 if (view->cache->update_counter == update_counter)
301 return;
302 view->cache->update_counter = update_counter;
303
304 cache = g_hash_table_lookup(view->cache->line_cache, line);
305 if (cache != NULL((void *)0)) {
306 g_free(cache);
307 g_hash_table_remove(view->cache->line_cache, line);
308 }
309}
310
311static void view_update_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
312 unsigned char update_counter)
313{
314 view_remove_cache(view, line, update_counter);
315
316 if (view->buffer->cur_line == line)
317 view->cache->last_linecount = view_get_linecount(view, line)textbuffer_view_get_line_cache(view, line)->count;
318}
319
320static void view_reset_cache(TEXT_BUFFER_VIEW_REC *view)
321{
322 GSList *tmp;
323
324 /* destroy line caches - note that you can't do simultaneously
325 unrefs + cache_get()s or it will keep using the old caches */
326 textbuffer_cache_unref(view->cache);
327 g_slist_foreach(view->siblings, (GFunc) textbuffer_cache_unref, NULL((void *)0));
328
329 view->cache = textbuffer_cache_get(view->siblings, view->width);
330 for (tmp = view->siblings; tmp != NULL((void *)0); tmp = tmp->next) {
331 TEXT_BUFFER_VIEW_REC *rec = tmp->data;
332
333 rec->cache = textbuffer_cache_get(rec->siblings, rec->width);
334 }
335}
336
337static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
338 int subline, int ypos, int max)
339{
340 INDENT_FUNC indent_func;
341 LINE_CACHE_REC *cache;
342 const unsigned char *text, *end, *text_newline;
343 unsigned char *tmp;
344 unichar chr;
345 int xpos, color, drawcount, first, need_move, need_clrtoeol, char_width;
346
347 if (view->dirty) /* don't bother drawing anything - redraw is coming */
[1] Taking false branch
348 return 0;
349
350 cache = textbuffer_view_get_line_cache(view, line);
351 if (subline >= cache->count)
[2] Taking false branch
352 return 0;
353
354 color = ATTR_RESET(0x0100|0x0200);
355 need_move = TRUE(!(0)); need_clrtoeol = FALSE(0);
356 xpos = drawcount = 0; first = TRUE(!(0));
357 text_newline = text =
358 subline == 0 ? line->text : cache->lines[subline-1].start;
[3] '?' condition evaluates to false
359 for (;;) {
[4] Loop condition is true. Entering loop body
[18] Loop condition is true. Entering loop body
360 if (text == text_newline) {
[5] Taking true branch
[19] Taking true branch
361 if (need_clrtoeol && xpos < term_width) {
[6] Taking false branch
[20] Taking false branch
362 term_set_color(view->window, ATTR_RESET(0x0100|0x0200));
363 term_clrtoeol(view->window);
364 }
365
366 if (first)
[7] Taking true branch
[21] Taking false branch
367 first = FALSE(0);
368 else {
369 ypos++;
370 if (--max == 0)
[22] Taking false branch
371 break;
372 }
373
374 if (subline > 0) {
[8] Taking true branch
[23] Taking false branch
375 /* continuing previous line - indent it */
376 indent_func = cache->lines[subline-1].indent_func;
377 if (indent_func == NULL((void *)0))
[9] Taking true branch
378 xpos = cache->lines[subline-1].indent;
379 color = cache->lines[subline-1].color;
380 } else {
381 indent_func = NULL((void *)0);
382 }
383
384 if (xpos == 0 && indent_func == NULL((void *)0))
[10] Taking false branch
[24] Taking false branch
385 need_clrtoeol = TRUE(!(0));
386 else {
387 /* line was indented - need to clear the
388 indented area first */
389 term_set_color(view->window, ATTR_RESET(0x0100|0x0200));
390 term_move(view->window, 0, ypos);
391 term_clrtoeol(view->window);
392
393 if (indent_func != NULL((void *)0))
[11] Taking false branch
[25] Taking false branch
394 xpos = indent_func(view, line, ypos);
395 }
396
397 if (need_move || xpos > 0)
[12] Taking true branch
[26] Taking false branch
398 term_move(view->window, xpos, ypos);
399
400 term_set_color(view->window, color);
401
402 if (subline == cache->count-1) {
[13] Taking true branch
[27] Taking false branch
403 text_newline = NULL((void *)0);
404 need_move = FALSE(0);
405 } else {
406 /* get the beginning of the next subline */
407 text_newline = cache->lines[subline].start;
408 need_move = !cache->lines[subline].continues;
409 }
410 drawcount++;
411 subline++;
412 }
413
414 if (*text == '\0') {
[14] Taking true branch
[28] Dereference of null pointer
415 /* command */
416 text++;
417 if (*text == LINE_CMD_EOL)
[15] Taking false branch
418 break;
419
420 if (*text == LINE_CMD_CONTINUE) {
[16] Taking true branch
421 /* jump to next block */
422 memcpy(&tmp, text+1, sizeof(unsigned char *));
423 text = tmp;
424 continue;
[17] Execution continues on line 359
425 } else {
426 update_cmd_color(*text, &color);
427 term_set_color(view->window, color);
428 }
429 text++;
430 continue;
431 }
432
433 if (view->utf8) {
434 chr = read_unichar(text, &end, &char_width);
435 } else {
436 chr = *text;
437 end = text;
438 if (term_type == TERM_TYPE_BIG52 &&
439 is_big5(end[0], end[1])((0x81 <= (end[0]) && (end[0]) <= 0xFE) &&
(((0x40 <= (end[1]) && (end[1]) <= 0x7E) || (0x80
<= (end[1]) && (end[1]) <= 0xFE))))
)
440 char_width = 2;
441 else
442 char_width = 1;
443 end += char_width;
444 }
445
446 xpos += char_width;
447 if (xpos <= term_width) {
448 if (unichar_isprint(chr)(((chr) & ~0x80) >= 32)) {
449 if (view->utf8)
450 term_add_unichar(view->window, chr);
451 else
452 for (; text < end; text++)
453 term_addch(view->window, *text);
454 } else {
455 /* low-ascii */
456 term_set_color(view->window, ATTR_RESET(0x0100|0x0200)|ATTR_REVERSE0x2000);
457 term_addch(view->window, (chr & 127)+'A'-1);
458 term_set_color(view->window, color);
459 }
460 }
461 text = end;
462 }
463
464 if (need_clrtoeol && xpos < term_width) {
465 term_set_color(view->window, ATTR_RESET(0x0100|0x0200));
466 term_clrtoeol(view->window);
467 }
468
469 return drawcount;
470}
471
472/* Recalculate view's bottom line information - try to keep the
473 original if possible */
474static void textbuffer_view_init_bottom(TEXT_BUFFER_VIEW_REC *view)
475{
476 LINE_REC *line;
477 int linecount, total;
478
479 if (view->empty_linecount == 0) {
480 /* no empty lines in screen, no need to try to keep
481 the old bottom startline */
482 view->bottom_startline = NULL((void *)0);
483 }
484
485 total = 0;
486 line = textbuffer_line_last(view->buffer);
487 for (; line != NULL((void *)0); line = line->prev) {
488 linecount = view_get_linecount(view, line)textbuffer_view_get_line_cache(view, line)->count;
489 if (line == view->bottom_startline) {
490 /* keep the old one, make sure that subline is ok */
491 if (view->bottom_subline > linecount)
492 view->bottom_subline = linecount;
493 view->empty_linecount = view->height - total -
494 (linecount-view->bottom_subline);
495 return;
496 }
497
498 total += linecount;
499 if (total >= view->height) {
500 view->bottom_startline = line;
501 view->bottom_subline = total - view->height;
502 view->empty_linecount = 0;
503 return;
504 }
505 }
506
507 /* not enough lines so we must be at the beginning of the buffer */
508 view->bottom_startline = view->buffer->first_line;
509 view->bottom_subline = 0;
510 view->empty_linecount = view->height - total;
511}
512
513static void textbuffer_view_init_ypos(TEXT_BUFFER_VIEW_REC *view)
514{
515 LINE_REC *line;
516
517 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
518
519 view->ypos = -view->subline-1;
520 for (line = view->startline; line != NULL((void *)0); line = line->next)
521 view->ypos += view_get_linecount(view, line)textbuffer_view_get_line_cache(view, line)->count;
522}
523
524/* Create new view. */
525TEXT_BUFFER_VIEW_REC *textbuffer_view_create(TEXT_BUFFER_REC *buffer,
526 int width, int height,
527 int scroll, int utf8)
528{
529 TEXT_BUFFER_VIEW_REC *view;
530
531 g_return_val_if_fail(buffer != NULL, NULL)do{ if (buffer != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "buffer != NULL"); return
(((void *)0)); }; }while (0)
;
532 g_return_val_if_fail(width > 0, NULL)do{ if (width > 0) { } else { g_return_if_fail_warning ("TextBufferView"
, __PRETTY_FUNCTION__, "width > 0"); return (((void *)0));
}; }while (0)
;
533
534 view = g_new0(TEXT_BUFFER_VIEW_REC, 1)((TEXT_BUFFER_VIEW_REC *) g_malloc0 (((gsize) sizeof (TEXT_BUFFER_VIEW_REC
)) * ((gsize) (1))))
;
535 view->buffer = buffer;
536 view->siblings = textbuffer_get_views(buffer);
537
538 view->width = width;
539 view->height = height;
540 view->scroll = scroll;
541 view->utf8 = utf8;
542
543 view->cache = textbuffer_cache_get(view->siblings, width);
544 textbuffer_view_init_bottom(view);
545
546 view->startline = view->bottom_startline;
547 view->subline = view->bottom_subline;
548 view->bottom = TRUE(!(0));
549
550 textbuffer_view_init_ypos(view);
551
552 view->bookmarks = g_hash_table_new((GHashFunc) g_str_hash,
553 (GCompareFunc) g_str_equal);
554
555 views = g_slist_append(views, view);
556 return view;
557}
558
559/* Destroy the view. */
560void textbuffer_view_destroy(TEXT_BUFFER_VIEW_REC *view)
561{
562 GSList *tmp;
563
564 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
565
566 views = g_slist_remove(views, view);
567
568 if (view->siblings == NULL((void *)0)) {
569 /* last view for textbuffer, destroy */
570 textbuffer_destroy(view->buffer);
571 } else {
572 /* remove ourself from siblings lists */
573 for (tmp = view->siblings; tmp != NULL((void *)0); tmp = tmp->next) {
574 TEXT_BUFFER_VIEW_REC *rec = tmp->data;
575
576 rec->siblings = g_slist_remove(rec->siblings, view);
577 }
578 g_slist_free(view->siblings);
579 }
580
581 g_hash_table_foreach(view->bookmarks, (GHFunc) g_free, NULL((void *)0));
582 g_hash_table_destroy(view->bookmarks);
583
584 textbuffer_cache_unref(view->cache);
585 g_free(view);
586}
587
588/* Change the default indent position */
589void textbuffer_view_set_default_indent(TEXT_BUFFER_VIEW_REC *view,
590 int default_indent,
591 int longword_noindent,
592 INDENT_FUNC indent_func)
593{
594 if (default_indent != -1)
595 view->default_indent = default_indent;
596 if (longword_noindent != -1)
597 view->longword_noindent = longword_noindent;
598
599 view->default_indent_func = indent_func;
600}
601
602static void view_unregister_indent_func(TEXT_BUFFER_VIEW_REC *view,
603 INDENT_FUNC indent_func)
604{
605 if (view->default_indent_func == indent_func)
606 view->default_indent_func = NULL((void *)0);
607
608 /* recreate cache so it won't contain references
609 to the indent function */
610 view_reset_cache(view);
611 view->cache = textbuffer_cache_get(view->siblings, view->width);
612}
613
614void textbuffer_views_unregister_indent_func(INDENT_FUNC indent_func)
615{
616 g_slist_foreach(views, (GFunc) view_unregister_indent_func,
617 (void *) indent_func);
618}
619
620void textbuffer_view_set_scroll(TEXT_BUFFER_VIEW_REC *view, int scroll)
621{
622 view->scroll = scroll;
623}
624
625void textbuffer_view_set_utf8(TEXT_BUFFER_VIEW_REC *view, int utf8)
626{
627 view->utf8 = utf8;
628}
629
630static int view_get_linecount_all(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
631{
632 int linecount;
633
634 linecount = 0;
635 while (line != NULL((void *)0)) {
636 linecount += view_get_linecount(view, line)textbuffer_view_get_line_cache(view, line)->count;
637 line = line->next;
638 }
639
640 return linecount;
641}
642
643static void view_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
644 int subline, int ypos, int lines, int fill_bottom)
645{
646 int linecount;
647
648 if (view->dirty) /* don't bother drawing anything - redraw is coming */
649 return;
650
651 while (line != NULL((void *)0) && lines > 0) {
652 linecount = view_line_draw(view, line, subline, ypos, lines);
653 ypos += linecount; lines -= linecount;
654
655 subline = 0;
656 line = line->next;
657 }
658
659 if (fill_bottom) {
660 /* clear the rest of the view */
661 term_set_color(view->window, ATTR_RESET(0x0100|0x0200));
662 while (lines > 0) {
663 term_move(view->window, 0, ypos);
664 term_clrtoeol(view->window);
665 ypos++; lines--;
666 }
667 }
668}
669
670#define view_draw_top(view, lines, fill_bottom)view_draw(view, (view)->startline, (view)->subline, 0, lines
, fill_bottom)
\
671 view_draw(view, (view)->startline, (view)->subline, \
672 0, lines, fill_bottom)
673
674static void view_draw_bottom(TEXT_BUFFER_VIEW_REC *view, int lines)
675{
676 LINE_REC *line;
677 int ypos, maxline, subline, linecount;
678
679 maxline = view->height-lines;
680 line = view->startline; ypos = -view->subline; subline = 0;
681 while (line != NULL((void *)0) && ypos < maxline) {
682 linecount = view_get_linecount(view, line)textbuffer_view_get_line_cache(view, line)->count;
683 ypos += linecount;
684 if (ypos > maxline) {
685 subline = maxline-(ypos-linecount);
686 break;
687 }
688 line = line->next;
689 }
690
691 view_draw(view, line, subline, maxline, lines, TRUE(!(0)));
692}
693
694/* Returns number of lines actually scrolled */
695static int view_scroll(TEXT_BUFFER_VIEW_REC *view, LINE_REC **lines,
696 int *subline, int scrollcount, int draw_nonclean)
697{
698 int linecount, realcount, scroll_visible;
699
700 if (*lines == NULL((void *)0))
701 return 0;
702
703 /* scroll down */
704 scroll_visible = lines == &view->startline;
705
706 realcount = -*subline;
707 scrollcount += *subline;
708 *subline = 0;
709 while (scrollcount > 0) {
710 linecount = view_get_linecount(view, *lines)textbuffer_view_get_line_cache(view, *lines)->count;
711
712 if ((scroll_visible && *lines == view->bottom_startline) &&
713 (scrollcount >= view->bottom_subline)) {
714 *subline = view->bottom_subline;
715 realcount += view->bottom_subline;
716 scrollcount = 0;
717 break;
718 }
719
720 realcount += linecount;
721 scrollcount -= linecount;
722 if (scrollcount < 0) {
723 realcount += scrollcount;
724 *subline = linecount+scrollcount;
725 scrollcount = 0;
726 break;
727 }
728
729 if ((*lines)->next == NULL((void *)0))
730 break;
731
732 *lines = (*lines)->next;
733 }
734
735 /* scroll up */
736 while (scrollcount < 0 && (*lines)->prev != NULL((void *)0)) {
737 *lines = (*lines)->prev;
738 linecount = view_get_linecount(view, *lines)textbuffer_view_get_line_cache(view, *lines)->count;
739
740 realcount -= linecount;
741 scrollcount += linecount;
742 if (scrollcount > 0) {
743 realcount += scrollcount;
744 *subline = scrollcount;
745 break;
746 }
747 }
748
749 if (scroll_visible && realcount != 0 && view->window != NULL((void *)0)) {
750 if (realcount <= -view->height || realcount >= view->height) {
751 /* scrolled more than screenful, redraw the
752 whole view */
753 textbuffer_view_redraw(view);
754 } else {
755 term_set_color(view->window, ATTR_RESET(0x0100|0x0200));
756 term_window_scroll(view->window, realcount);
757
758 if (draw_nonclean) {
759 if (realcount < 0)
760 view_draw_top(view, -realcount, TRUE)view_draw(view, (view)->startline, (view)->subline, 0, -
realcount, (!(0)))
;
761 else
762 view_draw_bottom(view, realcount);
763 }
764
765 term_refresh(view->window);
766 }
767 }
768
769 return realcount >= 0 ? realcount : -realcount;
770}
771
772/* Resize the view. */
773void textbuffer_view_resize(TEXT_BUFFER_VIEW_REC *view, int width, int height)
774{
775 int linecount;
776
777 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
778 g_return_if_fail(width > 0)do{ if (width > 0) { } else { g_return_if_fail_warning ("TextBufferView"
, __PRETTY_FUNCTION__, "width > 0"); return; }; }while (0)
;
779
780 if (view->width != width) {
781 /* line cache needs to be recreated */
782 textbuffer_cache_unref(view->cache);
783 view->cache = textbuffer_cache_get(view->siblings, width);
784 }
785
786 view->width = width > 10 ? width : 10;
787 view->height = height > 1 ? height : 1;
788
789 if (view->buffer->first_line == NULL((void *)0)) {
790 view->empty_linecount = height;
791 return;
792 }
793
794 textbuffer_view_init_bottom(view);
795
796 /* check that we didn't scroll lower than bottom startline.. */
797 if (textbuffer_line_exists_after(view->bottom_startline->next,
798 view->startline)) {
799 view->startline = view->bottom_startline;
800 view->subline = view->bottom_subline;
801 } else if (view->startline == view->bottom_startline &&
802 view->subline > view->bottom_subline) {
803 view->subline = view->bottom_subline;
804 } else {
805 /* make sure the subline is still in allowed range */
806 linecount = view_get_linecount(view, view->startline)textbuffer_view_get_line_cache(view, view->startline)->
count
;
807 if (view->subline > linecount)
808 view->subline = linecount;
809 }
810
811 textbuffer_view_init_ypos(view);
812 if (view->bottom && !view_is_bottom(view)((view)->ypos >= -1 && (view)->ypos < (view
)->height)
) {
813 /* we scrolled to far up, need to get down. go right over
814 the empty lines if there's any */
815 view->startline = view->bottom_startline;
816 view->subline = view->bottom_subline;
817 if (view->empty_linecount > 0) {
818 view_scroll(view, &view->startline, &view->subline,
819 -view->empty_linecount, FALSE(0));
820 }
821 textbuffer_view_init_ypos(view);
822 }
823
824 view->bottom = view_is_bottom(view)((view)->ypos >= -1 && (view)->ypos < (view
)->height)
;
825 if (view->bottom) {
826 /* check if we left empty space at the bottom.. */
827 linecount = view_get_linecount_all(view, view->startline) -
828 view->subline;
829 if (view->empty_linecount < view->height-linecount)
830 view->empty_linecount = view->height-linecount;
831 view->more_text = FALSE(0);
832 }
833
834 view->dirty = TRUE(!(0));
835}
836
837/* Clear the view, don't actually remove any lines from buffer. */
838void textbuffer_view_clear(TEXT_BUFFER_VIEW_REC *view)
839{
840 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
841
842 view->ypos = -1;
843 view->bottom_startline = view->startline =
844 textbuffer_line_last(view->buffer);
845 view->bottom_subline = view->subline =
846 view->buffer->cur_line == NULL((void *)0) ? 0 :
847 view_get_linecount(view, view->buffer->cur_line)textbuffer_view_get_line_cache(view, view->buffer->cur_line
)->count
;
848 view->empty_linecount = view->height;
849 view->bottom = TRUE(!(0));
850 view->more_text = FALSE(0);
851
852 textbuffer_view_redraw(view);
853}
854
855/* Scroll the view up/down */
856void textbuffer_view_scroll(TEXT_BUFFER_VIEW_REC *view, int lines)
857{
858 int count;
859
860 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
861
862 count = view_scroll(view, &view->startline, &view->subline,
863 lines, TRUE(!(0)));
864 view->ypos += lines < 0 ? count : -count;
865 view->bottom = view_is_bottom(view)((view)->ypos >= -1 && (view)->ypos < (view
)->height)
;
866 if (view->bottom) view->more_text = FALSE(0);
867
868 if (view->window != NULL((void *)0))
869 term_refresh(view->window);
870}
871
872/* Scroll to specified line */
873void textbuffer_view_scroll_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
874{
875 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
876
877 if (textbuffer_line_exists_after(view->bottom_startline->next, line)) {
878 view->startline = view->bottom_startline;
879 view->subline = view->bottom_subline;
880 } else {
881 view->startline = line;
882 view->subline = 0;
883 }
884
885 textbuffer_view_init_ypos(view);
886 view->bottom = view_is_bottom(view)((view)->ypos >= -1 && (view)->ypos < (view
)->height)
;
887 if (view->bottom) view->more_text = FALSE(0);
888
889 textbuffer_view_redraw(view);
890}
891
892/* Return line cache */
893LINE_CACHE_REC *textbuffer_view_get_line_cache(TEXT_BUFFER_VIEW_REC *view,
894 LINE_REC *line)
895{
896 LINE_CACHE_REC *cache;
897
898 g_assert(view != NULL)do { if (view != ((void *)0)) ; else g_assertion_message_expr
("TextBufferView", "textbuffer-view.c", 898, ((const char*) (
__PRETTY_FUNCTION__)), "view != NULL"); } while (0)
;
899 g_assert(line != NULL)do { if (line != ((void *)0)) ; else g_assertion_message_expr
("TextBufferView", "textbuffer-view.c", 899, ((const char*) (
__PRETTY_FUNCTION__)), "line != NULL"); } while (0)
;
900
901 cache = g_hash_table_lookup(view->cache->line_cache, line);
902 if (cache == NULL((void *)0))
903 cache = view_update_line_cache(view, line);
904 else
905 cache->last_access = time(NULL((void *)0));
906
907 return cache;
908}
909
910static void view_insert_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
911{
912 int linecount, ypos, subline;
913
914 if (!view->bottom)
915 view->more_text = TRUE(!(0));
916
917 if (view->bottom_startline == NULL((void *)0)) {
918 view->startline = view->bottom_startline =
919 view->buffer->first_line;
920 }
921
922 if (view->buffer->cur_line != line &&
923 !textbuffer_line_exists_after(view->bottom_startline, line))
924 return;
925
926 linecount = view->cache->last_linecount;
927 view->ypos += linecount;
928 if (view->empty_linecount > 0) {
929 view->empty_linecount -= linecount;
930 if (view->empty_linecount >= 0)
931 linecount = 0;
932 else {
933 linecount = -view->empty_linecount;
934 view->empty_linecount = 0;
935 }
936 }
937
938 if (linecount > 0) {
939 view_scroll(view, &view->bottom_startline,
940 &view->bottom_subline, linecount, FALSE(0));
941 }
942
943 if (view->bottom) {
944 if (view->scroll && view->ypos >= view->height) {
945 linecount = view->ypos-view->height+1;
946 view_scroll(view, &view->startline,
947 &view->subline, linecount, FALSE(0));
948 view->ypos -= linecount;
949 } else {
950 view->bottom = view_is_bottom(view)((view)->ypos >= -1 && (view)->ypos < (view
)->height)
;
951 }
952
953 if (view->window != NULL((void *)0)) {
954 ypos = view->ypos+1 - view->cache->last_linecount;
955 if (ypos >= 0)
956 subline = 0;
957 else {
958 subline = -ypos;
959 ypos = 0;
960 }
961 if (ypos < view->height) {
962 view_line_draw(view, line, subline, ypos,
963 view->height - ypos);
964 }
965 }
966 }
967
968 if (view->window != NULL((void *)0))
969 term_refresh(view->window);
970}
971
972/* Update some line in the buffer which has been modified using
973 textbuffer_append() or textbuffer_insert(). */
974void textbuffer_view_insert_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
975{
976 GSList *tmp;
977 unsigned char update_counter;
978
979 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
980 g_return_if_fail(line != NULL)do{ if (line != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "line != NULL"); return
; }; }while (0)
;
981
982 if (!view->buffer->last_eol)
983 return;
984
985 update_counter = view->cache->update_counter+1;
986 view_update_cache(view, line, update_counter);
987 view_insert_line(view, line);
988
989 for (tmp = view->siblings; tmp != NULL((void *)0); tmp = tmp->next) {
990 TEXT_BUFFER_VIEW_REC *rec = tmp->data;
991
992 view_update_cache(rec, line, update_counter);
993 view_insert_line(rec, line);
994 }
995}
996
997typedef struct {
998 LINE_REC *remove_line;
999 GSList *remove_list;
1000} BOOKMARK_FIND_REC;
1001
1002static void bookmark_check_remove(char *key, LINE_REC *line,
1003 BOOKMARK_FIND_REC *rec)
1004{
1005 if (line == rec->remove_line)
1006 rec->remove_list = g_slist_append(rec->remove_list, key);
1007}
1008
1009static void view_bookmarks_check(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
1010{
1011 BOOKMARK_FIND_REC rec;
1012 GSList *tmp;
1013
1014 rec.remove_line = line;
1015 rec.remove_list = NULL((void *)0);
1016 g_hash_table_foreach(view->bookmarks,
1017 (GHFunc) bookmark_check_remove, &rec);
1018
1019 if (rec.remove_list != NULL((void *)0)) {
1020 for (tmp = rec.remove_list; tmp != NULL((void *)0); tmp = tmp->next) {
1021 g_hash_table_remove(view->bookmarks, tmp->data);
1022 g_free(tmp->data);
1023 }
1024 g_slist_free(rec.remove_list);
1025 }
1026}
1027
1028/* Return number of real lines `lines' list takes -
1029 stops counting when the height reaches the view height */
1030static int view_get_lines_height(TEXT_BUFFER_VIEW_REC *view,
1031 LINE_REC *line, int subline,
1032 LINE_REC *skip_line)
1033{
1034 int height, linecount;
1035
1036 height = -subline;
1037 while (line != NULL((void *)0) && height < view->height) {
1038 if (line != skip_line) {
1039 linecount = view_get_linecount(view, line)textbuffer_view_get_line_cache(view, line)->count;
1040 height += linecount;
1041 }
1042 line = line->next;
1043 }
1044
1045 return height < view->height ? height : view->height;
1046}
1047
1048static void view_remove_line_update_startline(TEXT_BUFFER_VIEW_REC *view,
1049 LINE_REC *line, int linecount)
1050{
1051 int scroll;
1052
1053 if (view->startline == line) {
1054 view->startline = view->startline->prev != NULL((void *)0) ?
1055 view->startline->prev : view->startline->next;
1056 view->subline = 0;
1057 } else {
1058 scroll = view->height -
1059 view_get_lines_height(view, view->startline,
1060 view->subline, line);
1061 if (scroll > 0) {
1062 view_scroll(view, &view->startline,
1063 &view->subline, -scroll, FALSE(0));
1064 }
1065 }
1066
1067 /* FIXME: this is slow and unnecessary, but it's easy and
1068 really works :) */
1069 textbuffer_view_init_ypos(view);
1070 if (textbuffer_line_exists_after(view->startline, line))
1071 view->ypos -= linecount;
1072}
1073
1074static void view_remove_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
1075 int linecount)
1076{
1077 int realcount;
1078
1079 view_bookmarks_check(view, line);
1080
1081 if (view->buffer->cur_line == line) {
1082 /* the last line is being removed */
1083 LINE_REC *prevline;
1084
1085 prevline = view->buffer->first_line == line ? NULL((void *)0) :
1086 textbuffer_line_last(view->buffer);
1087 view->cache->last_linecount = prevline == NULL((void *)0) ? 0 :
1088 view_get_linecount(view, prevline)textbuffer_view_get_line_cache(view, prevline)->count;
1089 }
1090
1091 if (view->buffer->first_line == line) {
1092 /* first line in the buffer - this is the most commonly
1093 removed line.. */
1094 if (view->bottom_startline == line) {
1095 /* very small scrollback.. */
1096 view->bottom_startline = view->bottom_startline->next;
1097 view->bottom_subline = 0;
1098 }
1099
1100 if (view->startline == line) {
1101 /* removing the first line in screen */
1102 int is_last = view->startline->next == NULL((void *)0);
1103
1104 realcount = view_scroll(view, &view->startline,
1105 &view->subline,
1106 linecount, FALSE(0));
1107 view->ypos -= realcount;
1108 view->empty_linecount += linecount-realcount;
1109 if (is_last == 1)
1110 view->startline = NULL((void *)0);
1111 }
1112 } else {
1113 if (textbuffer_line_exists_after(view->bottom_startline,
1114 line)) {
1115 realcount = view_scroll(view, &view->bottom_startline,
1116 &view->bottom_subline,
1117 -linecount, FALSE(0));
1118 view->empty_linecount += linecount-realcount;
1119 }
1120
1121 if (textbuffer_line_exists_after(view->startline,
1122 line)) {
1123 view_remove_line_update_startline(view, line,
1124 linecount);
1125 }
1126 }
1127
1128 view->bottom = view_is_bottom(view)((view)->ypos >= -1 && (view)->ypos < (view
)->height)
;
1129 if (view->bottom) view->more_text = FALSE(0);
1130 if (view->window != NULL((void *)0))
1131 term_refresh(view->window);
1132}
1133
1134/* Remove one line from buffer. */
1135void textbuffer_view_remove_line(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
1136{
1137 GSList *tmp;
1138 unsigned char update_counter;
1139 int linecount;
1140
1141 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
1142 g_return_if_fail(line != NULL)do{ if (line != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "line != NULL"); return
; }; }while (0)
;
1143
1144 linecount = view_get_linecount(view, line)textbuffer_view_get_line_cache(view, line)->count;
1145 update_counter = view->cache->update_counter+1;
1146
1147 view_remove_line(view, line, linecount);
1148 view_remove_cache(view, line, update_counter);
1149
1150 for (tmp = view->siblings; tmp != NULL((void *)0); tmp = tmp->next) {
1151 TEXT_BUFFER_VIEW_REC *rec = tmp->data;
1152
1153 view_remove_line(rec, line, linecount);
1154 view_remove_cache(rec, line, update_counter);
1155 }
1156
1157 textbuffer_remove(view->buffer, line);
1158}
1159
1160void textbuffer_view_remove_lines_by_level(TEXT_BUFFER_VIEW_REC *view, int level)
1161{
1162 LINE_REC *line, *next;
1163
1164 term_refresh_freeze();
1165 line = textbuffer_view_get_lines(view)((view)->buffer->first_line);
1166
1167 while (line != NULL((void *)0)) {
1168 next = line->next;
1169
1170 if (line->info.level & level)
1171 textbuffer_view_remove_line(view, line);
1172 line = next;
1173 }
1174 textbuffer_view_redraw(view);
1175 term_refresh_thaw();
1176}
1177
1178static int g_free_true(void *data)
1179{
1180 g_free(data);
1181 return TRUE(!(0));
1182}
1183
1184/* Remove all lines from buffer. */
1185void textbuffer_view_remove_all_lines(TEXT_BUFFER_VIEW_REC *view)
1186{
1187 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
1188
1189 textbuffer_remove_all_lines(view->buffer);
1190
1191 g_hash_table_foreach_remove(view->bookmarks,
1192 (GHRFunc) g_free_true, NULL((void *)0));
1193
1194 view_reset_cache(view);
1195 textbuffer_view_clear(view);
1196 g_slist_foreach(view->siblings, (GFunc) textbuffer_view_clear, NULL((void *)0));
1197}
1198
1199/* Set a bookmark in view */
1200void textbuffer_view_set_bookmark(TEXT_BUFFER_VIEW_REC *view,
1201 const char *name, LINE_REC *line)
1202{
1203 gpointer key, value;
1204
1205 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
1206 g_return_if_fail(name != NULL)do{ if (name != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "name != NULL"); return
; }; }while (0)
;
1207
1208 if (g_hash_table_lookup_extended(view->bookmarks, name,
1209 &key, &value)) {
1210 g_hash_table_remove(view->bookmarks, key);
1211 g_free(key);
1212 }
1213
1214 g_hash_table_insert(view->bookmarks, g_strdup(name), line);
1215}
1216
1217/* Set a bookmark in view to the bottom line */
1218void textbuffer_view_set_bookmark_bottom(TEXT_BUFFER_VIEW_REC *view,
1219 const char *name)
1220{
1221 LINE_REC *line;
1222
1223 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
1224 g_return_if_fail(name != NULL)do{ if (name != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "name != NULL"); return
; }; }while (0)
;
1225
1226 if (view->bottom_startline != NULL((void *)0)) {
1227 line = textbuffer_line_last(view->buffer);
1228 textbuffer_view_set_bookmark(view, name, line);
1229 }
1230}
1231
1232/* Return the line for bookmark */
1233LINE_REC *textbuffer_view_get_bookmark(TEXT_BUFFER_VIEW_REC *view,
1234 const char *name)
1235{
1236 g_return_val_if_fail(view != NULL, NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
(((void *)0)); }; }while (0)
;
1237 g_return_val_if_fail(name != NULL, NULL)do{ if (name != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "name != NULL"); return
(((void *)0)); }; }while (0)
;
1238
1239 return g_hash_table_lookup(view->bookmarks, name);
1240}
1241
1242/* Specify window where the changes in view should be drawn,
1243 NULL disables it. */
1244void textbuffer_view_set_window(TEXT_BUFFER_VIEW_REC *view,
1245 TERM_WINDOW *window)
1246{
1247 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
1248
1249 if (view->window != window) {
1250 view->window = window;
1251 if (window != NULL((void *)0))
1252 view->dirty = TRUE(!(0));
1253 }
1254}
1255
1256/* Redraw a view to window */
1257void textbuffer_view_redraw(TEXT_BUFFER_VIEW_REC *view)
1258{
1259 g_return_if_fail(view != NULL)do{ if (view != ((void *)0)) { } else { g_return_if_fail_warning
("TextBufferView", __PRETTY_FUNCTION__, "view != NULL"); return
; }; }while (0)
;
1260
1261 if (view->window != NULL((void *)0)) {
1262 view->dirty = FALSE(0);
1263 view_draw_top(view, view->height, TRUE)view_draw(view, (view)->startline, (view)->subline, 0, view
->height, (!(0)))
;
1264 term_refresh(view->window);
1265 }
1266}
1267
1268static int line_cache_check_remove(void *key, LINE_CACHE_REC *cache,
1269 time_t *now)
1270{
1271 if (cache->last_access+LINE_CACHE_KEEP_TIME(10*60) > *now)
1272 return FALSE(0);
1273
1274 line_cache_destroy(NULL((void *)0), cache);
1275 return TRUE(!(0));
1276}
1277
1278static int sig_check_linecache(void)
1279{
1280 GSList *tmp, *caches;
1281 time_t now;
1282
1283 now = time(NULL((void *)0)); caches = NULL((void *)0);
1284 for (tmp = views; tmp != NULL((void *)0); tmp = tmp->next) {
1285 TEXT_BUFFER_VIEW_REC *rec = tmp->data;
1286
1287 if (g_slist_find(caches, rec->cache) != NULL((void *)0))
1288 continue;
1289
1290 caches = g_slist_append(caches, rec->cache);
1291 g_hash_table_foreach_remove(rec->cache->line_cache,
1292 (GHRFunc) line_cache_check_remove,
1293 &now);
1294 }
1295
1296 g_slist_free(caches);
1297 return 1;
1298}
1299
1300void textbuffer_view_init(void)
1301{
1302 linecache_tag = g_timeout_add(LINE_CACHE_CHECK_TIME(5*60*1000), (GSourceFunc) sig_check_linecache, NULL((void *)0));
1303}
1304
1305void textbuffer_view_deinit(void)
1306{
1307 g_source_remove(linecache_tag);
1308}