1 #include <string.h>
2 #include <sys/time.h>
3 
4 #include <gtk/gtk.h>
5 
6 #include "Calendar.hpp"
7 #include "Config.hpp"
8 
9 
fork_and_run(char * cmdline)10 void fork_and_run(char* cmdline)
11 {
12     if (strlen(cmdline)) {
13         if (fork() == 0) {
14             execl("/bin/sh", "/bin/sh", "-c", cmdline, NULL);
15             _exit(0);
16         }
17     }
18 }
19 
monthChangedCb(GtkCalendar * calendar,gpointer cls)20 void monthChangedCb(GtkCalendar *calendar, gpointer cls)
21 {
22     if (cls) {
23         ((Calendar*)cls)->markToday();
24     }
25 }
dayDoubleClickCb(GtkCalendar * calendar,gpointer cls)26 void dayDoubleClickCb(GtkCalendar *calendar, gpointer cls)
27 {
28     if (cls) {
29         ((Calendar*)cls)->runExternalViewer();
30     }
31 }
32 
33 
Calendar()34 Calendar::Calendar()
35 {
36     widget = gtk_calendar_new();
37 
38     Config* config = Config::getInstance();
39     g_object_set(widget,
40                  "show-heading", true,
41                  "show-day-names", true,
42                  "show-details", false,
43                  "show-week-numbers", config->show_week_numbers,
44                  NULL);
45     // Store today date to be able to jump to it.
46     gtk_calendar_get_date((GtkCalendar*)widget,
47                           &today_year, &today_month, &today_day);
48     if (config->mark_today) {
49         markToday();
50         g_signal_connect(widget, "month-changed",
51                          GCallback(monthChangedCb), (gpointer)this);
52     }
53     g_signal_connect(widget, "day-selected-double-click",
54                      GCallback(dayDoubleClickCb), (gpointer)this);
55 
56     gtk_widget_show(widget);
57 }
58 
~Calendar()59 Calendar::~Calendar()
60 {
61     gtk_widget_destroy(widget);
62 }
63 
nextYear()64 void Calendar::nextYear()
65 {
66     _change(1, 0, 0);
67 }
prevYear()68 void Calendar::prevYear()
69 {
70     _change(-1, 0, 0);
71 }
72 
nextMonth()73 void Calendar::nextMonth()
74 {
75     _change(0, 1, 0);
76 }
prevMonth()77 void Calendar::prevMonth()
78 {
79     _change(0, -1, 0);
80 }
81 
goLeft()82 void Calendar::goLeft()
83 {
84     _change(0, 0, -1);
85 }
goDown()86 void Calendar::goDown()
87 {
88     _change(0, 0, 7);
89 }
goUp()90 void Calendar::goUp()
91 {
92     _change(0, 0, -7);
93 }
goRight()94 void Calendar::goRight()
95 {
96     _change(0, 0, 1);
97 }
98 
_change(int year_offset,int month_offset,int day_offset)99 void Calendar::_change(int year_offset, int month_offset, int day_offset)
100 {
101     int year, month, day;
102     gtk_calendar_get_date((GtkCalendar*)widget,
103                           (guint*)&year, (guint*)&month, (guint*)&day);
104 
105     unsigned int n_days = _n_days(year, month);
106     day += day_offset;
107     if (day < 1) {
108         day += _n_days(year, month - 1);
109         month_offset--;
110     } else if (day > n_days) {
111         day -= n_days;
112         month_offset++;
113     }
114 
115     month += month_offset;
116     if (month > 11) {
117         month = 0;
118         year_offset++;
119     } else if (month < 0) {
120         month = 11;
121         year_offset--;
122     }
123 
124     year += year_offset;
125 
126     gtk_calendar_select_month((GtkCalendar*)widget, (guint)month, (guint)year);
127     gtk_calendar_select_day((GtkCalendar*)widget, day);
128 }
129 
_n_days(unsigned int year,unsigned int month)130 unsigned int Calendar::_n_days(unsigned int year, unsigned int month)
131 {
132     if (month == 3 || month == 5 || month == 8 || month == 10) {
133         return 30;
134     } else if (month == 1) {
135         bool leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
136         if (leap) {
137             return 29;
138         } else {
139             return 28;
140         }
141     } else {
142         return 31;
143     }
144 }
145 
markToday()146 bool Calendar::markToday()
147 {
148     guint year, month;
149     gtk_calendar_get_date((GtkCalendar*)widget, &year, &month, NULL);
150     if (year == today_year && month == today_month) {
151         gtk_calendar_mark_day((GtkCalendar*)widget, today_day);
152         return true;
153     } else {
154         gtk_calendar_unmark_day((GtkCalendar*)widget, today_day);
155         return false;
156     }
157 }
158 
goToday()159 void Calendar::goToday()
160 {
161     gtk_calendar_select_month((GtkCalendar*)widget, today_month, today_year);
162     gtk_calendar_select_day((GtkCalendar*)widget, today_day);
163 }
164 
runExternalViewer()165 bool Calendar::runExternalViewer()
166 {
167     Config* config = Config::getInstance();
168     size_t len = config->external_viewer.length();
169     if (len > 0) {
170         int year, month, day;
171         gtk_calendar_get_date((GtkCalendar*)widget,
172                               (guint*)&year, (guint*)&month, (guint*)&day);
173         struct tm date;
174         date.tm_year = year - 1900;
175         date.tm_mon = month;
176         date.tm_mday = day;
177         date.tm_sec = date.tm_min = date.tm_hour = date.tm_wday
178                     = date.tm_yday = date.tm_isdst = 0;
179 
180         size_t buf_size = len + 64;
181         char* cmd = new char[buf_size];
182         strftime(cmd, buf_size, config->external_viewer.c_str(), &date);
183         fork_and_run(cmd);
184         delete[] cmd;
185         return true;
186     } else {
187         return false;
188     }
189 }
190