File: breakrem/info.txt 1 This app keeps reminding you to take breaks from your 2 computer with pop-ups every %d minutes: time isn't 3 counted while pop-ups are showing. 4 5 The pop-ups will keep coming regularly as long as you 6 keep pressing OK to dismiss them when they show up; 7 pressing Cancel or the ✕ on the top corner will quit 8 this app and stop the reminders. 9 10 Note: you can start this app from the command-line with 11 a number between 1 and 20 to set how many minutes to 12 wait for each break reminder. File: breakrem/main.c 1 /* 2 Break Reminder 3 4 This app keeps reminding you to take breaks from your computer with pop-ups 5 every few minutes: time isn't counted while pop-ups are showing. 6 */ 7 8 // gcc -Os -o breakrem.exe -mwindows *.c 9 10 #include <stdio.h> 11 #include <windows.h> 12 13 const char start_fmt[] = "" 14 "This app keeps reminding you to take breaks from your\n" 15 "computer with pop-ups every %d minutes: time isn't\n" 16 "counted while pop-ups are showing.\n" 17 "\n" 18 "The pop-ups will keep coming regularly as long as you\n" 19 "keep pressing OK to dismiss them when they show up;\n" 20 "pressing Cancel or the X on the top corner will quit\n" 21 "this app and stop the reminders.\n" 22 "\n" 23 "Note: you can start this app from the command-line with\n" 24 "a number between 1 and 20 to set how many minutes to\n" 25 "wait for each break reminder." 26 ""; 27 28 const char break_time_fmt[] = "" 29 "The %d minutes have passed; time for a break\n" 30 "\n" 31 "To start the countdown for the next reminder, press OK\n" 32 "For no more reminders, press Cancel or X at the top" 33 ""; 34 35 // get_minutes figures out how many minutes to wait between breaks, by parsing 36 // the 1st cmd-line arg after the app's name, or using a default value 37 size_t get_minutes() { 38 int argc; 39 LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); 40 41 const size_t fallback = 15; 42 if (argc < 2) { 43 return fallback; 44 } 45 46 // turn 1st arg from UTF-16 into ASCII: non-ASCII chars are mangled in 47 // the process, but the resulting failure to parse a number is what 48 // would have happened even after converting properly 49 char buf[32]; 50 memset(buf, 0, sizeof(buf)); 51 WCHAR* src = argv[1]; 52 for (size_t i = 0; i < sizeof(buf) - 1; i++) { 53 buf[i] = src[i]; 54 } 55 56 57 int n = atoi(buf); 58 if (n > 20) { 59 return 20; 60 } 61 if (1 <= n && n <= 20) { 62 return (size_t)n; 63 } 64 return fallback; 65 } 66 67 int WINAPI WinMain(HINSTANCE cur, HINSTANCE prev, LPSTR cl, int show_cmd) { 68 MSG msg; 69 const UINT kind = MB_OKCANCEL | MB_TASKMODAL | MB_ICONINFORMATION; 70 71 size_t minutes = get_minutes(); 72 // make message string with the correct number of minutes 73 char start_msg[strlen(start_fmt) + 20]; 74 char break_time_msg[strlen(break_time_fmt) + 20]; 75 sprintf(start_msg, start_fmt, (int)minutes); 76 sprintf(break_time_msg, break_time_fmt, (int)minutes); 77 78 // let the user quit before even starting 79 if (MessageBoxA(NULL, start_msg, "Break Reminder", kind) != IDOK) { 80 return msg.wParam; 81 } 82 83 // start first timer, or popup will never show up 84 UINT_PTR timer = (UINT_PTR)NULL; 85 SetTimer(NULL, timer, minutes * 60 * 1000, NULL); 86 87 while (GetMessageW(&msg, NULL, 0, 0)) { 88 switch (msg.message) { 89 case WM_QUIT: 90 return msg.wParam; 91 92 case WM_TIMER: 93 // stop timer, to ensure the time elapsed while popup is showing 94 // doesn't count 95 KillTimer(NULL, timer); 96 97 // let the user quit any time the break-reminder is showing 98 if (MessageBoxA(NULL, break_time_msg, "Time for a Break!", kind) != IDOK) { 99 return msg.wParam; 100 } 101 102 // start timer for the next popup 103 SetTimer(NULL, timer, minutes * 60 * 1000, NULL); 104 break; 105 106 default: 107 // handle generic events to play nice with the system 108 TranslateMessage(&msg); 109 DispatchMessage(&msg); 110 break; 111 } 112 } 113 114 return msg.wParam; 115 }