textlist.c 3.78 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include "view.h"
#include "../utils.h"
#include "gui/gui.h"
#include <stdlib.h>
#include <pthread.h>
#include <string.h>

struct textlist {
  view common;
  gui *g;
  widget *w;
  int maxsize;
  int cursize;
  float refresh_rate;
  int autoscroll;
  pthread_mutex_t lock;
  list * volatile to_append;
};

20
static void _append(struct textlist *this, char *s, int *deleted)
21 22
{
  if (this->cursize == this->maxsize) {
23
    textlist_del_silent(this->g, this->w, 0);
24
    this->cursize--;
25
    (*deleted)++;
26
  }
27
  textlist_add_silent(this->g, this->w, s, -1, FOREGROUND_COLOR);
28 29 30 31 32 33
  this->cursize++;
}

static void *textlist_thread(void *_this)
{
  struct textlist *this = _this;
Cedric Roux's avatar
Cedric Roux committed
34
  int dirty;
35 36
  int deleted;
  int visible_lines, start_line, number_of_lines;
37 38 39

  while (1) {
    if (pthread_mutex_lock(&this->lock)) abort();
Cedric Roux's avatar
Cedric Roux committed
40
    dirty = this->to_append == NULL ? 0 : 1;
41
    deleted = 0;
42 43 44
    while (this->to_append != NULL) {
      char *s = this->to_append->data;
      this->to_append = list_remove_head(this->to_append);
45
      _append(this, s, &deleted);
46 47
      free(s);
    }
48
    if (dirty) {
49
      textlist_state(this->g, this->w, &visible_lines, &start_line,
50 51 52 53 54 55
          &number_of_lines);
      if (this->autoscroll)
        start_line = number_of_lines - visible_lines;
      else
        start_line -= deleted;
      if (start_line < 0) start_line = 0;
56 57
      textlist_set_start_line(this->g, this->w, start_line);
      /* this call is not necessary, but if things change in textlist... */
58 59
      widget_dirty(this->g, this->w);
    }
60
    if (pthread_mutex_unlock(&this->lock)) abort();
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    sleepms(1000/this->refresh_rate);
  }

  return 0;
}

static void clear(view *this)
{
  /* TODO */
}

static void append(view *_this, char *s)
{
  struct textlist *this = (struct textlist *)_this;
  char *dup;

  if (pthread_mutex_lock(&this->lock)) abort();
  dup = strdup(s); if (dup == NULL) abort();
  this->to_append = list_append(this->to_append, dup);
  if (pthread_mutex_unlock(&this->lock)) abort();
}

83 84 85 86 87 88 89 90 91 92
static void scroll(void *private, gui *g,
    char *notification, widget *w, void *notification_data)
{
  struct textlist *this = private;
  int visible_lines;
  int start_line;
  int number_of_lines;
  int new_line;
  int inc;

93 94
  if (pthread_mutex_lock(&this->lock)) abort();

95
  textlist_state(g, w, &visible_lines, &start_line, &number_of_lines);
96 97 98 99 100 101 102 103 104 105
  inc = 10;
  if (inc > visible_lines - 2) inc = visible_lines - 2;
  if (inc < 1) inc = 1;
  if (!strcmp(notification, "scrollup")) inc = -inc;

  new_line = start_line + inc;
  if (new_line > number_of_lines - visible_lines)
    new_line = number_of_lines - visible_lines;
  if (new_line < 0) new_line = 0;

106
  textlist_set_start_line(g, w, new_line);
107 108 109 110 111

  if (new_line + visible_lines < number_of_lines)
    this->autoscroll = 0;
  else
    this->autoscroll = 1;
112 113

  if (pthread_mutex_unlock(&this->lock)) abort();
114 115 116 117 118 119 120 121 122
}

static void click(void *private, gui *g,
    char *notification, widget *w, void *notification_data)
{
  struct textlist *this = private;
  int *d = notification_data;
  int button = d[1];

123 124
  if (pthread_mutex_lock(&this->lock)) abort();

125
  if (button == 1) this->autoscroll = 1 - this->autoscroll;
126 127

  if (pthread_mutex_unlock(&this->lock)) abort();
128 129
}

130
view *new_view_textlist(int maxsize, float refresh_rate, gui *g, widget *w)
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
{
  struct textlist *ret = calloc(1, sizeof(struct textlist));
  if (ret == NULL) abort();

  ret->common.clear = clear;
  ret->common.append = (void (*)(view *, ...))append;

  ret->cursize = 0;
  ret->maxsize = maxsize;
  ret->refresh_rate = refresh_rate;
  ret->g = g;
  ret->w = w;
  ret->autoscroll = 1;

  if (pthread_mutex_init(&ret->lock, NULL)) abort();

147 148 149 150
  register_notifier(g, "scrollup", w, scroll, ret);
  register_notifier(g, "scrolldown", w, scroll, ret);
  register_notifier(g, "click", w, click, ret);

151 152 153 154
  new_thread(textlist_thread, ret);

  return (view *)ret;
}