├── AUTHORS ├── macosx ├── AntiRSI.icns ├── English.lproj │ └── InfoPlist.strings ├── Makefile ├── AntiRSI_Prefix.pch ├── main.m ├── AntiRSIView.h ├── version.plist ├── Info.plist ├── AntiRSIView.m ├── AntiRSI.h ├── AntiRSI.m └── AntiRSI.xcodeproj │ └── project.pbxproj ├── Makefile ├── gnome ├── break-window.h ├── app.h ├── antirsi-applet.h ├── status-display.h ├── Makefile ├── antirsi-applet.server ├── status-display.c ├── app.c ├── antirsi-applet.c └── break-window.c ├── antirsi-core ├── antirsi-core.h └── antirsi-core.c └── COPYING /AUTHORS: -------------------------------------------------------------------------------- 1 | Onne Gorter 2 | Nicholas Riley -------------------------------------------------------------------------------- /macosx/AntiRSI.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onnlucky/AntiRSI/HEAD/macosx/AntiRSI.icns -------------------------------------------------------------------------------- /macosx/English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onnlucky/AntiRSI/HEAD/macosx/English.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /macosx/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | xcodebuild 3 | 4 | run: all 5 | open build/Default/AntiRSI.app 6 | 7 | clean: 8 | rm -rf build/ 9 | 10 | .PHONY:all run clean 11 | -------------------------------------------------------------------------------- /macosx/AntiRSI_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'AntiRSI' target in the 'AntiRSI' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /macosx/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-macosx 4 | * license: GPL 5 | */ 6 | 7 | #import 8 | 9 | int main(int argc, const char *argv[]) { 10 | return NSApplicationMain(argc, argv); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /macosx/AntiRSIView.h: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-macosx 4 | * license: GPL 5 | */ 6 | 7 | #import 8 | 9 | @interface AntiRSIView : NSView { } @end 10 | @interface AntiRSIButton : NSButton { } @end 11 | 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BASE=gnome 2 | 3 | ifeq ($(shell uname), Linux) 4 | BASE=gnome 5 | endif 6 | 7 | ifeq ($(shell uname), Darwin) 8 | BASE=macosx 9 | endif 10 | 11 | all: 12 | cd $(BASE) && make all 13 | 14 | run: 15 | cd $(BASE) && make run 16 | 17 | install: 18 | cd $(BASE) && make install 19 | 20 | uninstall: 21 | cd $(BASE) && make uninstall 22 | 23 | clean: 24 | cd gnome && make clean 25 | cd macosx && make clean 26 | 27 | .PHONY:all run clean install uninstall 28 | -------------------------------------------------------------------------------- /gnome/break-window.h: -------------------------------------------------------------------------------- 1 | #ifndef _break_window_h_ 2 | #define _break_window_h_ 3 | 4 | /* 5 | * author: Onne Gorter 6 | * package: antirsi-gnome 7 | * license: GPL 8 | */ 9 | 10 | #include "app.h" 11 | 12 | void handle_mini_break_start(gpointer data); 13 | void handle_work_break_start(gpointer data); 14 | void handle_break_end(gpointer data); 15 | void handle_break_update(gpointer data); 16 | 17 | void break_window_create(app_context * app); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /macosx/version.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildVersion 6 | 17 7 | CFBundleShortVersionString 8 | 0.1 9 | CFBundleVersion 10 | 0.1 11 | ProjectName 12 | NibPBTemplates 13 | SourceVersion 14 | 1150000 15 | 16 | 17 | -------------------------------------------------------------------------------- /macosx/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | AntiRSI 9 | CFBundleIconFile 10 | AntiRSI.icns 11 | CFBundleIdentifier 12 | com.onnlucky.antirsi 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundlePackageType 16 | APPL 17 | CFBundleSignature 18 | ONNE 19 | CFBundleVersion 20 | ${APPLICATION_VERSION} 21 | NSMainNibFile 22 | MainMenu 23 | NSPrincipalClass 24 | NSApplication 25 | 26 | 27 | -------------------------------------------------------------------------------- /gnome/app.h: -------------------------------------------------------------------------------- 1 | #ifndef _app_h_ 2 | #define _app_h_ 3 | 4 | // #define DEBUG 5 | 6 | /* 7 | * author: Onne Gorter 8 | * package: antirsi-gnome 9 | * license: GPL 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../antirsi-core/antirsi-core.h" 17 | 18 | typedef struct _app_context { 19 | // debug window 20 | GtkWidget *window; 21 | GtkWidget *mini_label; 22 | GtkWidget *work_label; 23 | GtkWidget *status_label; 24 | GtkWidget *history_label; 25 | 26 | // mini or work break window and widgets 27 | GtkWidget *break_window; 28 | GtkWidget *break_type_label; 29 | GtkWidget *time_left_label; 30 | GtkWidget *time_until_label; 31 | GtkWidget *progress_bar; 32 | GtkWidget *postpone_button; 33 | 34 | // status display 35 | GtkWidget *status_display; 36 | 37 | // timer driving the ticks 38 | gint timer; 39 | 40 | // the low level antirsi core 41 | ai_core * core; 42 | 43 | } app_context; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /gnome/antirsi-applet.h: -------------------------------------------------------------------------------- 1 | #ifndef _antirsi_applet_h_ 2 | #define _antirsi_applet_h_ 3 | 4 | /* 5 | * author: Onne Gorter 6 | * package: antirsi-gnome 7 | * license: GPL 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | G_BEGIN_DECLS 14 | 15 | #define TYPE_ANTIRSI_APPLET antirsi_applet_get_type() 16 | #define ANTIRSI_APPLET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_ANTIRSI_APPLET, AntiRSIApplet)) 17 | #define ANTIRSI_APPLET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_ANTIRSI_APPLET, AntiRSIAppletClass)) 18 | #define IS_ANTIRSI_APPLET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_ANTIRSI_APPLET)) 19 | #define IS_ANTIRSI_APPLET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_ANTIRSI_APPLET)) 20 | #define ANTIRSI_APPLET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_ANTIRSI_APPLET, AntiRSIAppletClass)) 21 | 22 | typedef struct { 23 | PanelApplet parent; 24 | } AntiRSIApplet; 25 | 26 | typedef struct { 27 | PanelAppletClass parent_class; 28 | } AntiRSIAppletClass; 29 | 30 | GType antirsi_applet_get_type (void); 31 | 32 | AntiRSIApplet * antirsi_applet_new (void); 33 | 34 | G_END_DECLS 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /gnome/status-display.h: -------------------------------------------------------------------------------- 1 | #ifndef _status_display_h_ 2 | #define _status_display_h_ 3 | 4 | /* 5 | * author: Onne Gorter 6 | * package: antirsi-gnome 7 | * license: GPL 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include "../antirsi-core/antirsi-core.h" 14 | 15 | G_BEGIN_DECLS 16 | 17 | #define TYPE_STATUS_DISPLAY (status_display_get_type ()) 18 | #define STATUS_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_STATUS_DISPLAY, StatusDisplay)) 19 | #define STATUS_DISPLAY_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), STATUS_DISPLAY, StatusDisplayClass)) 20 | #define IS_STATUS_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_STATUS_DISPLAY)) 21 | #define IS_STATUS_DISPLAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), TYPE_STATUS_DISPLAY)) 22 | #define STATUS_DISPLAY_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_STATUS_DISPLAY, StatusDisplayClass)) 23 | 24 | typedef struct { 25 | GtkDrawingArea parent; 26 | } StatusDisplay; 27 | 28 | typedef struct { 29 | GtkDrawingAreaClass parent_class; 30 | } StatusDisplayClass; 31 | 32 | GType status_display_get_type (void); 33 | 34 | GtkWidget * status_display_new(ai_core *core); 35 | void status_display_update(GtkWidget *status_display); 36 | 37 | G_END_DECLS 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /gnome/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-g -c -Wall `pkg-config --cflags gtk+-2.0` `pkg-config --cflags libpanelapplet-2.0` -std=c99 3 | LDFLAGS=`pkg-config --libs gtk+-2.0` `pkg-config --libs libpanelapplet-2.0` -lXss -lm 4 | PREFIX=/usr 5 | 6 | SOURCES=../antirsi-core/antirsi-core.c break-window.c status-display.c 7 | HEADERS=../antirsi-core/antirsi-core.h app.h break-window.h status-display.h antirsi-applet.h 8 | OBJECTS=$(SOURCES:.c=.o) 9 | 10 | EXECUTABLE=antirsi-applet 11 | TEST_EXECUTABLE=antirsi 12 | 13 | all: $(SOURCES) $(EXECUTABLE) 14 | 15 | test: $(SOURCES) app.c $(TEST_EXECUTABLE) 16 | 17 | run: $(EXECUTABLE) 18 | ./$(EXECUTABLE) 19 | 20 | test-run: $(TEST_EXECUTABLE) 21 | ./$(TEST_EXECUTABLE) 22 | 23 | $(EXECUTABLE): $(OBJECTS) antirsi-applet.o 24 | $(CC) $(LDFLAGS) $(OBJECTS) antirsi-applet.o -o $@ 25 | 26 | $(TEST_EXECUTABLE): $(OBJECTS) app.o 27 | $(CC) $(LDFLAGS) $(OBJECTS) app.o -o $@ 28 | 29 | .c.o: $(HEADERS) 30 | $(CC) $(CFLAGS) $< -o $@ 31 | 32 | clean: 33 | rm -f *.o $(EXECUTABLE) $(TEST_EXECUTABLE) ../antirsi-core/*.o 34 | 35 | install: 36 | cp antirsi-applet $(PREFIX)/lib/gnome-panel/ 37 | cp antirsi-applet.server $(PREFIX)/lib/bonobo/servers/ 38 | 39 | uninstall: 40 | rm $(PREFIX)/lib/gnome-panel/antirsi-applet 41 | rm $(PREFIX)/lib/bonobo/servers/antirsi-applet.server 42 | 43 | .PHONY:all run clean install uninstall 44 | -------------------------------------------------------------------------------- /gnome/antirsi-applet.server: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /macosx/AntiRSIView.m: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-macosx 4 | * license: GPL 5 | */ 6 | 7 | #import "AntiRSIView.h" 8 | 9 | @implementation AntiRSIView 10 | 11 | - (void)drawRect:(NSRect)rect { 12 | NSColor *bgColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.85]; 13 | 14 | NSRect bgRect = [self frame]; 15 | int minX = NSMinX(bgRect); 16 | int midX = NSMidX(bgRect); 17 | int maxX = NSMaxX(bgRect); 18 | int minY = NSMinY(bgRect); 19 | int midY = NSMidY(bgRect); 20 | int maxY = NSMaxY(bgRect); 21 | 22 | // correct value to duplicate Panther's App Switcher 23 | float radius = 25.0; 24 | 25 | NSBezierPath *bgPath = [NSBezierPath bezierPath]; 26 | 27 | /* XXX from Casey Marshall's version; does it help with the hole-in-window problem? */ 28 | [[NSColor clearColor] set]; 29 | NSRectFill(bgRect); 30 | /* XXX end */ 31 | 32 | // Bottom edge and bottom-right curve 33 | [bgPath moveToPoint:NSMakePoint(midX, minY)]; 34 | [bgPath appendBezierPathWithArcFromPoint:NSMakePoint(maxX, minY) 35 | toPoint:NSMakePoint(maxX, midY) 36 | radius:radius]; 37 | 38 | // Right edge and top-right curve 39 | [bgPath appendBezierPathWithArcFromPoint:NSMakePoint(maxX, maxY) 40 | toPoint:NSMakePoint(midX, maxY) 41 | radius:radius]; 42 | 43 | // Top edge and top-left curve 44 | [bgPath appendBezierPathWithArcFromPoint:NSMakePoint(minX, maxY) 45 | toPoint:NSMakePoint(minX, midY) 46 | radius:radius]; 47 | 48 | // Left edge and bottom-left curve 49 | [bgPath appendBezierPathWithArcFromPoint:bgRect.origin 50 | toPoint:NSMakePoint(midX, minY) 51 | radius:radius]; 52 | [bgPath closePath]; 53 | 54 | [bgColor set]; 55 | [bgPath fill]; 56 | } 57 | 58 | @end 59 | 60 | 61 | @implementation AntiRSIButton 62 | 63 | // prevents AntiRSI activation on mouse down 64 | - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)e { 65 | return YES; 66 | } 67 | 68 | - (void)mouseDown:(NSEvent *)e { 69 | [NSApp preventWindowOrdering]; 70 | [super mouseDown: e]; 71 | } 72 | 73 | @end 74 | 75 | -------------------------------------------------------------------------------- /macosx/AntiRSI.h: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-macosx 4 | * license: GPL 5 | */ 6 | 7 | #import 8 | #import "AntiRSIView.h" 9 | 10 | #include "../antirsi-core/antirsi-core.h" 11 | 12 | #define sLatestVersionURL @"http://tech.inhelsinki.nl/antirsi/antirsi_version.txt" 13 | #define sURL @"http://tech.inhelsinki.nl/antirsi/" 14 | 15 | #define sMicroPause @"Micro Pause" 16 | #define sWorkBreak @"Work Break" 17 | 18 | @interface AntiRSI : NSObject 19 | { 20 | // views to display current status in 21 | IBOutlet AntiRSIView *view; 22 | IBOutlet NSProgressIndicator *progress; 23 | IBOutlet AntiRSIButton *postpone; 24 | IBOutlet NSTextField *label; 25 | IBOutlet NSTextField *time; 26 | IBOutlet NSTextField *next_break; 27 | IBOutlet NSTextField *version; 28 | 29 | IBOutlet NSMenuItem *menuBreakNow; 30 | IBOutlet NSMenuItem *dockBreakNow; 31 | IBOutlet NSMenuItem *menuPostpone; 32 | IBOutlet NSMenuItem *dockPostpone; 33 | 34 | // dock icon image 35 | NSImage* dock_image; 36 | NSImage* original_dock_image; 37 | 38 | // window to display the views in 39 | NSWindow *main_window; 40 | 41 | // timer that ticks every second to update 42 | NSTimer *mtimer; 43 | 44 | double sample_interval; 45 | 46 | // verious other options 47 | bool lock_focus; 48 | bool draw_dock_image; 49 | bool draw_dock_image_q; 50 | 51 | // various colors 52 | NSColor* taking; 53 | NSColor* elapsed; 54 | NSColor* background; 55 | NSColor* darkbackground; 56 | 57 | NSString *sVersion; 58 | 59 | ai_core * core; 60 | } 61 | 62 | //bindings 63 | - (void)setSample_interval:(NSString *)s; 64 | - (void)setDraw_dock_image:(BOOL)b; 65 | - (void)setBackground:(NSColor *)c; 66 | 67 | // goto website button 68 | - (IBAction)gotoWebsite:(id)sender; 69 | 70 | // check updates 71 | - (IBAction)checkForUpdate:(id)sender; 72 | 73 | // postpone button 74 | - (IBAction)postpone:(id)sender; 75 | 76 | // workbreak now menu item 77 | - (IBAction)breakNow:(id)sender; 78 | 79 | // one second ticks away ... 80 | - (void)tick:(NSTimer *)timer; 81 | 82 | // update break window 83 | - (void)drawBreakWindow; 84 | 85 | // draw the dock icon 86 | - (void)drawDockImage; 87 | 88 | // run the micro pause window 89 | - (void)doMicroPause; 90 | 91 | // run the work break window 92 | - (void)doWorkBreak; 93 | 94 | // stop micro pause or work break 95 | - (void)endBreak; 96 | 97 | // time left string 98 | - (void)drawTimeLeft:(int)seconds; 99 | 100 | // time to next break string 101 | - (void)drawNextBreak:(int)seconds; 102 | 103 | @end 104 | 105 | -------------------------------------------------------------------------------- /gnome/status-display.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-gnome 4 | * license: GPL 5 | */ 6 | 7 | #include 8 | 9 | #include "status-display.h" 10 | #include "../antirsi-core/antirsi-core.h" 11 | 12 | #define STATUS_DISPLAY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TYPE_STATUS_DISPLAY, StatusDisplayPrivate)) 13 | 14 | G_DEFINE_TYPE(StatusDisplay, status_display, GTK_TYPE_DRAWING_AREA); 15 | 16 | typedef struct _StatusDisplayPrivate StatusDisplayPrivate; 17 | struct _StatusDisplayPrivate { 18 | ai_core * core; 19 | }; 20 | 21 | #define DRAW_TRESHOLD 0.0001 22 | 23 | static void 24 | draw(GtkWidget *status_display, cairo_t *cr) 25 | { 26 | StatusDisplayPrivate *priv; 27 | int width = status_display->allocation.width; 28 | int height = status_display->allocation.height; 29 | 30 | priv = STATUS_DISPLAY_GET_PRIVATE(status_display); 31 | double tmp; 32 | 33 | // whole widget 34 | GdkColor bc = status_display->style->bg[GTK_STATE_NORMAL]; 35 | cairo_rectangle(cr, 0, 0, width, height); 36 | cairo_set_source_rgb(cr, bc.red / 65536.0, bc.green / 65536.0, bc.blue / 65536.0); 37 | cairo_fill_preserve(cr); 38 | cairo_set_source_rgb(cr, bc.red / 62536.0, bc.green / 62536.0, bc.blue / 62536.0); 39 | cairo_stroke(cr); 40 | 41 | // mini break 42 | // elapsed 43 | tmp = priv->core->mini_t / priv->core->mini_interval; 44 | if (tmp > DRAW_TRESHOLD) { 45 | cairo_rectangle(cr, 1, (height / 40.0) * 4.0, (width - 1) * tmp, (height / 40.0) * 13.0); 46 | cairo_set_source_rgba(cr, 0.5, 0.5, 1, 0.8); 47 | cairo_fill_preserve(cr); 48 | cairo_set_source_rgba(cr, 0.4, 0.4, 1, 0.8); 49 | cairo_stroke(cr); 50 | } 51 | 52 | // natural 53 | tmp = priv->core->mini_taking_t / priv->core->mini_duration; 54 | if (tmp > DRAW_TRESHOLD) { 55 | cairo_rectangle(cr, 1, (height / 40.0) * 3.0, (width - 1) * tmp, (height / 40.0) * 16.0); 56 | cairo_set_source_rgba(cr, 0.5, 1, 0.5, 0.8); 57 | cairo_fill_preserve(cr); 58 | cairo_set_source_rgba(cr, 0.4, 1, 0.4, 0.8); 59 | cairo_stroke(cr); 60 | } 61 | 62 | // work break 63 | // elapsed 64 | tmp = priv->core->work_t / priv->core->work_interval; 65 | if (tmp > DRAW_TRESHOLD) { 66 | cairo_rectangle(cr, 1, (height / 40.0) * 23.0, (width - 1) * tmp, (height / 40.0) * 13.0); 67 | cairo_set_source_rgba(cr, 0.5, 0.5, 1, 0.8); 68 | cairo_fill_preserve(cr); 69 | cairo_set_source_rgba(cr, 0.4, 0.4, 1, 0.8); 70 | cairo_stroke(cr); 71 | } 72 | 73 | // natural 74 | tmp = priv->core->work_taking_t / priv->core->work_duration; 75 | if (tmp > DRAW_TRESHOLD) { 76 | cairo_rectangle(cr, 1, (height / 40.0) * 21.0, (width - 1) * tmp, (height / 40.0) * 16.0); 77 | cairo_set_source_rgba(cr, 0.5, 1, 0.5, 0.8); 78 | cairo_fill_preserve(cr); 79 | cairo_set_source_rgba(cr, 0.4, 1, 0.4, 0.8); 80 | cairo_stroke(cr); 81 | } 82 | } 83 | 84 | static gboolean 85 | status_display_expose(GtkWidget *status_display, GdkEventExpose *event) 86 | { 87 | cairo_t *cr; 88 | 89 | cr = gdk_cairo_create(status_display->window); 90 | 91 | draw(status_display, cr); 92 | 93 | cairo_destroy(cr); 94 | 95 | return FALSE; 96 | } 97 | 98 | void 99 | status_display_update(GtkWidget *status_display) 100 | { 101 | status_display_expose(status_display, NULL); 102 | } 103 | 104 | static void 105 | status_display_class_init(StatusDisplayClass *class) 106 | { 107 | GObjectClass *obj_class; 108 | GtkWidgetClass *widget_class; 109 | 110 | obj_class = G_OBJECT_CLASS(class); 111 | widget_class = GTK_WIDGET_CLASS(class); 112 | 113 | widget_class->expose_event = status_display_expose; 114 | 115 | g_type_class_add_private(obj_class, sizeof(StatusDisplayPrivate)); 116 | } 117 | 118 | static void 119 | status_display_init(StatusDisplay *status_display) 120 | { 121 | gtk_widget_set_size_request(GTK_WIDGET(status_display), 16, 24); 122 | } 123 | 124 | GtkWidget * 125 | status_display_new(ai_core *core) 126 | { 127 | StatusDisplay *status_display = g_object_new(TYPE_STATUS_DISPLAY, NULL); 128 | StatusDisplayPrivate *priv = STATUS_DISPLAY_GET_PRIVATE(status_display); 129 | 130 | priv->core = core; 131 | 132 | return GTK_WIDGET(status_display); 133 | } 134 | 135 | -------------------------------------------------------------------------------- /gnome/app.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-gnome 4 | * license: GPL 5 | * 6 | * 7 | * TODO 8 | * status bar plugin 9 | * 10 | * settings window / gconf configuration 11 | * 12 | * make window always on top of everything, currently it doesn't move anymore then 13 | */ 14 | 15 | #include "app.h" 16 | 17 | #include 18 | #include 19 | 20 | #include "break-window.h" 21 | #include "status-display.h" 22 | 23 | static double 24 | get_idle_time(app_context *app) 25 | { 26 | XScreenSaverInfo * sc_info; 27 | double idle_time; 28 | 29 | sc_info = XScreenSaverAllocInfo(); 30 | XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), sc_info); 31 | idle_time = sc_info->idle / 1000.0; 32 | free(sc_info); 33 | 34 | return idle_time; 35 | } 36 | 37 | static gboolean 38 | delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) 39 | { 40 | return FALSE; 41 | } 42 | 43 | static void 44 | destroy(GtkWidget *widget, gpointer data) 45 | { 46 | gtk_main_quit(); 47 | } 48 | 49 | gint 50 | app_tick(gpointer data) 51 | { 52 | char * tmp; 53 | app_context * app = (app_context *)data; 54 | 55 | ai_tick(app->core, get_idle_time(app)); 56 | 57 | tmp = g_strdup_printf("mini: %2.2f; %2.2f", app->core->mini_t, app->core->mini_taking_t); 58 | gtk_label_set_text(GTK_LABEL(app->mini_label), tmp); 59 | g_free(tmp); 60 | 61 | tmp = g_strdup_printf("work: %2.2f; %2.2f", app->core->work_t, app->core->work_taking_t); 62 | gtk_label_set_text(GTK_LABEL(app->work_label), tmp); 63 | g_free(tmp); 64 | 65 | tmp = g_strdup_printf("state: %s", (app->core->state == S_NORMAL)?"normal":(app->core->state == S_IN_MINI)?"mini":"work"); 66 | gtk_label_set_text(GTK_LABEL(app->status_label), tmp); 67 | g_free(tmp); 68 | 69 | tmp = g_strdup_printf("history: %1.1f, %1.1f, %1.1f, %1.1f", app->core->ith[0], app->core->ith[1], app->core->ith[2], app->core->ith[3]); 70 | gtk_label_set_text(GTK_LABEL(app->history_label), tmp); 71 | g_free(tmp); 72 | 73 | status_display_update(app->status_display); 74 | 75 | return TRUE; 76 | } 77 | 78 | int 79 | main(int argc, char * argv[]) 80 | { 81 | app_context * app; 82 | app = g_new0(app_context, 1); 83 | 84 | GtkWidget *vbox; 85 | 86 | gtk_init(&argc, &argv); 87 | app->core = antirsi_init(app); 88 | 89 | //app->core->emit_status_update = handle_status_update; 90 | 91 | app->core->emit_mini_break_start = handle_mini_break_start; 92 | app->core->emit_work_break_start = handle_work_break_start; 93 | app->core->emit_break_end = handle_break_end; 94 | app->core->emit_break_update = handle_break_update; 95 | 96 | #ifdef DEBUG 97 | app->core->mini_duration = 4; // 14; 98 | app->core->mini_interval = 10; // 4*60; 99 | app->core->work_duration = 20; // 8*50 100 | app->core->work_interval = 60 * 300; // 50*60; 101 | #endif 102 | 103 | app->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 104 | gtk_window_set_title(GTK_WINDOW(app->window), "AntiRSI"); 105 | 106 | app->mini_label = gtk_label_new("mini: 0; 0"); 107 | app->work_label = gtk_label_new("work: 0; 0"); 108 | app->status_label = gtk_label_new("status: normal"); 109 | app->history_label = gtk_label_new("history: 0, 0, 0, 0"); 110 | app->status_display = status_display_new(app->core); 111 | 112 | g_signal_connect(G_OBJECT(app->window), "delete_event", G_CALLBACK(delete_event), app); 113 | g_signal_connect(G_OBJECT(app->window), "destroy", G_CALLBACK(destroy), app); 114 | 115 | vbox = gtk_vbox_new(FALSE, 4); 116 | 117 | gtk_container_add(GTK_CONTAINER(vbox), app->mini_label); 118 | gtk_container_add(GTK_CONTAINER(vbox), app->work_label); 119 | gtk_container_add(GTK_CONTAINER(vbox), app->status_label); 120 | gtk_container_add(GTK_CONTAINER(vbox), app->history_label); 121 | gtk_container_add(GTK_CONTAINER(vbox), app->status_display); 122 | 123 | gtk_container_add(GTK_CONTAINER(app->window), vbox); 124 | 125 | app->timer = g_timeout_add(100, app_tick, app); 126 | 127 | break_window_create(app); 128 | 129 | gtk_widget_show_all(app->window); 130 | 131 | #ifdef DEBUG 132 | gtk_widget_show_all(app->break_window); 133 | #endif 134 | 135 | gtk_main(); 136 | 137 | return 0; 138 | } 139 | 140 | -------------------------------------------------------------------------------- /antirsi-core/antirsi-core.h: -------------------------------------------------------------------------------- 1 | #ifndef _antirsi_core_h_ 2 | #define _antirsi_core_h_ 3 | 4 | /* 5 | * author: Onne Gorter 6 | * package: antirsi-core 7 | * license: GPL 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /** the state antirsi is in */ 18 | typedef enum { 19 | S_NORMAL = 1, 20 | S_IN_MINI, 21 | S_IN_WORK 22 | } ai_state; 23 | 24 | /** a global context for the core */ 25 | typedef struct _ai_core { 26 | void * user_data; 27 | 28 | double time; 29 | 30 | // breaks 31 | /** time since last mini break */ 32 | double mini_t; 33 | /** time the user has been taking a mini break */ 34 | double mini_taking_t; 35 | /** time since last work break */ 36 | double work_t; 37 | /** time the user has been taking a work break */ 38 | double work_taking_t; 39 | 40 | // natural break continuation 41 | /** last #work_taking_t, for natural break continuation */ 42 | double last_work_taking_t; 43 | /** time when last natural work break was stopped */ 44 | double last_work_taking_t_countdown; 45 | 46 | // settings 47 | /** the time between mini breaks */ 48 | int mini_interval; 49 | /** the time a mini break lasts */ 50 | int mini_duration; 51 | /** the time between work breaks */ 52 | int work_interval; 53 | /** the time a work break lasts */ 54 | int work_duration; 55 | /** the time postpone will set #work_t back */ 56 | int postpone_time; 57 | 58 | /** 1 if no mini breaks are to be issues, 0 otherwise */ 59 | int mini_disabled; 60 | /** 1 if no work breaks are to be issues, 0 otherwise */ 61 | int work_disabled; 62 | 63 | // state 64 | ai_state state; 65 | double ith[4]; // history filter 66 | 67 | // library exit functions 68 | /** 69 | * when a break is over, this function is called 70 | * 71 | * The function will only be called if the function pointer is not NULL (default) 72 | * the user data set with #antirsi_init is passed to the function 73 | */ 74 | void (*emit_break_end)(void * data); 75 | /** when a mini break is starting; see #emit_break_end */ 76 | void (*emit_mini_break_start)(void * data); 77 | /** when a work break is starting; see #emit_break_end */ 78 | void (*emit_work_break_start)(void * data); 79 | /** everytime a tick has been processed, and we are in a break, this function is called; see #emit_break_end */ 80 | void (*emit_break_update)(void * data); 81 | /** everytime a tick has been processed, this function is called; see #emit_break_end */ 82 | void (*emit_status_update)(void * data); 83 | 84 | } ai_core; 85 | 86 | /** returns the seconds until the next work break */ 87 | int ai_seconds_until_next_work_break(ai_core * c); 88 | /** returns the seconds the current break lasts */ 89 | int ai_break_time_left(ai_core * c); 90 | /** returns double between 0 and 1, indicating the progress of the break; 0 is just starting, 1 is done */ 91 | double ai_break_progress(ai_core * c); 92 | /** will postpone the current break #ai_core->postpone_time */ 93 | void ai_work_break_postpone(ai_core *c); 94 | /** will initiate a work break right now */ 95 | void ai_work_break_now(ai_core *c); 96 | 97 | // natural break continuation 98 | /** 1 if a natural work break continuation is available, 0 otherwise */ 99 | int ai_can_continue_natural_break(ai_core *c); 100 | /** continue a natural work break, use this instead of #ai_work_break_now */ 101 | void ai_continue_natural_work_break(ai_core *c); 102 | 103 | /** 104 | * makes the core go one step, calculating times spend, idle time and then the new state/times 105 | * this function will call appropriate functions like #emit_break_end and such when necesairy. 106 | * Notice that these functions will only be called when the have been set: 107 | * @example 108 | * @code 109 | * static void handle_break_end(void * data){ 110 | * fprintf(stderr, "handle_break_end\n"); 111 | * } 112 | * 113 | * main { 114 | * ai_core * core; 115 | * ... 116 | * core->emit_break_end = handle_break_end; 117 | * ... 118 | * } 119 | * @code 120 | * 121 | * provide the current idle time (#idle_time) and antirsi context #ai_core 122 | */ 123 | void ai_tick(ai_core * c, double idle_time); 124 | 125 | /** 126 | * initialize antirsi core, #data will be used in all callbacks the library makes 127 | */ 128 | ai_core * antirsi_init(void * data); 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /gnome/antirsi-applet.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-gnome 4 | * license: GPL 5 | * 6 | * TODO 7 | * fix unexpected quit ... 8 | * add about/help/configuration 9 | * add break now / postpone break and natural break menu 10 | * remove app.h and put antirsi-applet.h with struct 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | #include "status-display.h" 17 | #include "break-window.h" 18 | #include "app.h" 19 | 20 | #include "antirsi-applet.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | static double 27 | get_idle_time(app_context *app) 28 | { 29 | XScreenSaverInfo * sc_info; 30 | double idle_time; 31 | 32 | sc_info = XScreenSaverAllocInfo(); 33 | XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), sc_info); 34 | idle_time = sc_info->idle / 1000.0; 35 | free(sc_info); 36 | 37 | return idle_time; 38 | } 39 | 40 | gint 41 | app_tick(gpointer data) 42 | { 43 | app_context * app = (app_context *)data; 44 | 45 | ai_tick(app->core, get_idle_time(app)); 46 | status_display_update(app->status_display); 47 | 48 | return TRUE; 49 | } 50 | 51 | G_DEFINE_TYPE (AntiRSIApplet, antirsi_applet, PANEL_TYPE_APPLET); 52 | 53 | static void antirsi_applet_change_background(PanelApplet *applet, PanelAppletBackgroundType type, 54 | GdkColor *colour, GdkPixmap *pixmap); 55 | 56 | static void 57 | antirsi_applet_class_init(AntiRSIAppletClass *klass) 58 | { 59 | } 60 | 61 | static void 62 | antirsi_applet_init(AntiRSIApplet *self) 63 | { 64 | g_signal_connect(self, "change-background", G_CALLBACK (antirsi_applet_change_background), NULL); 65 | } 66 | 67 | AntiRSIApplet* 68 | antirsi_applet_new(void) 69 | { 70 | return g_object_new (TYPE_ANTIRSI_APPLET, NULL); 71 | } 72 | 73 | static void 74 | antirsi_applet_change_background(PanelApplet *applet, PanelAppletBackgroundType type, 75 | GdkColor *colour, GdkPixmap *pixmap) 76 | { 77 | GtkRcStyle *rc_style; 78 | GtkStyle *style; 79 | 80 | /* reset style */ 81 | gtk_widget_set_style (GTK_WIDGET (applet), NULL); 82 | rc_style = gtk_rc_style_new (); 83 | gtk_widget_modify_style (GTK_WIDGET (applet), rc_style); 84 | gtk_rc_style_unref (rc_style); 85 | 86 | switch (type){ 87 | case PANEL_NO_BACKGROUND: 88 | break; 89 | case PANEL_COLOR_BACKGROUND: 90 | gtk_widget_modify_bg (GTK_WIDGET (applet), 91 | GTK_STATE_NORMAL, colour); 92 | break; 93 | case PANEL_PIXMAP_BACKGROUND: 94 | style = gtk_style_copy (GTK_WIDGET (applet)->style); 95 | 96 | if (style->bg_pixmap[GTK_STATE_NORMAL]) 97 | g_object_unref (style->bg_pixmap[GTK_STATE_NORMAL]); 98 | 99 | style->bg_pixmap[GTK_STATE_NORMAL] = g_object_ref (pixmap); 100 | gtk_widget_set_style (GTK_WIDGET (applet), style); 101 | g_object_unref (style); 102 | break; 103 | } 104 | } 105 | 106 | static const BonoboUIVerb antirsi_applet_menu_verbs [] = { 107 | // BONOBO_UI_UNSAFE_VERB ("Prefs", preferences_cb), 108 | // BONOBO_UI_UNSAFE_VERB ("Help", help_cb), 109 | // BONOBO_UI_UNSAFE_VERB ("About", about_cb), 110 | 111 | BONOBO_UI_VERB_END 112 | }; 113 | 114 | static const char context_menu_xml [] = 115 | "\n" 116 | " \n" 121 | " \n" 126 | " \n" 131 | " \n" 136 | "\n"; 137 | 138 | static gboolean 139 | antirsi_applet_fill(PanelApplet *applet) 140 | { 141 | g_debug("starting antirsi-applet"); 142 | 143 | AntiRSIApplet *antirsi_applet; 144 | 145 | g_return_val_if_fail(PANEL_IS_APPLET (applet), FALSE); 146 | 147 | app_context * app; 148 | app = g_new0(app_context, 1); 149 | 150 | app->core = antirsi_init(app); 151 | 152 | app->core->emit_mini_break_start = handle_mini_break_start; 153 | app->core->emit_work_break_start = handle_work_break_start; 154 | app->core->emit_break_end = handle_break_end; 155 | app->core->emit_break_update = handle_break_update; 156 | 157 | app->timer = g_timeout_add(100, app_tick, app); 158 | 159 | app->status_display = status_display_new(app->core); 160 | 161 | gtk_container_add(GTK_CONTAINER(applet), app->status_display); 162 | 163 | break_window_create(app); 164 | 165 | gtk_widget_show_all(GTK_WIDGET (applet)); 166 | 167 | 168 | panel_applet_setup_menu(applet, context_menu_xml, antirsi_applet_menu_verbs, antirsi_applet); 169 | 170 | if (panel_applet_get_locked_down (applet)) { 171 | BonoboUIComponent *popup_component; 172 | 173 | popup_component = panel_applet_get_popup_component (applet); 174 | 175 | bonobo_ui_component_set_prop (popup_component, 176 | "/commands/Props", 177 | "hidden", "1", 178 | NULL); 179 | } 180 | 181 | return TRUE; 182 | } 183 | 184 | static gboolean 185 | antirsi_applet_factory (PanelApplet *applet, 186 | const gchar *iid, 187 | gpointer data) 188 | { 189 | g_debug("antirsi applet factory"); 190 | gboolean retval = FALSE; 191 | 192 | if (!strcmp (iid, "OAFIID:AntiRSIApplet")) 193 | retval = antirsi_applet_fill (applet); 194 | 195 | if (retval == FALSE) { 196 | exit (-1); 197 | } 198 | 199 | return retval; 200 | } 201 | 202 | PANEL_APPLET_BONOBO_FACTORY ("OAFIID:AntiRSIApplet_Factory", 203 | TYPE_ANTIRSI_APPLET, 204 | "antirsi-applet", 205 | "0", 206 | antirsi_applet_factory, 207 | NULL) 208 | 209 | 210 | -------------------------------------------------------------------------------- /antirsi-core/antirsi-core.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-core 4 | * license: GPL 5 | * 6 | * TODO 7 | * mini or work break should both be allowed to be disabled using extra boolean ... 8 | * 9 | * emit lock focus and have setting for it 10 | * 11 | * implement a smarter algorithm for setting and predicting breaks, 12 | * maybe include scheduling static events, like tee or food and end of work day ... 13 | */ 14 | 15 | #include "antirsi-core.h" 16 | 17 | int 18 | ai_seconds_until_next_work_break(ai_core * c) 19 | { 20 | if (c->state == S_IN_WORK) { 21 | return c->work_duration + c->work_interval - c->work_taking_t; 22 | } 23 | 24 | return c->work_interval - c->work_t; 25 | } 26 | 27 | int 28 | ai_break_time_left(ai_core * c) 29 | { 30 | switch (c->state) { 31 | case S_IN_MINI: 32 | return c->mini_duration - c->mini_taking_t; 33 | case S_IN_WORK: 34 | return c->work_duration - c->work_taking_t; 35 | default: 36 | return 0; 37 | } 38 | } 39 | 40 | double 41 | ai_break_progress(ai_core * c) 42 | { 43 | switch (c->state) { 44 | case S_IN_MINI: 45 | return 1.0 * c->mini_taking_t / c->mini_duration; 46 | case S_IN_WORK: 47 | return 1.0 * c->work_taking_t / c->work_duration; 48 | default: 49 | return 0.0; 50 | } 51 | } 52 | 53 | void 54 | ai_work_break_postpone(ai_core *c) 55 | { 56 | c->mini_t = 0; 57 | c->mini_taking_t = 0; 58 | 59 | c->work_t = c->work_interval - c->postpone_time; 60 | if (c->work_t < 0) c->work_t = 0; 61 | c->work_taking_t = 0; 62 | 63 | c->state = S_NORMAL; 64 | 65 | if (c->emit_break_end) c->emit_break_end(c->user_data); 66 | } 67 | 68 | void 69 | ai_work_break_now(ai_core *c) 70 | { 71 | // implicit natural work break, shouldn't use it, but for older clients 72 | if (c->last_work_taking_t_countdown > 0 && c->work_taking_t < c->last_work_taking_t) { 73 | c->work_taking_t = c->last_work_taking_t; 74 | } 75 | 76 | c->state = S_IN_WORK; 77 | 78 | if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); 79 | } 80 | 81 | int 82 | ai_can_continue_natural_break(ai_core *c) 83 | { 84 | return c->last_work_taking_t_countdown > 0; 85 | } 86 | 87 | void 88 | ai_continue_natural_work_break(ai_core *c) 89 | { 90 | if (c->work_taking_t < c->last_work_taking_t) { 91 | c->work_taking_t = c->last_work_taking_t; 92 | } 93 | c->state = S_IN_WORK; 94 | 95 | if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); 96 | } 97 | 98 | void 99 | ai_tick(ai_core * c, double idle_time) 100 | { 101 | double new_time; 102 | double delta; 103 | 104 | struct timeval tv; 105 | int slack; 106 | 107 | if (gettimeofday(&tv, 0) != 0) { 108 | fprintf(stderr, "no gettimeofday\n"); 109 | return; 110 | } 111 | 112 | new_time = tv.tv_sec + (tv.tv_usec / 1000000.0); 113 | delta = new_time - c->time; 114 | 115 | // too fast, or initial run 116 | if (delta < 0.0001) { 117 | fprintf(stderr, "going too fast! %f - %f = %f\n", new_time, c->time, delta); 118 | return; 119 | } 120 | 121 | c->time = new_time; 122 | 123 | //fprintf(stderr, "fps: %0.2f\n", 1.0/delta); 124 | 125 | // if there was a long sleep, handle that first 126 | if (delta > c->work_duration) { 127 | c->mini_t = 0; 128 | c->mini_taking_t = c->mini_duration; 129 | 130 | c->work_t = 0; 131 | c->work_taking_t = c->work_duration; 132 | 133 | if (c->state != S_NORMAL) { 134 | if (c->emit_break_end) c->emit_break_end(c->user_data); 135 | } 136 | 137 | // do stuff on next tick 138 | return; 139 | 140 | } else if (delta > c->mini_duration) { 141 | c->mini_t = 0; 142 | c->mini_taking_t = 0; 143 | 144 | if (c->state != S_NORMAL) { 145 | if (c->emit_break_end) c->emit_break_end(c->user_data); 146 | } 147 | 148 | // do stuff on next tick 149 | return; 150 | } 151 | 152 | // process idle time with a 4 history filter; at least four discrete events within 15 seconds 153 | // prevents media players and such to activate antirsi (does not prevent accidental mouse moving or similar!) 154 | if (c->ith[0] >= idle_time) { 155 | // new event 156 | c->ith[3] = c->ith[2]; 157 | c->ith[2] = c->ith[1]; 158 | c->ith[1] = c->ith[0]; 159 | } 160 | c->ith[0] = idle_time; 161 | 162 | slack = (c->ith[3] + c->ith[2] + c->ith[1] + c->ith[0]) > 15; 163 | 164 | switch (c->state) { 165 | case S_NORMAL: 166 | // count down the natural work break validity 167 | if (c->last_work_taking_t_countdown > 0) { 168 | c->last_work_taking_t_countdown -= delta; 169 | } 170 | 171 | if (idle_time <= c->mini_duration * 0.3 && !slack) { 172 | // the normal case, no slack, and not enough idle time 173 | c->mini_t += delta; 174 | c->mini_taking_t = 0; 175 | 176 | c->work_t += delta; 177 | c->work_taking_t = 0; 178 | } else { 179 | // there is either slack or idle time, so we are taking some natural break 180 | 181 | if (c->work_taking_t >= c->work_duration) { 182 | 183 | // idle time has passed work break 184 | c->mini_t = 0; 185 | 186 | c->work_t = 0; 187 | c->work_taking_t = c->work_duration; 188 | 189 | // natural work break no longer valid 190 | c->last_work_taking_t_countdown = 0; 191 | 192 | } else if (c->mini_taking_t >= c->mini_duration && c->work_t > 0) { 193 | 194 | // idle time has passed mini break 195 | c->mini_t = 0; 196 | c->mini_taking_t = c->mini_duration; 197 | c->work_taking_t += delta; 198 | 199 | // 30 second window for user to activate natural break continuation 200 | c->last_work_taking_t_countdown = 30; 201 | c->last_work_taking_t = c->work_taking_t; 202 | 203 | } else { 204 | // idle time has just kicked in 205 | c->mini_taking_t += delta; 206 | 207 | c->work_t += delta; 208 | c->work_taking_t = 0; 209 | } 210 | } 211 | 212 | if (c->mini_t >= c->mini_interval) { 213 | // need to take a mini break 214 | if (c->work_t > c->work_interval - (c->mini_interval / 2)) { 215 | 216 | c->state = S_IN_WORK; 217 | c->work_t = c->work_interval; 218 | 219 | if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); 220 | 221 | } else { 222 | 223 | c->state = S_IN_MINI; 224 | 225 | if (c->emit_mini_break_start) c->emit_mini_break_start(c->user_data); 226 | 227 | } 228 | } 229 | 230 | if (c->work_t >= c->work_interval) { 231 | // need to take a work break 232 | c->mini_t = 0; 233 | c->mini_taking_t = c->mini_duration; 234 | c->state = S_IN_WORK; 235 | 236 | if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); 237 | } 238 | 239 | break; 240 | 241 | case S_IN_MINI: 242 | // natural work break no longer valid 243 | c->last_work_taking_t_countdown = 0; 244 | 245 | c->mini_taking_t += delta; 246 | c->work_t += delta; 247 | 248 | if (idle_time < 1 && !slack) { // TODO remove the idle_time ? 249 | // we weren't breaking, so reset the break; 250 | c->mini_taking_t = 0; 251 | } 252 | 253 | // TODO emit redraws 254 | // TODO if (c->lock_focus) 255 | 256 | if (c->mini_taking_t > c->mini_duration) { 257 | // mini break is over 258 | c->mini_t = 0; 259 | c->mini_taking_t = c->mini_duration; 260 | 261 | if (c->emit_break_end) c->emit_break_end(c->user_data); 262 | 263 | c->state = S_NORMAL; 264 | } 265 | 266 | if (c->work_t >= c->work_interval) { 267 | // work break should start 268 | c->mini_t = 0; 269 | c->mini_taking_t = c->mini_duration; 270 | 271 | if (c->emit_work_break_start) c->emit_work_break_start(c->user_data); 272 | 273 | c->state = S_IN_WORK; 274 | } 275 | 276 | if (c->emit_break_update) c->emit_break_update(c->user_data); 277 | 278 | break; 279 | 280 | case S_IN_WORK: 281 | // natural work break no longer valid 282 | c->last_work_taking_t_countdown = 0; 283 | 284 | if (idle_time >= 4 || slack) { 285 | // only when idle for 4 seconds, or there is some slack 286 | c->work_taking_t += delta; 287 | } 288 | 289 | // TODO emit redraws 290 | // TODO if (c->lock_focus) 291 | 292 | if (c->work_taking_t > c->work_duration) { 293 | // work break is over 294 | c->mini_t = 0; 295 | c->mini_taking_t = c->mini_duration; 296 | 297 | c->work_t = 0; 298 | c->work_taking_t = c->work_duration; 299 | 300 | if (c->emit_break_end) c->emit_break_end(c->user_data); 301 | 302 | c->state = S_NORMAL; 303 | } 304 | 305 | if (c->emit_break_update) c->emit_break_update(c->user_data); 306 | 307 | break; 308 | } 309 | 310 | if (c->emit_status_update) c->emit_status_update(c->user_data); 311 | } 312 | 313 | ai_core * 314 | antirsi_init(void * data) 315 | { 316 | ai_core * c = malloc(sizeof(ai_core)); 317 | memset(c, 0, sizeof(ai_core)); 318 | 319 | c->user_data = data; 320 | 321 | c->time = time(0); 322 | 323 | // default settings 324 | c->mini_duration = 14; 325 | c->mini_interval = 4*60; 326 | c->work_duration = 8*60; 327 | c->work_interval = 50*60; 328 | c->postpone_time = 10*60; 329 | 330 | c->state = S_NORMAL; 331 | 332 | return c; 333 | } 334 | 335 | -------------------------------------------------------------------------------- /gnome/break-window.c: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-gnome 4 | * license: GPL 5 | */ 6 | 7 | #include "break-window.h" 8 | 9 | gboolean handle_expose(GtkWidget *widget, GdkEventExpose *event, gpointer userdata); 10 | 11 | static void 12 | handle_postpone_clicked(GtkWidget * widget, gpointer data) 13 | { 14 | app_context * app = (app_context *)data; 15 | 16 | ai_work_break_postpone(app->core); 17 | } 18 | 19 | void 20 | handle_mini_break_start(gpointer data) 21 | { 22 | app_context * app = (app_context *)data; 23 | 24 | gtk_label_set_markup(GTK_LABEL(app->break_type_label), "Mini Break"); 25 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(app->progress_bar), 0); 26 | 27 | gtk_window_set_position(GTK_WINDOW(app->break_window), GTK_WIN_POS_CENTER); 28 | 29 | gtk_widget_show_all(app->break_window); 30 | gtk_widget_hide(app->postpone_button); 31 | 32 | gtk_window_stick(GTK_WINDOW(app->break_window)); 33 | gtk_window_set_keep_above(GTK_WINDOW(app->break_window), TRUE); 34 | } 35 | 36 | void 37 | handle_work_break_start(gpointer data) 38 | { 39 | app_context * app = (app_context *)data; 40 | 41 | gtk_label_set_markup(GTK_LABEL(app->break_type_label), "Work Break"); 42 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(app->progress_bar), 0); 43 | 44 | gtk_window_set_position(GTK_WINDOW(app->break_window), GTK_WIN_POS_CENTER); 45 | 46 | gtk_widget_show_all(app->break_window); 47 | gtk_widget_show(app->postpone_button); 48 | 49 | gtk_window_stick(GTK_WINDOW(app->break_window)); 50 | gtk_window_set_keep_above(GTK_WINDOW(app->break_window), TRUE); 51 | } 52 | 53 | void 54 | handle_break_end(gpointer data) 55 | { 56 | app_context * app = (app_context *)data; 57 | 58 | gtk_widget_hide(app->break_window); 59 | gtk_widget_hide(app->postpone_button); 60 | } 61 | 62 | void 63 | handle_break_update(gpointer data) 64 | { 65 | app_context * app = (app_context *)data; 66 | char * tmp; 67 | 68 | int seconds = ai_break_time_left(app->core); 69 | int minutes = (int)round(ai_seconds_until_next_work_break(app->core) / 60.0); 70 | 71 | tmp = g_strdup_printf("%d:%02d", seconds / 60, seconds % 60); 72 | gtk_label_set_text(GTK_LABEL(app->time_left_label), tmp); 73 | g_free(tmp); 74 | 75 | if (minutes > 60) { 76 | tmp = g_strdup_printf("next break in %d:%02d hours", minutes / 60, minutes % 60); 77 | } else if (seconds > 60) { 78 | tmp = g_strdup_printf("next break in %d minutes", minutes); 79 | } else if (minutes == 1) { 80 | tmp = g_strdup_printf("next break in 1 minute"); 81 | } else { 82 | tmp = g_strdup_printf("next break in %d minutes", minutes); 83 | } 84 | 85 | gtk_label_set_text(GTK_LABEL(app->time_until_label), tmp); 86 | g_free(tmp); 87 | 88 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(app->progress_bar), ai_break_progress(app->core)); 89 | } 90 | 91 | static gboolean 92 | handle_clicked(GtkWidget * window, GdkEventButton * event, gpointer data) 93 | { 94 | //app_context * app = (app_context *)data; 95 | 96 | if (event->button == 1) { 97 | gtk_window_begin_move_drag (GTK_WINDOW(window), event->button, event->x_root, event->y_root, event->time); 98 | 99 | return FALSE; 100 | } 101 | 102 | return FALSE; 103 | } 104 | 105 | /* Only some X servers support alpha channels. Always have a fallback */ 106 | gboolean supports_alpha = FALSE; 107 | 108 | static void 109 | handle_screen_changed(GtkWidget *widget, GdkScreen *old_screen, gpointer userdata) 110 | { 111 | /* To check if the display supports alpha channels, get the colormap */ 112 | GdkScreen *screen = gtk_widget_get_screen(widget); 113 | GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen); 114 | 115 | if (!colormap) 116 | { 117 | g_debug("Your screen does NOT support alpha channels!\n"); 118 | colormap = gdk_screen_get_rgb_colormap(screen); 119 | supports_alpha = FALSE; 120 | } 121 | else 122 | { 123 | g_debug("Your screen supports alpha channels!\n"); 124 | supports_alpha = TRUE; 125 | } 126 | 127 | /* Now we have a colormap appropriate for the screen, use it */ 128 | gtk_widget_set_colormap(widget, colormap); 129 | } 130 | 131 | void 132 | break_window_create(app_context * app) 133 | { 134 | GtkWidget * fixed; 135 | 136 | app->break_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 137 | 138 | // GTK_WINDOW_POPUP doesn't work, as it can not be made movable ... 139 | // gdk_window_set_override_redirect(GDK_WINDOW(app->break_window->window), FALSE); 140 | // gdk_window_set_type_hint(GDK_WINDOW(app->break_window->window), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); 141 | // gtk_window_set_type_hint(GTK_WINDOW(app->break_window), GDK_WINDOW_TYPE_HINT_MENU); 142 | gtk_window_set_accept_focus(GTK_WINDOW(app->break_window), FALSE); 143 | gtk_window_set_skip_taskbar_hint(GTK_WINDOW(app->break_window), TRUE); 144 | 145 | gtk_widget_set_size_request(app->break_window, 300, 300); 146 | gtk_window_set_resizable(GTK_WINDOW(app->break_window), FALSE); 147 | gtk_window_set_title(GTK_WINDOW(app->break_window), "Break"); 148 | // gtk_window_set_deletable(GTK_WINDOW(app->break_window), FALSE); /* gtk 2.10 */ 149 | 150 | gtk_window_set_position(GTK_WINDOW(app->break_window), GTK_WIN_POS_CENTER); 151 | gtk_window_stick(GTK_WINDOW(app->break_window)); 152 | gtk_window_set_decorated(GTK_WINDOW(app->break_window), FALSE); 153 | gtk_window_set_keep_above(GTK_WINDOW(app->break_window), TRUE); 154 | 155 | // magic to be transparent and movable 156 | gtk_widget_set_app_paintable(app->break_window, TRUE); 157 | 158 | g_signal_connect(G_OBJECT(app->break_window), "expose-event", G_CALLBACK(handle_expose), NULL); 159 | g_signal_connect(G_OBJECT(app->break_window), "screen-changed", G_CALLBACK(handle_screen_changed), NULL); 160 | 161 | gtk_widget_add_events(app->break_window, GDK_BUTTON_PRESS_MASK); 162 | g_signal_connect(G_OBJECT(app->break_window), "button-press-event", G_CALLBACK(handle_clicked), app); 163 | 164 | 165 | // add widgets 166 | fixed = gtk_fixed_new(); 167 | 168 | app->break_type_label = gtk_label_new("mini break"); 169 | gtk_label_set_markup(GTK_LABEL(app->break_type_label), "Mini Break"); 170 | gtk_widget_set_size_request(app->break_type_label, 298, -1); 171 | 172 | app->time_left_label = gtk_label_new("0:00"); 173 | 174 | app->progress_bar = gtk_progress_bar_new(); 175 | gtk_widget_set_size_request(app->progress_bar, 290, -1); 176 | 177 | app->postpone_button = gtk_button_new_with_label(" Postpone "); 178 | g_signal_connect(G_OBJECT(app->postpone_button), "clicked", G_CALLBACK(handle_postpone_clicked), app); 179 | 180 | app->time_until_label = gtk_label_new("next break in 0 minutes"); 181 | 182 | gtk_fixed_put(GTK_FIXED(fixed), app->break_type_label, 1, 100); 183 | gtk_fixed_put(GTK_FIXED(fixed), app->time_left_label, 200, 190); 184 | gtk_fixed_put(GTK_FIXED(fixed), app->progress_bar, 5, 210); 185 | gtk_fixed_put(GTK_FIXED(fixed), app->postpone_button, 200, 260); 186 | gtk_fixed_put(GTK_FIXED(fixed), app->time_until_label, 60, 235); 187 | 188 | gtk_container_add(GTK_CONTAINER(app->break_window), fixed); 189 | 190 | handle_screen_changed(app->break_window, NULL, NULL); 191 | } 192 | 193 | // DRAWING 194 | 195 | void 196 | cairo_rounded_rectangle(cairo_t * cr, double x, double y, double width, double height, double radius) 197 | { 198 | double x0, y0, x1,y1; 199 | 200 | x0 = x; 201 | y0 = y; 202 | x1 = x + width; 203 | y1 = y + height; 204 | 205 | cairo_move_to(cr, x0, y0 + radius); 206 | 207 | cairo_curve_to(cr, x0 , y0, x0, y0, x0 + radius, y0); 208 | 209 | cairo_line_to(cr, x1 - radius, y0); 210 | 211 | cairo_curve_to(cr, x1 , y0, x1, y0, x1, y0 + radius); 212 | 213 | cairo_line_to(cr, x1, y1 - radius); 214 | 215 | cairo_curve_to(cr, x1 , y1, x1, y1, x1 - radius, y1); 216 | 217 | cairo_line_to(cr, x0 + radius, y1); 218 | 219 | cairo_curve_to(cr, x0 , y1, x0, y1, x0, y1 - radius); 220 | 221 | cairo_close_path (cr); 222 | } 223 | 224 | /* This is called when we need to draw the windows contents */ 225 | gboolean 226 | handle_expose(GtkWidget *widget, GdkEventExpose *event, gpointer userdata) 227 | { 228 | cairo_t *cr = gdk_cairo_create(widget->window); 229 | 230 | int width, height; 231 | 232 | GdkColor bc = widget->style->bg[GTK_STATE_NORMAL]; 233 | GdkColor dc = widget->style->dark[GTK_STATE_NORMAL]; 234 | 235 | cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); 236 | cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); 237 | cairo_set_line_width(cr, 2.0); 238 | 239 | gtk_window_get_size(GTK_WINDOW(widget), &width, &height); 240 | 241 | if (supports_alpha) { 242 | cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); /* transparent */ 243 | } else { 244 | cairo_set_source_rgb (cr, bc.red / 65536.0, bc.green / 65536.0, bc.blue / 65536.0 ); 245 | } 246 | 247 | cairo_set_operator (cr, CAIRO_OPERATOR_OVER); 248 | cairo_paint (cr); 249 | 250 | cairo_set_operator (cr, CAIRO_OPERATOR_OVER); 251 | 252 | cairo_rounded_rectangle(cr, 2, 2, width - 4, height - 4, 40.0); 253 | 254 | if (supports_alpha) { 255 | cairo_set_source_rgba (cr, bc.red / 65536.0, bc.green / 65536.0, bc.blue / 65536.0, 0.85 ); 256 | } else { 257 | cairo_set_source_rgb (cr, bc.red / 65536.0, bc.green / 65536.0, bc.blue / 65536.0 ); 258 | } 259 | 260 | cairo_fill_preserve(cr); 261 | 262 | if (supports_alpha) { 263 | cairo_set_source_rgba (cr, dc.red / 65536.0, dc.green / 65536.0, dc.blue / 65536.0, 0.85 ); 264 | } else { 265 | cairo_set_source_rgb (cr, dc.red / 65536.0, dc.green / 65536.0, dc.blue / 65536.0 ); 266 | } 267 | 268 | cairo_stroke(cr); 269 | 270 | cairo_destroy(cr); 271 | return FALSE; 272 | } 273 | 274 | -------------------------------------------------------------------------------- /macosx/AntiRSI.m: -------------------------------------------------------------------------------- 1 | /* 2 | * author: Onne Gorter 3 | * package: antirsi-macosx 4 | * license: GPL 5 | * 6 | * TODO 7 | * clean up from old antirsi, like mini_break was micro_pause ... 8 | * remove smooth preference thingy, its no longer 600 mhz computers and old macosx 9 | * investigate status bar 10 | * use new style dockicon api 11 | */ 12 | 13 | #import "AntiRSI.h" 14 | 15 | #include 16 | #include 17 | 18 | // entry functions from antirsi-core 19 | 20 | static void handle_break_end(void * data) { 21 | id ai = (id)data; 22 | [ai endBreak]; 23 | } 24 | 25 | static void handle_mini_break_start(void * data) { 26 | id ai = (id)data; 27 | [ai doMicroPause]; 28 | } 29 | 30 | static void handle_work_break_start(void * data) { 31 | id ai = (id)data; 32 | [ai doWorkBreak]; 33 | } 34 | 35 | static void handle_break_update(void * data) { 36 | id ai = (id)data; 37 | [ai drawBreakWindow]; 38 | } 39 | 40 | static void handle_status_update(void * data) { 41 | id ai = (id)data; 42 | [ai drawDockImage]; 43 | } 44 | 45 | @implementation AntiRSI 46 | 47 | // bindings methods 48 | - (void)setMicro_pause_duration:(float)f { core->mini_duration = round(f); } 49 | - (void)setMicro_pause_period:(float)f { core->mini_interval = 60 * round(f); } 50 | - (void)setWork_break_duration:(float)f { core->work_duration = 60 * round(f); } 51 | - (void)setWork_break_period:(float)f { core->work_interval = 60 * round(f); } 52 | 53 | - (float)micro_pause_duration { return core->mini_duration; } 54 | - (float)micro_pause_period { return core->mini_interval; } 55 | - (float)work_break_duration { return core->work_duration; } 56 | - (float)work_break_period { return core->work_interval; } 57 | 58 | - (void)installTimer:(double)interval 59 | { 60 | if (mtimer != nil) { 61 | [mtimer invalidate]; 62 | [mtimer autorelease]; 63 | } 64 | mtimer = [[NSTimer scheduledTimerWithTimeInterval:interval 65 | target:self 66 | selector:@selector(tick:) 67 | userInfo:nil repeats:YES] retain]; 68 | } 69 | 70 | - (void)setSample_interval:(NSString *)s 71 | { 72 | sample_interval = 1; 73 | if ([s isEqualToString:@"Super Smooth"]) sample_interval = 0.1; 74 | if ([s isEqualToString:@"Smooth"]) sample_interval = 0.33; 75 | if ([s isEqualToString:@"Normal"]) sample_interval = 1; 76 | if ([s isEqualToString:@"Low"]) sample_interval = 2; 77 | 78 | [self installTimer:sample_interval]; 79 | } 80 | 81 | - (void)setDraw_dock_image:(BOOL)b 82 | { 83 | draw_dock_image=b; 84 | if (!b) { 85 | [NSApp setApplicationIconImage: original_dock_image]; 86 | } else { 87 | [self drawDockImage]; 88 | } 89 | } 90 | 91 | - (void)setBackground:(NSColor *)c 92 | { 93 | [background autorelease]; 94 | background=[c retain]; 95 | 96 | // make new darkbackground color 97 | float r,g,b,a; 98 | [background getRed:&r green:&g blue:&b alpha:&a]; 99 | [darkbackground autorelease]; 100 | darkbackground=[[NSColor colorWithCalibratedRed:r*0.35 green:g*0.35 blue:b*0.35 alpha:a+0.2] retain]; 101 | 102 | [self drawDockImage]; 103 | } 104 | 105 | - (void)setElapsed:(NSColor *)c 106 | { 107 | [elapsed autorelease]; 108 | elapsed=[c retain]; 109 | [self drawDockImage]; 110 | } 111 | 112 | - (void)setTaking:(NSColor *)c 113 | { 114 | [taking autorelease]; 115 | taking=[c retain]; 116 | [self drawDockImage]; 117 | } 118 | 119 | // end of bindings 120 | 121 | - (void)awakeFromNib 122 | { 123 | core = antirsi_init(self); 124 | // want transparancy 125 | [NSColor setIgnoresAlpha:NO]; 126 | 127 | // initial colors 128 | elapsed = [[NSColor colorWithCalibratedRed:0.3 green:0.3 blue:0.9 alpha:0.95] retain]; 129 | taking = [[NSColor colorWithCalibratedRed:0.3 green:0.9 blue:0.3 alpha:0.90] retain]; 130 | background = [NSColor colorWithCalibratedRed:0.9 green:0.9 blue:0.9 alpha:0.7]; 131 | 132 | //initial values 133 | core->mini_interval = 4*60; 134 | core->mini_duration = 13; 135 | core->work_interval = 50*60; 136 | core->work_duration = 8*60; 137 | 138 | core->emit_break_end = handle_break_end; 139 | core->emit_mini_break_start = handle_mini_break_start; 140 | core->emit_work_break_start = handle_work_break_start; 141 | core->emit_break_update = handle_break_update; 142 | core->emit_status_update = handle_status_update; 143 | 144 | sample_interval = 1; 145 | 146 | // initialize dock image 147 | dock_image = [[NSImage alloc] initWithSize:NSMakeSize(128,128)]; 148 | [dock_image setCacheMode:NSImageCacheNever]; 149 | original_dock_image = [NSImage imageNamed:@"AntiRSI"]; 150 | draw_dock_image_q = YES; 151 | 152 | // setup main window that will show either micropause or workbreak 153 | main_window = [[NSWindow alloc] initWithContentRect:[view frame] 154 | styleMask:NSBorderlessWindowMask 155 | backing:NSBackingStoreBuffered defer:YES]; 156 | [main_window setBackgroundColor:[NSColor clearColor]]; 157 | [main_window setLevel:NSScreenSaverWindowLevel]; 158 | [main_window setAlphaValue:0.85]; 159 | [main_window setOpaque:NO]; 160 | [main_window setHasShadow:NO]; 161 | [main_window setMovableByWindowBackground:YES]; 162 | [main_window center]; 163 | [main_window setContentView:view]; 164 | [main_window setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; 165 | 166 | // set background now 167 | [self setBackground:background]; 168 | 169 | // create initial values 170 | NSMutableDictionary* initial = [NSMutableDictionary dictionaryWithCapacity:10]; 171 | [initial setObject:[NSNumber numberWithFloat:4] forKey:@"micro_pause_period"]; 172 | [initial setObject:[NSNumber numberWithFloat:13] forKey:@"micro_pause_duration"]; 173 | [initial setObject:[NSNumber numberWithFloat:50] forKey:@"work_break_period"]; 174 | [initial setObject:[NSNumber numberWithFloat:8] forKey:@"work_break_duration"]; 175 | [initial setObject:@"Smooth" forKey:@"sample_interval"]; 176 | [initial setObject:[NSNumber numberWithBool:YES] forKey:@"draw_dock_image"]; 177 | [initial setObject:[NSNumber numberWithBool:NO] forKey:@"lock_focus"]; 178 | [initial setObject:[NSArchiver archivedDataWithRootObject:elapsed] forKey:@"elapsed"]; 179 | [initial setObject:[NSArchiver archivedDataWithRootObject:taking] forKey:@"taking"]; 180 | [initial setObject:[NSArchiver archivedDataWithRootObject:background] forKey:@"background"]; 181 | [[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:initial]; 182 | 183 | // bind to defauls controller 184 | id dc = [NSUserDefaultsController sharedUserDefaultsController]; 185 | [self bind:@"micro_pause_period" toObject:dc withKeyPath:@"values.micro_pause_period" options:nil]; 186 | [self bind:@"micro_pause_duration" toObject:dc withKeyPath:@"values.micro_pause_duration" options:nil]; 187 | [self bind:@"work_break_period" toObject:dc withKeyPath:@"values.work_break_period" options:nil]; 188 | [self bind:@"work_break_duration" toObject:dc withKeyPath:@"values.work_break_duration" options:nil]; 189 | [self bind:@"sample_interval" toObject:dc withKeyPath:@"values.sample_interval" options:nil]; 190 | [self bind:@"draw_dock_image" toObject:dc withKeyPath:@"values.draw_dock_image" options:nil]; 191 | [self bind:@"lock_focus" toObject:dc withKeyPath:@"values.lock_focus" options:nil]; 192 | NSDictionary* unarchive = [NSDictionary dictionaryWithObject:NSUnarchiveFromDataTransformerName forKey:@"NSValueTransformerName"]; 193 | [self bind:@"elapsed" toObject:dc withKeyPath:@"values.elapsed" options:unarchive]; 194 | [self bind:@"taking" toObject:dc withKeyPath:@"values.taking" options:unarchive]; 195 | [self bind:@"background" toObject:dc withKeyPath:@"values.background" options:unarchive]; 196 | 197 | // alert every binding 198 | [[NSUserDefaultsController sharedUserDefaultsController] revert:self]; 199 | 200 | // start the timer 201 | [self installTimer:sample_interval]; 202 | 203 | // about dialog 204 | sVersion = [[NSString stringWithFormat:@"%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]] retain]; 205 | [version setStringValue:[NSString stringWithFormat:@"Version %@", sVersion]]; 206 | 207 | // TODO remove? 208 | [progress setMaxValue:1]; 209 | } 210 | 211 | // tick every second and update status 212 | - (void)tick:(NSTimer *)timer { 213 | 214 | // still even iTunes posts HID events to prevent screen blanks and screen saver ... ugly 215 | CFTimeInterval idle_time = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateHIDSystemState, kCGAnyInputEventType); 216 | ai_tick(core, idle_time); 217 | } 218 | 219 | // draw the break window progress bar and such 220 | - (void)drawBreakWindow { 221 | // update window 222 | [progress setDoubleValue:ai_break_progress(core)]; 223 | [self drawTimeLeft:ai_break_time_left(core)]; 224 | [self drawNextBreak:ai_seconds_until_next_work_break(core)]; 225 | 226 | // if user likes to be interrupted 227 | if (lock_focus) { 228 | [NSApp activateIgnoringOtherApps:YES]; 229 | [main_window makeKeyAndOrderFront:self]; 230 | } 231 | } 232 | 233 | // draw the dock icon 234 | - (void)drawDockImage { 235 | if (!draw_dock_image) return; 236 | 237 | [dock_image lockFocus]; 238 | 239 | // clear all 240 | [[NSColor clearColor] set]; 241 | NSRectFill(NSMakeRect(0,0,127,127)); 242 | 243 | NSBezierPath* p; 244 | float end; 245 | 246 | //draw background circle 247 | [darkbackground set]; 248 | p =[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(6,6,115,115)]; 249 | [p setLineWidth:4]; 250 | [p stroke]; 251 | 252 | //fill 253 | [background set]; 254 | [[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(8,8,111,111)] fill]; 255 | 256 | //put dot in middle 257 | [darkbackground set]; 258 | [[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(59,59,9,9)] fill]; 259 | 260 | // reuse this one 261 | p = [NSBezierPath bezierPath]; 262 | 263 | // draw work_break 264 | [elapsed set]; 265 | end = 360 - (360.0 / core->work_interval * core->work_t - 90); 266 | if (end <= 90) end=90.1; 267 | [p appendBezierPathWithArcWithCenter:NSMakePoint(63.5, 63.5) radius:40 startAngle:90 endAngle:end clockwise:YES]; 268 | [p setLineWidth:22]; 269 | [p stroke]; 270 | 271 | // draw work break taking 272 | [taking set]; 273 | [p removeAllPoints]; 274 | end = 360 - (360.0 / core->work_duration * core->work_taking_t - 90); 275 | if (end <= 90) end=90.1; 276 | [p appendBezierPathWithArcWithCenter:NSMakePoint(63.5, 63.5) radius:40 startAngle:90 endAngle:end clockwise:YES]; 277 | [p setLineWidth:18]; 278 | [p stroke]; 279 | 280 | // draw micro pause 281 | [elapsed set]; 282 | [p removeAllPoints]; 283 | end = 360 - (360.0 / core->mini_interval * core->mini_t - 90); 284 | if (end <= 90) end = 90.1; 285 | [p appendBezierPathWithArcWithCenter:NSMakePoint(63.5, 63.5) radius:17 startAngle:90 endAngle:end clockwise:YES]; 286 | [p setLineWidth:22]; 287 | [p stroke]; 288 | 289 | // draw micro pause taking 290 | [taking set]; 291 | [p removeAllPoints]; 292 | end = 360 - (360.0 / core->mini_duration * core->mini_taking_t - 90); 293 | if (end <= 90) end = 90.1; 294 | [p appendBezierPathWithArcWithCenter:NSMakePoint(63.5, 63.5) radius:17 startAngle:90 endAngle:end clockwise:YES]; 295 | [p setLineWidth:18]; 296 | [p stroke]; 297 | 298 | [dock_image unlockFocus]; 299 | 300 | // and set it in the dock check draw_dock_image one last time ... 301 | if (draw_dock_image_q) [NSApp setApplicationIconImage:dock_image]; 302 | } 303 | 304 | // done with micro pause or work break 305 | - (void)endBreak { 306 | [[main_window animator] setAlphaValue:0.0]; 307 | // what is the consequence of hiding it, instead of ordering it out?? 308 | //[main_window orderOut:NULL]; 309 | 310 | // reset time interval to user's choice 311 | [self installTimer:sample_interval]; 312 | } 313 | 314 | // center and make appear the break window 315 | - (void)orderInBreakWindow { 316 | [main_window center]; 317 | [main_window orderFrontRegardless]; 318 | [main_window setAlphaValue:0.0]; 319 | [[main_window animator] setAlphaValue:1.0]; 320 | 321 | // temporarily set time interval for smooth updating during the pause 322 | [self installTimer:0.1]; 323 | } 324 | 325 | // display micro_pause window with appropriate widgets and progress bar 326 | - (void)doMicroPause { 327 | [label setStringValue: sMicroPause]; 328 | [progress setDoubleValue:ai_break_progress(core)]; 329 | [postpone setHidden:YES]; 330 | [self drawTimeLeft:ai_break_time_left(core)]; 331 | [self drawNextBreak:ai_seconds_until_next_work_break(core)]; 332 | [self orderInBreakWindow]; 333 | } 334 | 335 | // display work_break window with appropriate widgets and progress bar 336 | - (void)doWorkBreak { 337 | [label setStringValue: sWorkBreak]; 338 | [progress setDoubleValue:ai_break_progress(core)]; 339 | [postpone setHidden:NO]; 340 | [self drawTimeLeft:ai_break_time_left(core)]; 341 | [self drawNextBreak:ai_seconds_until_next_work_break(core)]; 342 | [self orderInBreakWindow]; 343 | } 344 | 345 | // diplays time left 346 | - (void)drawTimeLeft:(int)seconds { 347 | [time setStringValue:[NSString stringWithFormat:@"%d:%02d", seconds / 60, seconds % 60]]; 348 | } 349 | 350 | // displays next break 351 | - (void)drawNextBreak:(int)seconds { 352 | int minutes = round(seconds / 60.0) ; 353 | 354 | // nice hours, minutes ... 355 | if (minutes > 60) { 356 | [next_break setStringValue:[NSString stringWithFormat:@"next break in %d:%02d hours", 357 | minutes / 60, minutes % 60]]; 358 | } else { 359 | [next_break setStringValue:[NSString stringWithFormat:@"next break in %d minutes", minutes]]; 360 | } 361 | } 362 | 363 | // goto website 364 | - (IBAction)gotoWebsite:(id)sender 365 | { 366 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:sURL]]; 367 | } 368 | 369 | // check for update 370 | - (IBAction)checkForUpdate:(id)sender 371 | { 372 | NSString *latest_version = [NSString stringWithContentsOfURL: [NSURL URLWithString:sLatestVersionURL]]; 373 | if (latest_version == Nil) latest_version = @""; 374 | 375 | latest_version = [latest_version stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 376 | 377 | if ([latest_version length] == 0) { 378 | NSRunInformationalAlertPanel( 379 | @"Unable to Determine", 380 | @"Unable to determine the latest AntiRSI version number.", 381 | @"Ok", nil, nil); 382 | } else if ([latest_version compare:sVersion] == NSOrderedDescending) { 383 | int r = NSRunInformationalAlertPanel( 384 | @"New Version", 385 | [NSString stringWithFormat:@"A new version (%@) of AntiRSI is available; would you like to go to the website now?", latest_version], 386 | @"Goto Website", @"Cancel", nil); 387 | if (r == NSOKButton) { 388 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:sURL]]; 389 | } 390 | } else { 391 | NSRunInformationalAlertPanel( 392 | @"No Update Available", 393 | @"This is the latest version of AntiRSI.", 394 | @"OK", nil, nil); 395 | } 396 | } 397 | 398 | // stop work break and postpone by 10 minutes 399 | - (IBAction)postpone:(id)sender { 400 | ai_work_break_postpone(core); 401 | } 402 | 403 | // start a work break right now 404 | - (IBAction)breakNow:(id)sender { 405 | ai_work_break_now(core); 406 | } 407 | 408 | // validate menu items 409 | - (BOOL)validateMenuItem:(NSMenuItem *)menu { 410 | 411 | if (menu == menuBreakNow || menu == dockBreakNow) { 412 | if (ai_can_continue_natural_break(core)) { 413 | [menu setTitle: @"Continue Work Break"]; 414 | } else { 415 | [menu setTitle: @"Take Break Now"]; 416 | } 417 | return core->state == S_NORMAL; 418 | } 419 | 420 | if (menu == menuPostpone || menu == dockPostpone) { 421 | return core->state == S_IN_WORK; 422 | } 423 | 424 | return [super validateMenuItem:menu]; 425 | } 426 | 427 | - (void)applicationWillTerminate:(NSNotification *)aNotification 428 | { 429 | // make sure timer doesn't tick once more ... 430 | draw_dock_image_q = NO; 431 | [mtimer invalidate]; 432 | [mtimer autorelease]; 433 | mtimer = nil; 434 | [dock_image release]; 435 | 436 | // and make sure to show original dock image 437 | [NSApp setApplicationIconImage: original_dock_image]; 438 | } 439 | 440 | @end 441 | 442 | -------------------------------------------------------------------------------- /macosx/AntiRSI.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 42; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 036E7B420A5C47B900D38801 /* antirsi-core.c in Sources */ = {isa = PBXBuildFile; fileRef = 036E7B410A5C47B900D38801 /* antirsi-core.c */; }; 11 | 036E7B440A5C47C800D38801 /* antirsi-core.h in Headers */ = {isa = PBXBuildFile; fileRef = 036E7B430A5C47C700D38801 /* antirsi-core.h */; }; 12 | 4DB6164E061B59EA002EF355 /* AntiRSI.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DB6164C061B59EA002EF355 /* AntiRSI.h */; }; 13 | 4DB6164F061B59EA002EF355 /* AntiRSI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DB6164D061B59EA002EF355 /* AntiRSI.m */; }; 14 | 4DF73F67061E136200B0D9C9 /* AntiRSIView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DF73F65061E136200B0D9C9 /* AntiRSIView.m */; }; 15 | 4DF73F68061E136200B0D9C9 /* AntiRSIView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DF73F66061E136200B0D9C9 /* AntiRSIView.h */; }; 16 | 4DF73F86061E155C00B0D9C9 /* AntiRSI.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4DF73F85061E155C00B0D9C9 /* AntiRSI.icns */; }; 17 | 8D1107280486CEB800E47090 /* AntiRSI_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 32CA4F630368D1EE00C91783 /* AntiRSI_Prefix.pch */; }; 18 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 19 | 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 20 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 21 | EEA827B20FE0D04B009F8249 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = EEA827B00FE0D04B009F8249 /* MainMenu.xib */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | 036E7B410A5C47B900D38801 /* antirsi-core.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = "antirsi-core.c"; path = "../antirsi-core/antirsi-core.c"; sourceTree = SOURCE_ROOT; }; 26 | 036E7B430A5C47C700D38801 /* antirsi-core.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "antirsi-core.h"; path = "../antirsi-core/antirsi-core.h"; sourceTree = SOURCE_ROOT; }; 27 | 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 28 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 29 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 31 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 32 | 32CA4F630368D1EE00C91783 /* AntiRSI_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AntiRSI_Prefix.pch; sourceTree = ""; }; 33 | 4DB6164C061B59EA002EF355 /* AntiRSI.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AntiRSI.h; sourceTree = ""; }; 34 | 4DB6164D061B59EA002EF355 /* AntiRSI.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 30; path = AntiRSI.m; sourceTree = ""; }; 35 | 4DF73BC7061DAB3B00B0D9C9 /* ScreenSaver.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ScreenSaver.framework; path = /System/Library/Frameworks/ScreenSaver.framework; sourceTree = ""; }; 36 | 4DF73F65061E136200B0D9C9 /* AntiRSIView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AntiRSIView.m; sourceTree = ""; }; 37 | 4DF73F66061E136200B0D9C9 /* AntiRSIView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AntiRSIView.h; sourceTree = ""; }; 38 | 4DF73F85061E155C00B0D9C9 /* AntiRSI.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = AntiRSI.icns; sourceTree = ""; }; 39 | 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 40 | 8D1107320486CEB800E47090 /* AntiRSI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AntiRSI.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | EEA827B10FE0D04B009F8249 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | 8D11072E0486CEB800E47090 /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXFrameworksBuildPhase section */ 54 | 55 | /* Begin PBXGroup section */ 56 | 080E96DDFE201D6D7F000001 /* Classes */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 4DB6164C061B59EA002EF355 /* AntiRSI.h */, 60 | 4DB6164D061B59EA002EF355 /* AntiRSI.m */, 61 | 4DF73F66061E136200B0D9C9 /* AntiRSIView.h */, 62 | 4DF73F65061E136200B0D9C9 /* AntiRSIView.m */, 63 | ); 64 | name = Classes; 65 | sourceTree = ""; 66 | }; 67 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 71 | ); 72 | name = "Linked Frameworks"; 73 | sourceTree = ""; 74 | }; 75 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 4DF73BC7061DAB3B00B0D9C9 /* ScreenSaver.framework */, 79 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */, 80 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */, 81 | ); 82 | name = "Other Frameworks"; 83 | sourceTree = ""; 84 | }; 85 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 8D1107320486CEB800E47090 /* AntiRSI.app */, 89 | ); 90 | name = Products; 91 | sourceTree = ""; 92 | }; 93 | 29B97314FDCFA39411CA2CEA /* AntiRSI */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 080E96DDFE201D6D7F000001 /* Classes */, 97 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 98 | 29B97317FDCFA39411CA2CEA /* Resources */, 99 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 100 | 19C28FACFE9D520D11CA2CBB /* Products */, 101 | ); 102 | name = AntiRSI; 103 | sourceTree = ""; 104 | }; 105 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 036E7B430A5C47C700D38801 /* antirsi-core.h */, 109 | 036E7B410A5C47B900D38801 /* antirsi-core.c */, 110 | 32CA4F630368D1EE00C91783 /* AntiRSI_Prefix.pch */, 111 | 29B97316FDCFA39411CA2CEA /* main.m */, 112 | ); 113 | name = "Other Sources"; 114 | sourceTree = ""; 115 | }; 116 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | EEA827B00FE0D04B009F8249 /* MainMenu.xib */, 120 | 4DF73F85061E155C00B0D9C9 /* AntiRSI.icns */, 121 | 8D1107310486CEB800E47090 /* Info.plist */, 122 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, 123 | ); 124 | name = Resources; 125 | sourceTree = ""; 126 | }; 127 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 131 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, 132 | ); 133 | name = Frameworks; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXHeadersBuildPhase section */ 139 | 8D1107270486CEB800E47090 /* Headers */ = { 140 | isa = PBXHeadersBuildPhase; 141 | buildActionMask = 2147483647; 142 | files = ( 143 | 8D1107280486CEB800E47090 /* AntiRSI_Prefix.pch in Headers */, 144 | 4DB6164E061B59EA002EF355 /* AntiRSI.h in Headers */, 145 | 4DF73F68061E136200B0D9C9 /* AntiRSIView.h in Headers */, 146 | 036E7B440A5C47C800D38801 /* antirsi-core.h in Headers */, 147 | ); 148 | runOnlyForDeploymentPostprocessing = 0; 149 | }; 150 | /* End PBXHeadersBuildPhase section */ 151 | 152 | /* Begin PBXNativeTarget section */ 153 | 8D1107260486CEB800E47090 /* AntiRSI */ = { 154 | isa = PBXNativeTarget; 155 | buildConfigurationList = 03C29A010945B33D00639E3E /* Build configuration list for PBXNativeTarget "AntiRSI" */; 156 | buildPhases = ( 157 | 8D1107270486CEB800E47090 /* Headers */, 158 | 8D1107290486CEB800E47090 /* Resources */, 159 | 8D11072C0486CEB800E47090 /* Sources */, 160 | 8D11072E0486CEB800E47090 /* Frameworks */, 161 | ); 162 | buildRules = ( 163 | ); 164 | dependencies = ( 165 | ); 166 | name = AntiRSI; 167 | productInstallPath = "$(HOME)/Applications"; 168 | productName = AntiRSI; 169 | productReference = 8D1107320486CEB800E47090 /* AntiRSI.app */; 170 | productType = "com.apple.product-type.application"; 171 | }; 172 | /* End PBXNativeTarget section */ 173 | 174 | /* Begin PBXProject section */ 175 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 176 | isa = PBXProject; 177 | buildConfigurationList = 03C29A050945B33D00639E3E /* Build configuration list for PBXProject "AntiRSI" */; 178 | compatibilityVersion = "Xcode 2.4"; 179 | hasScannedForEncodings = 1; 180 | mainGroup = 29B97314FDCFA39411CA2CEA /* AntiRSI */; 181 | projectDirPath = ""; 182 | projectRoot = ""; 183 | targets = ( 184 | 8D1107260486CEB800E47090 /* AntiRSI */, 185 | ); 186 | }; 187 | /* End PBXProject section */ 188 | 189 | /* Begin PBXResourcesBuildPhase section */ 190 | 8D1107290486CEB800E47090 /* Resources */ = { 191 | isa = PBXResourcesBuildPhase; 192 | buildActionMask = 2147483647; 193 | files = ( 194 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, 195 | 4DF73F86061E155C00B0D9C9 /* AntiRSI.icns in Resources */, 196 | EEA827B20FE0D04B009F8249 /* MainMenu.xib in Resources */, 197 | ); 198 | runOnlyForDeploymentPostprocessing = 0; 199 | }; 200 | /* End PBXResourcesBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 8D11072C0486CEB800E47090 /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 8D11072D0486CEB800E47090 /* main.m in Sources */, 208 | 4DB6164F061B59EA002EF355 /* AntiRSI.m in Sources */, 209 | 4DF73F67061E136200B0D9C9 /* AntiRSIView.m in Sources */, 210 | 036E7B420A5C47B900D38801 /* antirsi-core.c in Sources */, 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | }; 214 | /* End PBXSourcesBuildPhase section */ 215 | 216 | /* Begin PBXVariantGroup section */ 217 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { 218 | isa = PBXVariantGroup; 219 | children = ( 220 | 089C165DFE840E0CC02AAC07 /* English */, 221 | ); 222 | name = InfoPlist.strings; 223 | sourceTree = ""; 224 | }; 225 | EEA827B00FE0D04B009F8249 /* MainMenu.xib */ = { 226 | isa = PBXVariantGroup; 227 | children = ( 228 | EEA827B10FE0D04B009F8249 /* English */, 229 | ); 230 | name = MainMenu.xib; 231 | sourceTree = ""; 232 | }; 233 | /* End PBXVariantGroup section */ 234 | 235 | /* Begin XCBuildConfiguration section */ 236 | 03C29A020945B33D00639E3E /* Development */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)"; 240 | ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386"; 241 | COPY_PHASE_STRIP = NO; 242 | DEBUGGING_SYMBOLS = YES; 243 | DEPLOYMENT_LOCATION = NO; 244 | FRAMEWORK_SEARCH_PATHS = ""; 245 | GCC_DYNAMIC_NO_PIC = NO; 246 | GCC_ENABLE_FIX_AND_CONTINUE = YES; 247 | GCC_ENABLE_TRIGRAPHS = NO; 248 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 249 | GCC_OPTIMIZATION_LEVEL = 0; 250 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 251 | GCC_PREFIX_HEADER = AntiRSI_Prefix.pch; 252 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; 253 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; 254 | GCC_WARN_UNKNOWN_PRAGMAS = NO; 255 | HEADER_SEARCH_PATHS = ""; 256 | INFOPLIST_FILE = Info.plist; 257 | INSTALL_PATH = "$(HOME)/Applications"; 258 | LIBRARY_SEARCH_PATHS = ""; 259 | MACOSX_DEPLOYMENT_TARGET = 10.5; 260 | OTHER_CFLAGS = ""; 261 | OTHER_LDFLAGS = ""; 262 | PRODUCT_NAME = AntiRSI; 263 | SDKROOT = /Developer/SDKs/MacOSX10.5.sdk; 264 | SECTORDER_FLAGS = ""; 265 | WARNING_CFLAGS = ( 266 | "-Wmost", 267 | "-Wno-four-char-constants", 268 | "-Wno-unknown-pragmas", 269 | ); 270 | WRAPPER_EXTENSION = app; 271 | ZERO_LINK = YES; 272 | }; 273 | name = Development; 274 | }; 275 | 03C29A030945B33D00639E3E /* Deployment */ = { 276 | isa = XCBuildConfiguration; 277 | buildSettings = { 278 | ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)"; 279 | ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386"; 280 | COPY_PHASE_STRIP = YES; 281 | DEPLOYMENT_LOCATION = NO; 282 | FRAMEWORK_SEARCH_PATHS = ""; 283 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 284 | GCC_ENABLE_OBJC_GC = NO; 285 | GCC_ENABLE_TRIGRAPHS = NO; 286 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO; 287 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 288 | GCC_PREFIX_HEADER = AntiRSI_Prefix.pch; 289 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; 290 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; 291 | GCC_WARN_UNKNOWN_PRAGMAS = NO; 292 | HEADER_SEARCH_PATHS = ""; 293 | INFOPLIST_FILE = Info.plist; 294 | INSTALL_PATH = "$(HOME)/Applications"; 295 | LIBRARY_SEARCH_PATHS = ""; 296 | MACOSX_DEPLOYMENT_TARGET = 10.5; 297 | OTHER_CFLAGS = ""; 298 | OTHER_LDFLAGS = ""; 299 | PRODUCT_NAME = AntiRSI; 300 | SDKROOT = /Developer/SDKs/MacOSX10.5.sdk; 301 | SECTORDER_FLAGS = ""; 302 | WARNING_CFLAGS = ( 303 | "-Wmost", 304 | "-Wno-four-char-constants", 305 | "-Wno-unknown-pragmas", 306 | ); 307 | WRAPPER_EXTENSION = app; 308 | ZERO_LINK = NO; 309 | }; 310 | name = Deployment; 311 | }; 312 | 03C29A040945B33D00639E3E /* Default */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ARCHS = "$(ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1)"; 316 | ARCHS_STANDARD_32_BIT_PRE_XCODE_3_1 = "ppc i386"; 317 | DEPLOYMENT_LOCATION = NO; 318 | FRAMEWORK_SEARCH_PATHS = ""; 319 | GCC_ENABLE_TRIGRAPHS = NO; 320 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO; 321 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 322 | GCC_PREFIX_HEADER = AntiRSI_Prefix.pch; 323 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; 324 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; 325 | GCC_WARN_UNKNOWN_PRAGMAS = NO; 326 | HEADER_SEARCH_PATHS = ""; 327 | INFOPLIST_FILE = Info.plist; 328 | INSTALL_PATH = "$(HOME)/Applications"; 329 | LIBRARY_SEARCH_PATHS = ""; 330 | MACOSX_DEPLOYMENT_TARGET = 10.5; 331 | OTHER_CFLAGS = ""; 332 | OTHER_LDFLAGS = ""; 333 | PRODUCT_NAME = AntiRSI; 334 | SDKROOT = /Developer/SDKs/MacOSX10.5.sdk; 335 | SECTORDER_FLAGS = ""; 336 | WARNING_CFLAGS = ( 337 | "-Wmost", 338 | "-Wno-four-char-constants", 339 | "-Wno-unknown-pragmas", 340 | ); 341 | WRAPPER_EXTENSION = app; 342 | }; 343 | name = Default; 344 | }; 345 | 03C29A060945B33D00639E3E /* Development */ = { 346 | isa = XCBuildConfiguration; 347 | buildSettings = { 348 | APPLICATION_VERSION = 2.1; 349 | ARCHS = "${NATIVE_ARCH}"; 350 | MACOSX_DEPLOYMENT_TARGET = 10.4; 351 | SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; 352 | }; 353 | name = Development; 354 | }; 355 | 03C29A070945B33D00639E3E /* Deployment */ = { 356 | isa = XCBuildConfiguration; 357 | buildSettings = { 358 | APPLICATION_VERSION = 2.1; 359 | ARCHS = ( 360 | ppc, 361 | i386, 362 | ); 363 | MACOSX_DEPLOYMENT_TARGET = 10.4; 364 | SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; 365 | }; 366 | name = Deployment; 367 | }; 368 | 03C29A080945B33D00639E3E /* Default */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | APPLICATION_VERSION = 2.1; 372 | ARCHS = "${NATIVE_ARCH}"; 373 | MACOSX_DEPLOYMENT_TARGET = 10.4; 374 | SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; 375 | }; 376 | name = Default; 377 | }; 378 | /* End XCBuildConfiguration section */ 379 | 380 | /* Begin XCConfigurationList section */ 381 | 03C29A010945B33D00639E3E /* Build configuration list for PBXNativeTarget "AntiRSI" */ = { 382 | isa = XCConfigurationList; 383 | buildConfigurations = ( 384 | 03C29A020945B33D00639E3E /* Development */, 385 | 03C29A030945B33D00639E3E /* Deployment */, 386 | 03C29A040945B33D00639E3E /* Default */, 387 | ); 388 | defaultConfigurationIsVisible = 0; 389 | defaultConfigurationName = Default; 390 | }; 391 | 03C29A050945B33D00639E3E /* Build configuration list for PBXProject "AntiRSI" */ = { 392 | isa = XCConfigurationList; 393 | buildConfigurations = ( 394 | 03C29A060945B33D00639E3E /* Development */, 395 | 03C29A070945B33D00639E3E /* Deployment */, 396 | 03C29A080945B33D00639E3E /* Default */, 397 | ); 398 | defaultConfigurationIsVisible = 0; 399 | defaultConfigurationName = Default; 400 | }; 401 | /* End XCConfigurationList section */ 402 | }; 403 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 404 | } 405 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | --------------------------------------------------------------------------------