File: rest.c

package info (click to toggle)
xwrits 2.19-1
  • links: PTS
  • area: main
  • in suites: woody
  • size: 564 kB
  • ctags: 641
  • sloc: ansic: 5,242; sh: 330; makefile: 93
file content (263 lines) | stat: -rw-r--r-- 7,044 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#include <config.h>
#include "xwrits.h"
#include <stdlib.h>
#include <assert.h>

static void
ensure_one_hand(Port *port)
{
  Hand *h;
  int nmapped = 0;
  for (h = port->hands; h; h = h->next)
    if (h->mapped)
      nmapped++;
  if (nmapped == 0)
    XMapRaised(port->display, port->hands->w);
}


/* wait for break */

static struct timeval wait_over_time;

static int
wait_x_loop(XEvent *e, const struct timeval *now)
{
  struct timeval diff;
  
  if (e->type == KeyPress || e->type == MotionNotify
      || e->type == ButtonPress) {
    xwSUBTIME(diff, *now, last_key_time);
    last_key_time = *now;
    
    /* if check_idle is on, long idle periods are the same as breaks */
    if (check_idle && xwTIMEGEQ(diff, idle_time))
      return TRAN_REST;
    
    /* if check_quota is on, mini-breaks add up over time */
    if (check_quota && xwTIMEGEQ(diff, quota_time)) {
      xwADDTIME(quota_allotment, quota_allotment, diff);
      if (check_idle && xwTIMEGEQ(quota_allotment, idle_time))
	return TRAN_REST;
    }
    
    /* wake up if time to warn */
    return (xwTIMEGEQ(*now, wait_over_time) ? TRAN_WARN : 0);
    
  } else
    return 0;
}

static int
adjust_wait_time(struct timeval *wait_began_time, const struct timeval *type_time)
     /* Adjust the time to wake up to reflect the length of the break, if
        under check_quota. Want to be able to type for slightly longer if
        you've been taking mini-breaks. */
{
  struct timeval this_break_time;
  struct timeval break_end_time;
  assert(check_quota);

  /* Find the time when this break should end = beginning of wait + type delay
     + break delay */
  xwADDTIME(break_end_time, *wait_began_time, *type_time);
  xwADDTIME(break_end_time, break_end_time, ocurrent->break_time);
  
  /* Find the length of this break */
  xwSUBTIME(this_break_time, ocurrent->break_time, quota_allotment);
  if (xwTIMEGEQ(ocurrent->min_break_time, this_break_time))
    this_break_time = ocurrent->min_break_time;
  
  /* Subtract to find when we should start warning */
  xwSUBTIME(break_end_time, break_end_time, this_break_time);
  
  /* Check against wait_over_time; if <=, wait is over */
  if (xwTIMEGEQ(wait_over_time, break_end_time))
    return TRAN_WARN;
  
  /* Set wait_over_time and return 0 -- we still need to wait */
  wait_over_time = break_end_time;
  return 0;
}

int
wait_for_break(const struct timeval *type_time)
{
  int val, i;
  struct timeval wait_began_time;

  /* Schedule wait_over_time */
  xwGETTIME(wait_began_time);
  xwADDTIME(wait_over_time, wait_began_time, *type_time);
  if (check_quota)
    xwSETTIME(quota_allotment, 0, 0);

  /* Pretend there's been a keystroke */
  last_key_time = wait_began_time;

  /* Clear slideshows */
  /* Do this now so later set_slideshows start from scratch. */
  for (i = 0; i < nports; i++) {
    set_all_slideshows(ports[i].hands, 0);
    set_all_slideshows(ports[i].icon_hands, 0);
  }
  
  val = 0;
  while (val != TRAN_WARN && val != TRAN_REST) {
    /* If !check_idle, we want to appear even if no keystroke happens, so
       schedule an alarm */
    if (!check_idle) {
      Alarm *a = new_alarm(A_AWAKE);
      a->timer = wait_over_time;
      unschedule(A_AWAKE);
      schedule(a);
    }
    
    /* Wait */
    val = loopmaster(0, wait_x_loop);
    if (val == TRAN_AWAKE) val = TRAN_WARN; /* patch A_AWAKE case */
    
    /* Adjust the wait time if necessary */
    assert(val == TRAN_WARN || val == TRAN_REST);
    if (val == TRAN_WARN && check_quota)
      val = adjust_wait_time(&wait_began_time, type_time);
  }
  
  unschedule(A_FLASH | A_AWAKE);
  assert(val == TRAN_WARN || val == TRAN_REST);
  return val;
}


