diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f69ddf --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.DS_Store +*.swp +*.xcworkspace +xcuserdata diff --git a/antirsi-core/antirsi-core.c b/antirsi-core/antirsi-core.c index ac8a006..b9ea3ef 100644 --- a/antirsi-core/antirsi-core.c +++ b/antirsi-core/antirsi-core.c @@ -3,332 +3,335 @@ * package: antirsi-core * license: GPL * - * TODO - * mini or work break should both be allowed to be disabled using extra boolean ... - * - * emit lock focus and have setting for it - * - * implement a smarter algorithm for setting and predicting breaks, - * maybe include scheduling static events, like tee or food and end of work day ... + * TODO: + * - mini or work break should both be allowed to be disabled using extra boolean ... + * - emit lock focus and have setting for it + * - implement a smarter algorithm for setting and predicting breaks, + * maybe include scheduling static events, like tee or food and end of work day ... */ #include "antirsi-core.h" -int -ai_seconds_until_next_work_break(ai_core * c) +int ai_seconds_until_next_work_break(ai_core *c) { - if (c->state == S_IN_WORK) { - return c->work_duration + c->work_interval - c->work_taking_t; - } - - return c->work_interval - c->work_t; + if (c->state == S_IN_WORK) { + return c->work_duration + c->work_interval - c->work_taking_t; + } + + return c->work_interval - c->work_t; } -int -ai_break_time_left(ai_core * c) +int ai_break_time_left(ai_core *c) { - switch (c->state) { - case S_IN_MINI: - return c->mini_duration - c->mini_taking_t; - case S_IN_WORK: - return c->work_duration - c->work_taking_t; - default: - return 0; - } + switch (c->state) { + case S_IN_MINI: + return c->mini_duration - c->mini_taking_t; + case S_IN_WORK: + return c->work_duration - c->work_taking_t; + default: + return 0; + } } -double -ai_break_progress(ai_core * c) +double ai_break_progress(ai_core *c) { - switch (c->state) { - case S_IN_MINI: - return 1.0 * c->mini_taking_t / c->mini_duration; - case S_IN_WORK: - return 1.0 * c->work_taking_t / c->work_duration; - default: - return 0.0; - } + switch (c->state) { + case S_IN_MINI: + return 1.0 * c->mini_taking_t / c->mini_duration; + case S_IN_WORK: + return 1.0 * c->work_taking_t / c->work_duration; + default: + return 0.0; + } } -void -ai_work_break_postpone(ai_core *c) +void ai_work_break_postpone(ai_core *c) { - c->mini_t = 0; - c->mini_taking_t = 0; - - c->work_t = c->work_interval - c->postpone_time; - if (c->work_t < 0) c->work_t = 0; - c->work_taking_t = 0; - - c->state = S_NORMAL; - - if (c->emit_break_end) c->emit_break_end(c->user_data); + c->mini_t = 0; + c->mini_taking_t = 0; + + c->work_t = c->work_interval - c->postpone_time; + if (c->work_t < 0) c->work_t = 0; + c->work_taking_t = 0; + + c->state = S_NORMAL; + + if (c->emit_break_end) { + c->emit_break_end(c->user_data); + } } -void -ai_work_break_now(ai_core *c) +void ai_work_break_now(ai_core *c) { - // implicit natural work break, shouldn't use it, but for older clients - if (c->last_work_taking_t_countdown > 0 && c->work_taking_t < c->last_work_taking_t) { - c->work_taking_t = c->last_work_taking_t; - } - - c->state = S_IN_WORK; - - if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); + // implicit natural work break, shouldn't use it, but for older clients + if (c->last_work_taking_t_countdown > 0 && c->work_taking_t < c->last_work_taking_t) { + c->work_taking_t = c->last_work_taking_t; + } + + c->state = S_IN_WORK; + + if (c->emit_work_break_start) { + c->emit_work_break_start(c->user_data); + } } -int -ai_can_continue_natural_break(ai_core *c) +int ai_can_continue_natural_break(ai_core *c) { return c->last_work_taking_t_countdown > 0; } -void -ai_continue_natural_work_break(ai_core *c) +void ai_continue_natural_work_break(ai_core *c) { - if (c->work_taking_t < c->last_work_taking_t) { - c->work_taking_t = c->last_work_taking_t; - } - c->state = S_IN_WORK; - - if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); + if (c->work_taking_t < c->last_work_taking_t) { + c->work_taking_t = c->last_work_taking_t; + } + c->state = S_IN_WORK; + + if (c->emit_work_break_start) { + c->emit_work_break_start(c->user_data); + } } -void -ai_tick(ai_core * c, double idle_time) +void ai_tick(ai_core *c, double idle_time) { - double new_time; - double delta; - - struct timeval tv; - int slack; - - if (gettimeofday(&tv, 0) != 0) { - fprintf(stderr, "no gettimeofday\n"); - return; - } - - new_time = tv.tv_sec + (tv.tv_usec / 1000000.0); - delta = new_time - c->time; - - // too fast, or initial run - if (delta < 0.0001) { - fprintf(stderr, "going too fast! %f - %f = %f\n", new_time, c->time, delta); - return; - } - - c->time = new_time; - - //fprintf(stderr, "fps: %0.2f\n", 1.0/delta); - - // if there was a long sleep, handle that first - if (delta > c->work_duration) { - c->mini_t = 0; - c->mini_taking_t = c->mini_duration; - - c->work_t = 0; - c->work_taking_t = c->work_duration; - - if (c->state != S_NORMAL) { - if (c->emit_break_end) c->emit_break_end(c->user_data); + double new_time; + double delta; + + struct timeval tv; + int slack; + + if (gettimeofday(&tv, 0) != 0) { + fprintf(stderr, "no gettimeofday\n"); + return; } - - // do stuff on next tick - return; - - } else if (delta > c->mini_duration) { - c->mini_t = 0; - c->mini_taking_t = 0; - - if (c->state != S_NORMAL) { - if (c->emit_break_end) c->emit_break_end(c->user_data); + + new_time = tv.tv_sec + (tv.tv_usec / 1000000.0); + delta = new_time - c->time; + + // too fast, or initial run + if (delta < 0.0001) { + fprintf(stderr, "going too fast! %f - %f = %f\n", new_time, c->time, delta); + return; } - - // do stuff on next tick - return; - } - - // process idle time with a 4 history filter; at least four discrete events within 15 seconds - // prevents media players and such to activate antirsi (does not prevent accidental mouse moving or similar!) - if (c->ith[0] >= idle_time) { - // new event - c->ith[3] = c->ith[2]; - c->ith[2] = c->ith[1]; - c->ith[1] = c->ith[0]; - } - c->ith[0] = idle_time; - - slack = (c->ith[3] + c->ith[2] + c->ith[1] + c->ith[0]) > 15; - - switch (c->state) { - case S_NORMAL: - // count down the natural work break validity - if (c->last_work_taking_t_countdown > 0) { - c->last_work_taking_t_countdown -= delta; + + c->time = new_time; + + //fprintf(stderr, "fps: %0.2f\n", 1.0/delta); + + // if there was a long sleep, handle that first + if (delta > c->work_duration) { + c->mini_t = 0; + c->mini_taking_t = c->mini_duration; + + c->work_t = 0; + c->work_taking_t = c->work_duration; + + if (c->state != S_NORMAL) { + if (c->emit_break_end) c->emit_break_end(c->user_data); } - - if (idle_time <= c->mini_duration * 0.3 && !slack) { - // the normal case, no slack, and not enough idle time - c->mini_t += delta; - c->mini_taking_t = 0; - - c->work_t += delta; - c->work_taking_t = 0; - } else { - // there is either slack or idle time, so we are taking some natural break - - if (c->work_taking_t >= c->work_duration) { - - // idle time has passed work break - c->mini_t = 0; - - c->work_t = 0; - c->work_taking_t = c->work_duration; - + + // do stuff on next tick + return; + + } else if (delta > c->mini_duration) { + c->mini_t = 0; + c->mini_taking_t = 0; + + if (c->state != S_NORMAL) { + if (c->emit_break_end) c->emit_break_end(c->user_data); + } + + // do stuff on next tick + return; + } + + // process idle time with a 4 history filter; at least four discrete events within 15 seconds + // prevents media players and such to activate antirsi (does not prevent accidental mouse moving or similar!) + if (c->ith[0] >= idle_time) { + // new event + c->ith[3] = c->ith[2]; + c->ith[2] = c->ith[1]; + c->ith[1] = c->ith[0]; + } + c->ith[0] = idle_time; + + slack = (c->ith[3] + c->ith[2] + c->ith[1] + c->ith[0]) > 15; + + switch (c->state) { + case S_NORMAL: + // count down the natural work break validity + if (c->last_work_taking_t_countdown > 0) { + c->last_work_taking_t_countdown -= delta; + } + + if (idle_time <= c->mini_duration * 0.3 && !slack) { + // the normal case, no slack, and not enough idle time + c->mini_t += delta; + c->mini_taking_t = 0; + + c->work_t += delta; + c->work_taking_t = 0; + } else { + // there is either slack or idle time, so we are taking some natural break + + if (c->work_taking_t >= c->work_duration) { + // idle time has passed work break + c->mini_t = 0; + + c->work_t = 0; + c->work_taking_t = c->work_duration; + + // natural work break no longer valid + c->last_work_taking_t_countdown = 0; + } else if (c->mini_taking_t >= c->mini_duration && c->work_t > 0) { + // idle time has passed mini break + c->mini_t = 0; + c->mini_taking_t = c->mini_duration; + c->work_taking_t += delta; + + // 30 second window for user to activate natural break continuation + c->last_work_taking_t_countdown = 30; + c->last_work_taking_t = c->work_taking_t; + } else { + // idle time has just kicked in + c->mini_taking_t += delta; + + c->work_t += delta; + c->work_taking_t = 0; + } + } + + if (c->mini_t >= c->mini_interval) { + // need to take a mini break + if (c->work_t > c->work_interval - (c->mini_interval / 2)) { + c->state = S_IN_WORK; + c->work_t = c->work_interval; + + if (c->emit_work_break_start) { + c->emit_work_break_start(c->user_data); + } + } else { + c->state = S_IN_MINI; + + if (c->emit_mini_break_start) { + c->emit_mini_break_start(c->user_data); + } + } + } + + if (c->work_t >= c->work_interval) { + // need to take a work break + c->mini_t = 0; + c->mini_taking_t = c->mini_duration; + c->state = S_IN_WORK; + + if (c->emit_work_break_start) { + c->emit_work_break_start(c->user_data); + } + } + + break; + + case S_IN_MINI: // natural work break no longer valid c->last_work_taking_t_countdown = 0; - - } else if (c->mini_taking_t >= c->mini_duration && c->work_t > 0) { - - // idle time has passed mini break - c->mini_t = 0; - c->mini_taking_t = c->mini_duration; - c->work_taking_t += delta; - - // 30 second window for user to activate natural break continuation - c->last_work_taking_t_countdown = 30; - c->last_work_taking_t = c->work_taking_t; - - } else { - // idle time has just kicked in + c->mini_taking_t += delta; - c->work_t += delta; - c->work_taking_t = 0; - } - } - - if (c->mini_t >= c->mini_interval) { - // need to take a mini break - if (c->work_t > c->work_interval - (c->mini_interval / 2)) { - - c->state = S_IN_WORK; - c->work_t = c->work_interval; - - if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); - - } else { - - c->state = S_IN_MINI; - - if (c->emit_mini_break_start) c->emit_mini_break_start(c->user_data); - - } - } - - if (c->work_t >= c->work_interval) { - // need to take a work break - c->mini_t = 0; - c->mini_taking_t = c->mini_duration; - c->state = S_IN_WORK; - - if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); - } - - break; - - case S_IN_MINI: - // natural work break no longer valid - c->last_work_taking_t_countdown = 0; - - c->mini_taking_t += delta; - c->work_t += delta; - - if (idle_time < 1 && !slack) { // TODO remove the idle_time ? - // we weren't breaking, so reset the break; - c->mini_taking_t = 0; - } - - // TODO emit redraws - // TODO if (c->lock_focus) - - if (c->mini_taking_t > c->mini_duration) { - // mini break is over - c->mini_t = 0; - c->mini_taking_t = c->mini_duration; - - if (c->emit_break_end) c->emit_break_end(c->user_data); - - c->state = S_NORMAL; - } - - if (c->work_t >= c->work_interval) { - // work break should start - c->mini_t = 0; - c->mini_taking_t = c->mini_duration; - - if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); - - c->state = S_IN_WORK; - } - - if (c->emit_break_update) c->emit_break_update(c->user_data); - - break; - - case S_IN_WORK: - // natural work break no longer valid - c->last_work_taking_t_countdown = 0; - - if (idle_time >= 4 || slack) { - // only when idle for 4 seconds, or there is some slack - c->work_taking_t += delta; - } - - // TODO emit redraws - // TODO if (c->lock_focus) - - if (c->work_taking_t > c->work_duration) { - // work break is over - c->mini_t = 0; - c->mini_taking_t = c->mini_duration; - - c->work_t = 0; - c->work_taking_t = c->work_duration; - - if (c->emit_break_end) c->emit_break_end(c->user_data); - - c->state = S_NORMAL; - } - - if (c->emit_break_update) c->emit_break_update(c->user_data); - - break; - } - - if (c->emit_status_update) c->emit_status_update(c->user_data); + + if (idle_time < 1 && !slack) { // TODO remove the idle_time ? + // we weren't breaking, so reset the break; + c->mini_taking_t = 0; + } + + // TODO emit redraws + // TODO if (c->lock_focus) + + if (c->mini_taking_t > c->mini_duration) { + // mini break is over + c->mini_t = 0; + c->mini_taking_t = c->mini_duration; + + if (c->emit_break_end) { + c->emit_break_end(c->user_data); + } + + c->state = S_NORMAL; + } + + if (c->work_t >= c->work_interval) { + // work break should start + c->mini_t = 0; + c->mini_taking_t = c->mini_duration; + + if (c->emit_work_break_start) { + c->emit_work_break_start(c->user_data); + } + + c->state = S_IN_WORK; + } + + if (c->emit_break_update) { + c->emit_break_update(c->user_data); + } + + break; + + case S_IN_WORK: + // natural work break no longer valid + c->last_work_taking_t_countdown = 0; + + if (idle_time >= 4 || slack) { + // only when idle for 4 seconds, or there is some slack + c->work_taking_t += delta; + } + + // TODO emit redraws + // TODO if (c->lock_focus) + + if (c->work_taking_t > c->work_duration) { + // work break is over + c->mini_t = 0; + c->mini_taking_t = c->mini_duration; + + c->work_t = 0; + c->work_taking_t = c->work_duration; + + if (c->emit_break_end) c->emit_break_end(c->user_data); + + c->state = S_NORMAL; + } + + if (c->emit_break_update) { + c->emit_break_update(c->user_data); + } + + break; + } + + if (c->emit_status_update) { + c->emit_status_update(c->user_data); + } } -ai_core * -antirsi_init(void * data) +ai_core *antirsi_init(void *data) { - ai_core * c = malloc(sizeof(ai_core)); - memset(c, 0, sizeof(ai_core)); - - c->user_data = data; - - c->time = time(0); - - // default settings - c->mini_duration = 14; - c->mini_interval = 4*60; - c->work_duration = 8*60; - c->work_interval = 50*60; - c->postpone_time = 10*60; - - c->state = S_NORMAL; - - return c; + ai_core *c = malloc(sizeof(ai_core)); + memset(c, 0, sizeof(ai_core)); + + c->user_data = data; + + c->time = time(0); + + // default settings + c->mini_duration = 14; + c->mini_interval = 4*60; + c->work_duration = 8*60; + c->work_interval = 50*60; + c->postpone_time = 10*60; + + c->state = S_NORMAL; + + return c; } diff --git a/antirsi-core/antirsi-core.h b/antirsi-core/antirsi-core.h index 99a6d4e..da24f22 100644 --- a/antirsi-core/antirsi-core.h +++ b/antirsi-core/antirsi-core.h @@ -2,7 +2,7 @@ #define _antirsi_core_h_ /* - * author: Onne Gorter + * author: Onne Gorter , Jahn Bertsch * package: antirsi-core * license: GPL */ @@ -16,54 +16,62 @@ /** the state antirsi is in */ typedef enum { - S_NORMAL = 1, - S_IN_MINI, - S_IN_WORK + S_NORMAL = 1, + S_IN_MINI, + S_IN_WORK } ai_state; /** a global context for the core */ typedef struct _ai_core { - void * user_data; - + void *user_data; + double time; - + // breaks /** time since last mini break */ double mini_t; + /** time the user has been taking a mini break */ double mini_taking_t; + /** time since last work break */ double work_t; + /** time the user has been taking a work break */ double work_taking_t; - + // natural break continuation /** last #work_taking_t, for natural break continuation */ double last_work_taking_t; + /** time when last natural work break was stopped */ double last_work_taking_t_countdown; - + // settings /** the time between mini breaks */ int mini_interval; + /** the time a mini break lasts */ int mini_duration; + /** the time between work breaks */ int work_interval; + /** the time a work break lasts */ int work_duration; + /** the time postpone will set #work_t back */ int postpone_time; - + /** 1 if no mini breaks are to be issues, 0 otherwise */ int mini_disabled; /** 1 if no work breaks are to be issues, 0 otherwise */ int work_disabled; - + // state ai_state state; double ith[4]; // history filter - + // library exit functions /** * when a break is over, this function is called @@ -71,47 +79,55 @@ typedef struct _ai_core { * The function will only be called if the function pointer is not NULL (default) * the user data set with #antirsi_init is passed to the function */ - void (*emit_break_end)(void * data); + void (*emit_break_end)(void *data); + /** when a mini break is starting; see #emit_break_end */ - void (*emit_mini_break_start)(void * data); + void (*emit_mini_break_start)(void *data); + /** when a work break is starting; see #emit_break_end */ - void (*emit_work_break_start)(void * data); + void (*emit_work_break_start)(void *data); + /** everytime a tick has been processed, and we are in a break, this function is called; see #emit_break_end */ - void (*emit_break_update)(void * data); + void (*emit_break_update)(void *data); + /** everytime a tick has been processed, this function is called; see #emit_break_end */ - void (*emit_status_update)(void * data); - + void (*emit_status_update)(void *data); } ai_core; /** returns the seconds until the next work break */ -int ai_seconds_until_next_work_break(ai_core * c); +int ai_seconds_until_next_work_break(ai_core *c); + /** returns the seconds the current break lasts */ -int ai_break_time_left(ai_core * c); +int ai_break_time_left(ai_core *c); + /** returns double between 0 and 1, indicating the progress of the break; 0 is just starting, 1 is done */ -double ai_break_progress(ai_core * c); +double ai_break_progress(ai_core *c); + /** will postpone the current break #ai_core->postpone_time */ void ai_work_break_postpone(ai_core *c); + /** will initiate a work break right now */ void ai_work_break_now(ai_core *c); // natural break continuation /** 1 if a natural work break continuation is available, 0 otherwise */ int ai_can_continue_natural_break(ai_core *c); + /** continue a natural work break, use this instead of #ai_work_break_now */ void ai_continue_natural_work_break(ai_core *c); /** * makes the core go one step, calculating times spend, idle time and then the new state/times - * this function will call appropriate functions like #emit_break_end and such when necesairy. + * this function will call appropriate functions like #emit_break_end and such when neccessary. * Notice that these functions will only be called when the have been set: * @example * @code - * static void handle_break_end(void * data){ + * static void handle_break_end(void *data){ * fprintf(stderr, "handle_break_end\n"); * } * * main { - * ai_core * core; + * ai_core *core; * ... * core->emit_break_end = handle_break_end; * ... @@ -120,11 +136,12 @@ void ai_continue_natural_work_break(ai_core *c); * * provide the current idle time (#idle_time) and antirsi context #ai_core */ -void ai_tick(ai_core * c, double idle_time); +void ai_tick(ai_core *c, double idle_time); /** * initialize antirsi core, #data will be used in all callbacks the library makes */ -ai_core * antirsi_init(void * data); +ai_core *antirsi_init(void *data); #endif + diff --git a/macosx/AntiRSI.h b/macosx/AntiRSI.h index 2584b67..a210476 100644 --- a/macosx/AntiRSI.h +++ b/macosx/AntiRSI.h @@ -1,5 +1,5 @@ /* - * author: Onne Gorter + * author: Onne Gorter , Jahn Bertsch * package: antirsi-macosx * license: GPL */ @@ -22,29 +22,29 @@ IBOutlet NSTextField *time; IBOutlet NSTextField *next_break; IBOutlet NSTextField *version; - + IBOutlet NSMenuItem *menuBreakNow; IBOutlet NSMenuItem *dockBreakNow; IBOutlet NSMenuItem *menuPostpone; IBOutlet NSMenuItem *dockPostpone; - + // dock icon image NSImage* dock_image; NSImage* original_dock_image; - + // window to display the views in NSWindow *main_window; - + // timer that ticks every second to update NSTimer *mtimer; - + double sample_interval; - + // verious other options bool lock_focus; bool draw_dock_image; bool draw_dock_image_q; - + // various colors NSColor* taking; NSColor* elapsed; @@ -52,14 +52,13 @@ NSColor* darkbackground; NSString *sVersion; - + ai_core * core; } //bindings - (void)setSample_interval:(NSString *)s; - (void)setDraw_dock_image:(BOOL)b; -- (void)setBackground:(NSColor *)c; // postpone button - (IBAction)postpone:(id)sender; diff --git a/macosx/AntiRSI.m b/macosx/AntiRSI.m index f0d0d65..e60ba10 100644 --- a/macosx/AntiRSI.m +++ b/macosx/AntiRSI.m @@ -17,27 +17,27 @@ // entry functions from antirsi-core -static void handle_break_end(void * data) { +static void handle_break_end(void *data) { id ai = (id)data; [ai endBreak]; } -static void handle_mini_break_start(void * data) { +static void handle_mini_break_start(void *data) { id ai = (id)data; [ai doMicroPause]; } -static void handle_work_break_start(void * data) { +static void handle_work_break_start(void *data) { id ai = (id)data; [ai doWorkBreak]; } -static void handle_break_update(void * data) { +static void handle_break_update(void *data) { id ai = (id)data; [ai drawBreakWindow]; } -static void handle_status_update(void * data) { +static void handle_status_update(void *data) { id ai = (id)data; [ai drawDockImage]; } @@ -59,22 +59,18 @@ - (void)installTimer:(double)interval { if (mtimer != nil) { [mtimer invalidate]; - [mtimer autorelease]; } - mtimer = [[NSTimer scheduledTimerWithTimeInterval:interval - target:self - selector:@selector(tick:) - userInfo:nil repeats:YES] retain]; + mtimer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(tick:) userInfo:nil repeats:YES]; } -- (void)setSample_interval:(NSString *)s +- (void)setSample_interval:(NSString *)string { sample_interval = 1; - if ([s isEqualToString:@"Super Smooth"]) sample_interval = 0.1; - if ([s isEqualToString:@"Smooth"]) sample_interval = 0.33; - if ([s isEqualToString:@"Normal"]) sample_interval = 1; - if ([s isEqualToString:@"Low"]) sample_interval = 2; - + if ([string isEqualToString:@"Super Smooth"]) sample_interval = 0.1; + if ([string isEqualToString:@"Smooth"]) sample_interval = 0.33; + if ([string isEqualToString:@"Normal"]) sample_interval = 1; + if ([string isEqualToString:@"Low"]) sample_interval = 2; + [self installTimer:sample_interval]; } @@ -88,31 +84,13 @@ - (void)setDraw_dock_image:(BOOL)b } } -- (void)setBackground:(NSColor *)c +- (void)setElapsed { - [background autorelease]; - background=[c retain]; - - // make new darkbackground color - CGFloat r,g,b,a; - [background getRed:&r green:&g blue:&b alpha:&a]; - [darkbackground autorelease]; - darkbackground=[[NSColor colorWithCalibratedRed:r*0.35 green:g*0.35 blue:b*0.35 alpha:a+0.2] retain]; - [self drawDockImage]; } -- (void)setElapsed:(NSColor *)c +- (void)setTaking { - [elapsed autorelease]; - elapsed=[c retain]; - [self drawDockImage]; -} - -- (void)setTaking:(NSColor *)c -{ - [taking autorelease]; - taking=[c retain]; [self drawDockImage]; } @@ -123,36 +101,34 @@ - (void)awakeFromNib core = antirsi_init(self); // want transparancy [NSColor setIgnoresAlpha:NO]; - + // initial colors - elapsed = [[NSColor colorWithCalibratedRed:0.77 green:0 blue:0 alpha:0.9] retain]; - taking = [[NSColor colorWithCalibratedRed:0.04 green:0.46 blue:0.04 alpha:0.9] retain]; + elapsed = [NSColor colorWithCalibratedRed:0.77 green:0 blue:0 alpha:0.9]; + taking = [NSColor colorWithCalibratedRed:0.04 green:0.46 blue:0.04 alpha:0.9]; background = [NSColor colorWithCalibratedRed:0.9 green:0.9 blue:0.9 alpha:0.7]; - + //initial values core->mini_interval = 4*60; core->mini_duration = 13; core->work_interval = 50*60; core->work_duration = 8*60; - + core->emit_break_end = handle_break_end; core->emit_mini_break_start = handle_mini_break_start; core->emit_work_break_start = handle_work_break_start; core->emit_break_update = handle_break_update; core->emit_status_update = handle_status_update; - + sample_interval = 1; - + // initialize dock image dock_image = [[NSImage alloc] initWithSize:NSMakeSize(128,128)]; [dock_image setCacheMode:NSImageCacheNever]; original_dock_image = [NSImage imageNamed:@"AntiRSI"]; draw_dock_image_q = YES; - + // setup main window that will show either micropause or workbreak - main_window = [[NSWindow alloc] initWithContentRect:[view frame] - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered defer:YES]; + main_window = [[NSWindow alloc] initWithContentRect:[view frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]; [main_window setBackgroundColor:[NSColor clearColor]]; [main_window setLevel:NSScreenSaverWindowLevel]; [main_window setAlphaValue:0.85]; @@ -162,10 +138,9 @@ - (void)awakeFromNib [main_window center]; [main_window setContentView:view]; [main_window setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; - - // set background now - [self setBackground:background]; - + + [self drawDockImage]; + // create initial values NSMutableDictionary* initial = [NSMutableDictionary dictionaryWithCapacity:10]; [initial setObject:[NSNumber numberWithFloat:10] forKey:@"micro_pause_period"]; @@ -179,38 +154,35 @@ - (void)awakeFromNib [initial setObject:[NSArchiver archivedDataWithRootObject:taking] forKey:@"taking"]; [initial setObject:[NSArchiver archivedDataWithRootObject:background] forKey:@"background"]; [[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:initial]; - + // bind to defauls controller - id dc = [NSUserDefaultsController sharedUserDefaultsController]; - [self bind:@"micro_pause_period" toObject:dc withKeyPath:@"values.micro_pause_period" options:nil]; - [self bind:@"micro_pause_duration" toObject:dc withKeyPath:@"values.micro_pause_duration" options:nil]; - [self bind:@"work_break_period" toObject:dc withKeyPath:@"values.work_break_period" options:nil]; - [self bind:@"work_break_duration" toObject:dc withKeyPath:@"values.work_break_duration" options:nil]; - [self bind:@"sample_interval" toObject:dc withKeyPath:@"values.sample_interval" options:nil]; - [self bind:@"draw_dock_image" toObject:dc withKeyPath:@"values.draw_dock_image" options:nil]; - [self bind:@"lock_focus" toObject:dc withKeyPath:@"values.lock_focus" options:nil]; + id userDefaultsController = [NSUserDefaultsController sharedUserDefaultsController]; + [self bind:@"micro_pause_period" toObject:userDefaultsController withKeyPath:@"values.micro_pause_period" options:nil]; + [self bind:@"micro_pause_duration" toObject:userDefaultsController withKeyPath:@"values.micro_pause_duration" options:nil]; + [self bind:@"work_break_period" toObject:userDefaultsController withKeyPath:@"values.work_break_period" options:nil]; + [self bind:@"work_break_duration" toObject:userDefaultsController withKeyPath:@"values.work_break_duration" options:nil]; + [self bind:@"sample_interval" toObject:userDefaultsController withKeyPath:@"values.sample_interval" options:nil]; + [self bind:@"draw_dock_image" toObject:userDefaultsController withKeyPath:@"values.draw_dock_image" options:nil]; + [self bind:@"lock_focus" toObject:userDefaultsController withKeyPath:@"values.lock_focus" options:nil]; NSDictionary* unarchive = [NSDictionary dictionaryWithObject:NSUnarchiveFromDataTransformerName forKey:@"NSValueTransformerName"]; - [self bind:@"elapsed" toObject:dc withKeyPath:@"values.elapsed" options:unarchive]; - [self bind:@"taking" toObject:dc withKeyPath:@"values.taking" options:unarchive]; - [self bind:@"background" toObject:dc withKeyPath:@"values.background" options:unarchive]; - + [self bind:@"elapsed" toObject:userDefaultsController withKeyPath:@"values.elapsed" options:unarchive]; + [self bind:@"taking" toObject:userDefaultsController withKeyPath:@"values.taking" options:unarchive]; + [self bind:@"background" toObject:userDefaultsController withKeyPath:@"values.background" options:unarchive]; + // alert every binding [[NSUserDefaultsController sharedUserDefaultsController] revert:self]; - + // start the timer [self installTimer:sample_interval]; - + // about dialog - sVersion = [[NSString stringWithFormat:@"%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]] retain]; + sVersion = [NSString stringWithFormat:@"%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]; [version setStringValue:[NSString stringWithFormat:@"Version %@", sVersion]]; - - // TODO remove? - [progress setMaxValue:1]; } // tick every second and update status - (void)tick:(NSTimer *)timer { - + // still even iTunes posts HID events to prevent screen blanks and screen saver ... ugly CFTimeInterval idle_time = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateHIDSystemState, kCGAnyInputEventType); ai_tick(core, idle_time); @@ -222,7 +194,7 @@ - (void)drawBreakWindow { [progress setDoubleValue:ai_break_progress(core)]; [self drawTimeLeft:ai_break_time_left(core)]; [self drawNextBreak:ai_seconds_until_next_work_break(core)]; - + // if user likes to be interrupted if (lock_focus) { [NSApp activateIgnoringOtherApps:YES]; @@ -233,33 +205,33 @@ - (void)drawBreakWindow { // draw the dock icon - (void)drawDockImage { if (!draw_dock_image) return; - + [dock_image lockFocus]; - + // clear all [[NSColor clearColor] set]; NSRectFill(NSMakeRect(0,0,127,127)); - + NSBezierPath* p; float end; - + //draw background circle [darkbackground set]; p =[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(6,6,115,115)]; [p setLineWidth:4]; [p stroke]; - + //fill [background set]; [[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(8,8,111,111)] fill]; - + //put dot in middle [darkbackground set]; [[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(59,59,9,9)] fill]; - + // reuse this one p = [NSBezierPath bezierPath]; - + // draw work_break [elapsed set]; end = 360 - (360.0 / core->work_interval * core->work_t - 90); @@ -267,7 +239,7 @@ - (void)drawDockImage { [p appendBezierPathWithArcWithCenter:NSMakePoint(63.5, 63.5) radius:40 startAngle:90 endAngle:end clockwise:YES]; [p setLineWidth:22]; [p stroke]; - + // draw work break taking [taking set]; [p removeAllPoints]; @@ -276,7 +248,7 @@ - (void)drawDockImage { [p appendBezierPathWithArcWithCenter:NSMakePoint(63.5, 63.5) radius:40 startAngle:90 endAngle:end clockwise:YES]; [p setLineWidth:18]; [p stroke]; - + // draw micro pause [elapsed set]; [p removeAllPoints]; @@ -285,7 +257,7 @@ - (void)drawDockImage { [p appendBezierPathWithArcWithCenter:NSMakePoint(63.5, 63.5) radius:17 startAngle:90 endAngle:end clockwise:YES]; [p setLineWidth:22]; [p stroke]; - + // draw micro pause taking [taking set]; [p removeAllPoints]; @@ -294,9 +266,9 @@ - (void)drawDockImage { [p appendBezierPathWithArcWithCenter:NSMakePoint(63.5, 63.5) radius:17 startAngle:90 endAngle:end clockwise:YES]; [p setLineWidth:18]; [p stroke]; - + [dock_image unlockFocus]; - + // and set it in the dock check draw_dock_image one last time ... if (draw_dock_image_q) [NSApp setApplicationIconImage:dock_image]; } @@ -306,7 +278,7 @@ - (void)endBreak { [[main_window animator] setAlphaValue:0.0]; // what is the consequence of hiding it, instead of ordering it out?? //[main_window orderOut:NULL]; - + // reset time interval to user's choice [self installTimer:sample_interval]; } @@ -317,7 +289,7 @@ - (void)orderInBreakWindow { [main_window orderFrontRegardless]; [main_window setAlphaValue:0.0]; [[main_window animator] setAlphaValue:1.0]; - + // temporarily set time interval for smooth updating during the pause [self installTimer:0.1]; } @@ -350,11 +322,10 @@ - (void)drawTimeLeft:(int)seconds { // displays next break - (void)drawNextBreak:(int)seconds { int minutes = round(seconds / 60.0) ; - + // nice hours, minutes ... if (minutes > 60) { - [next_break setStringValue:[NSString stringWithFormat:@"Next break in %d:%02d hours", - minutes / 60, minutes % 60]]; + [next_break setStringValue:[NSString stringWithFormat:@"Next break in %d:%02d hours", minutes / 60, minutes % 60]]; } else { [next_break setStringValue:[NSString stringWithFormat:@"Next break in %d minutes", minutes]]; } @@ -372,7 +343,6 @@ - (IBAction)breakNow:(id)sender { // validate menu items - (BOOL)validateMenuItem:(NSMenuItem *)menu { - if (menu == menuBreakNow || menu == dockBreakNow) { if (ai_can_continue_natural_break(core)) { [menu setTitle: @"Continue Work Break"]; @@ -381,11 +351,11 @@ - (BOOL)validateMenuItem:(NSMenuItem *)menu { } return core->state == S_NORMAL; } - + if (menu == menuPostpone || menu == dockPostpone) { return core->state == S_IN_WORK; } - + return [super validateMenuItem:menu]; } @@ -394,10 +364,8 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification // make sure timer doesn't tick once more ... draw_dock_image_q = NO; [mtimer invalidate]; - [mtimer autorelease]; mtimer = nil; - [dock_image release]; - + // and make sure to show original dock image [NSApp setApplicationIconImage: original_dock_image]; } diff --git a/macosx/AntiRSIView.h b/macosx/AntiRSIView.h index a9e5f75..f0b76cf 100644 --- a/macosx/AntiRSIView.h +++ b/macosx/AntiRSIView.h @@ -1,5 +1,5 @@ /* - * author: Onne Gorter + * author: Onne Gorter , Jahn Bertsch * package: antirsi-macosx * license: GPL */ @@ -13,4 +13,3 @@ AntiRSIView: NSVisualEffectView {} @interface AntiRSIButton: NSButton {} @end - diff --git a/macosx/English.lproj/Main.xib b/macosx/English.lproj/Main.xib index 56d6b33..737ad89 100644 --- a/macosx/English.lproj/Main.xib +++ b/macosx/English.lproj/Main.xib @@ -546,7 +546,7 @@ - + diff --git a/macosx/main.m b/macosx/main.m index d5ad89c..1d383fa 100644 --- a/macosx/main.m +++ b/macosx/main.m @@ -1,5 +1,5 @@ /* - * author: Onne Gorter + * author: Onne Gorter , Jahn Bertsch * package: antirsi-macosx * license: GPL */