#define _POSIX_C_SOURCE 199309L #include #include #include #include #include #include #include #include #include // Unfortunately, 0 = Sunday. int weekday(int year, int month, int day) { struct tm tm = { .tm_year = year - 1900, .tm_mon = month - 1, .tm_mday = day, }; mktime(&tm); return tm.tm_wday; } const char *maaned[] = { "", "JANUAR", "FEBRUAR", "MARS", "APRIL", "MAI", "JUNI", "JULI", "AUGUST", "SEPTEMBER", "OKTOBER", "NOVEMBER", "DESEMBER", }; const char *ukedag[] = { "SØNDAG", "MANDAG", "TIRSDAG", "ONSDAG", "TORSDAG", "FREDAG", "LØRDAG", }; enum { MAX_EVENTS = 64, SIZEOF_TITLE = 256, }; struct event { int year; int month; int day; int wday; int hour; int minute; char title[SIZEOF_TITLE]; }; struct event the_events[MAX_EVENTS]; int num_events; char * read_stream(char *s, size_t size, void *d) { return fgets(s, (int)size, (FILE *)d); } void load_the_events(void) { icalparser *p = icalparser_new(); assert(p); FILE *f = fopen("events.ical", "r"); assert(f); icalparser_set_gen_data(p, f); for (;;) { char *line = icalparser_get_line(p, read_stream); if (!line) { break; } icalcomponent *comp = icalparser_add_line(p, line); if (!comp) { continue; } for (icalcompiter i = icalcomponent_begin_component( comp, ICAL_VEVENT_COMPONENT); icalcompiter_deref(&i); icalcompiter_next(&i)) { if (MAX_EVENTS <= num_events) { warnx("MAX_EVENTS exceeded at %u", num_events); break; } icalcomponent *c = icalcompiter_deref(&i); struct icaltimetype dts = icalcomponent_get_dtstart(c); const char *sum = icalcomponent_get_summary(c); the_events[num_events].year = dts.year; the_events[num_events].month = dts.month; the_events[num_events].day = dts.day; the_events[num_events].hour = dts.hour; the_events[num_events].minute = dts.minute; strncpy(the_events[num_events].title, sum, SIZEOF_TITLE); the_events[num_events].wday = weekday(dts.year, dts.month, dts.day); ++num_events; } icalcomponent_free(comp); } icalparser_free(p); } const char *the_alphabet = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ" "abcdefghijklmnopqrstuvwxyzæøå" "!@#$%^&*()[];'\\:\"|,./<>?"; void line(int x, int y, Font f, Color c, char *s) { DrawTextEx(f, s, (Vector2){x, y}, (float)f.baseSize, 2, c); } int main(void) { load_the_events(); const int sw = 1920; const int sh = 1080; InitWindow(sw, sh, "opplysning"); SetTargetFPS(60); int ncp = 0; int *cp = LoadCodepoints(the_alphabet, &ncp); Font font_h = LoadFontEx("font/adventpro-bold.ttf", 60, cp, ncp); Font font_p = LoadFontEx("font/adventpro-semibold.ttf", 40, cp, ncp); UnloadCodepoints(cp); Color bg = RAYWHITE; Color fg = BLACK; Color hd = {0xf0, 0x4a, 0x00, 0xff}; while (!WindowShouldClose()) { struct timespec now = {0}; clock_gettime(CLOCK_REALTIME, &now); struct tm *ti = localtime(&now.tv_sec); char ts[64] = {0}; snprintf(ts, sizeof(ts), "%02d:%02d", ti->tm_hour, ti->tm_min); BeginDrawing(); ClearBackground(bg); line(sw / 2 - 60, 0, font_h, fg, ts); int y = 0; int year = 0, month = 0, day = 0; for (int i = 0; i < num_events; ++i) { struct event *e = the_events + i; if (year != e->year || month != e->month || day != e->day) { year = e->year; month = e->month; day = e->day; char s[64] = {0}; snprintf(s, sizeof(s), "%s %u. %s", ukedag[e->wday], e->day, maaned[e->month]); line(20, y += 50, font_h, hd, s); y += 20; } { char s[64] = {0}; snprintf(s, sizeof(s), "%02u:%02u %s", e->hour, e->minute, e->title); line(25, y += 40, font_p, fg, s); } } EndDrawing(); } CloseWindow(); }