/* rest */

static int current_cheats;
static struct timeval break_over_time;

static int
rest_x_loop(XEvent *e, const struct timeval *now)
{
  /* If the break is over, wake up. */
  if (xwTIMEGEQ(*now, break_over_time))
    return TRAN_AWAKE;
  
  if (e->type == Xw_DeleteWindow && active_hands() == 0)
    /* Window manager deleted last xwrits window. Consider break over. */
    return TRAN_CANCEL;
  else if (e->type == KeyPress || e->type == MotionNotify
	   || e->type == ButtonPress) {
    last_key_time = *now;
    current_cheats++;
    return (current_cheats > max_cheats ? TRAN_FAIL : 0);
  } else
    return 0;
}

void
calculate_break_time(struct timeval *break_over_time, const struct timeval *now)
{
  struct timeval this_break_time;
  
  /* determine length of this break. usually break_time; can be different if
     check_quota is on */
  this_break_time = ocurrent->break_time;
  if (check_quota) {
    xwSUBTIME(this_break_time, this_break_time, quota_allotment);
    if (xwTIMEGEQ(ocurrent->min_break_time, this_break_time))
      this_break_time = ocurrent->min_break_time;
  }
  
  /* determine when to end the break */
  if (!check_idle)
    xwADDTIME(*break_over_time, *now, this_break_time);
  else
    xwADDTIME(*break_over_time, last_key_time, this_break_time);
}

int
rest(void)
{
  struct timeval now;
  Alarm *a;
  int tran, i;

  /* set up pictures */
  /* Do this first so later set_slideshows start from scratch. */
  for (i = 0; i < nports; i++) {
    set_all_slideshows(ports[i].hands, resting_slideshow);
    set_all_slideshows(ports[i].icon_hands, resting_icon_slideshow);
    ensure_one_hand(&ports[i]);
  }
  current_cheats = 0;
  
  /* calculate time when break is over */
  xwGETTIME(now);
  calculate_break_time(&break_over_time, &now);
  
  /* if break already over, return */
  if (xwTIMEGEQ(now, break_over_time))
    return TRAN_AWAKE;

  /* schedule wakeup */
  a = new_alarm(A_AWAKE);
  a->timer = break_over_time;
  schedule(a);
  
  /* reschedule mouse position query timing: allow 5 seconds for people to
     jiggle the mouse before we save its position */
  if (check_mouse) {
    a = grab_alarm_data(A_MOUSE, 0, 0);
    a->timer = now;
    a->timer.tv_sec += 5;
    schedule(a);
    for (i = 0; i < nports; i++)
      ports[i].last_mouse_root = None;
  }
  
  if (ocurrent->break_clock) {
    clock_zero_time = break_over_time;
    draw_all_clocks(&now);
    a = new_alarm(A_CLOCK);
    xwADDTIME(a->timer, now, clock_tick);
    schedule(a);
  }

  for (i = 0; i < nports; i++)
    XFlush(ports[i].display);
  tran = loopmaster(0, rest_x_loop);
  
  unschedule(A_FLASH | A_AWAKE | A_CLOCK);
  erase_all_clocks();
  assert(tran == TRAN_CANCEL || tran == TRAN_AWAKE || tran == TRAN_FAIL);
  return tran;
}


/* ready */

static int
ready_x_loop(XEvent *e, const struct timeval *now)
{
  if (e->type == KeyPress || e->type == MotionNotify
      || e->type == ButtonPress) {
    /* if they typed, disappear automatically */
    last_key_time = *now;
    return 1;
  } else
    return 0;
}

void
ready(void)
{
  int i;
  for (i = 0; i < nports; i++) {
    set_all_slideshows(ports[i].hands, ready_slideshow);
    set_all_slideshows(ports[i].icon_hands, ready_icon_slideshow);
    ensure_one_hand(&ports[i]);
    if (ocurrent->beep)
      XBell(ports[i].display, 0);
    XFlush(ports[i].display);
  }
  loopmaster(0, ready_x_loop);
}