source: mainline/uspace/app/taskbar/clock.c@ f9ae472

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f9ae472 was 983052c, checked in by Jiri Svoboda <jiri@…>, 2 years ago

Task bar should not crash when starting in terminal

Firstly, we need to make sure we do not paint anything while
UI is suspended. Also, we were missing calls to ui_lock/unlock()
while delivering kbd/pos events from console.

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/*
2 * Copyright (c) 2022 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup taskbar
30 * @{
31 */
32/** @file Task bar clock.
33 *
34 * Displays the current time in an inset frame.
35 */
36
37#include <errno.h>
38#include <gfx/render.h>
39#include <gfx/text.h>
40#include <stdlib.h>
41#include <stdio.h>
42#include <task.h>
43#include <ui/control.h>
44#include <ui/paint.h>
45#include <ui/resource.h>
46#include <ui/ui.h>
47#include "clock.h"
48
49static void taskbar_clock_ctl_destroy(void *);
50static errno_t taskbar_clock_ctl_paint(void *);
51static ui_evclaim_t taskbar_clock_ctl_kbd_event(void *, kbd_event_t *);
52static ui_evclaim_t taskbar_clock_ctl_pos_event(void *, pos_event_t *);
53static void taskbar_clock_timer(void *);
54
55/** Task bar clock control ops */
56static ui_control_ops_t taskbar_clock_ctl_ops = {
57 .destroy = taskbar_clock_ctl_destroy,
58 .paint = taskbar_clock_ctl_paint,
59 .kbd_event = taskbar_clock_ctl_kbd_event,
60 .pos_event = taskbar_clock_ctl_pos_event
61};
62
63/** Create task bar clock.
64 *
65 * @param window Containing window
66 * @param rclock Place to store pointer to new clock
67 * @return EOK on success or an error code
68 */
69errno_t taskbar_clock_create(ui_window_t *window, taskbar_clock_t **rclock)
70{
71 taskbar_clock_t *clock;
72 errno_t rc;
73
74 clock = calloc(1, sizeof(taskbar_clock_t));
75 if (clock == NULL)
76 return ENOMEM;
77
78 rc = ui_control_new(&taskbar_clock_ctl_ops, (void *)clock,
79 &clock->control);
80 if (rc != EOK) {
81 free(clock);
82 return rc;
83 }
84
85 clock->timer = fibril_timer_create(NULL);
86 if (clock->timer == NULL) {
87 rc = ENOMEM;
88 goto error;
89 }
90
91 fibril_mutex_initialize(&clock->lock);
92 fibril_condvar_initialize(&clock->timer_done_cv);
93 fibril_timer_set(clock->timer, 1000000, taskbar_clock_timer, clock);
94
95 clock->window = window;
96 *rclock = clock;
97 return EOK;
98error:
99 ui_control_delete(clock->control);
100 free(clock);
101 return rc;
102}
103
104/** Destroy task bar clock.
105 *
106 * @param clock Task bar clock
107 */
108void taskbar_clock_destroy(taskbar_clock_t *clock)
109{
110 /*
111 * Signal to the timer that we are cleaning up. If the timer handler
112 * misses it and sets the timer again, we will clear that active
113 * timer and be done (and if we were even slower and the timer
114 * fired again, it's the same situation as before.
115 */
116 fibril_mutex_lock(&clock->lock);
117 clock->timer_cleanup = true;
118 fibril_mutex_unlock(&clock->lock);
119
120 /* If we catch the timer while it's active, there's nothing to do. */
121 if (fibril_timer_clear(clock->timer) != fts_active) {
122 /* Need to wait for timer handler to finish */
123 fibril_mutex_lock(&clock->lock);
124 while (clock->timer_done == false)
125 fibril_condvar_wait(&clock->timer_done_cv, &clock->lock);
126 fibril_mutex_unlock(&clock->lock);
127 }
128
129 fibril_timer_destroy(clock->timer);
130 ui_control_delete(clock->control);
131 free(clock);
132}
133
134static errno_t taskbar_clock_get_text(taskbar_clock_t *clock, char *buf,
135 size_t bsize)
136{
137 struct timespec ts;
138 struct tm tm;
139 errno_t rc;
140
141 getrealtime(&ts);
142 rc = time_utc2tm(ts.tv_sec, &tm);
143 if (rc != EOK)
144 return rc;
145
146 snprintf(buf, bsize, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min,
147 tm.tm_sec);
148 return EOK;
149}
150
151/** Paint task bar clock.
152 *
153 * @param clock Task bar clock
154 */
155errno_t taskbar_clock_paint(taskbar_clock_t *clock)
156{
157 gfx_context_t *gc = ui_window_get_gc(clock->window);
158 ui_resource_t *res = ui_window_get_res(clock->window);
159 ui_t *ui = ui_window_get_ui(clock->window);
160 char buf[10];
161 gfx_text_fmt_t fmt;
162 gfx_coord2_t pos;
163 gfx_rect_t irect;
164 errno_t rc;
165
166 if (!ui_is_textmode(ui)) {
167 /* Paint frame */
168 rc = ui_paint_inset_frame(res, &clock->rect, &irect);
169 if (rc != EOK)
170 goto error;
171 } else {
172 irect = clock->rect;
173 }
174
175 rc = gfx_set_color(gc, ui_resource_get_wnd_face_color(res));
176 if (rc != EOK)
177 goto error;
178
179 /* Fill background */
180 rc = gfx_fill_rect(gc, &irect);
181 if (rc != EOK)
182 goto error;
183
184 pos.x = (irect.p0.x + irect.p1.x) / 2;
185 pos.y = (irect.p0.y + irect.p1.y) / 2;
186
187 gfx_text_fmt_init(&fmt);
188 fmt.font = ui_resource_get_font(res);
189 fmt.color = ui_resource_get_wnd_text_color(res);
190 fmt.halign = gfx_halign_center;
191 fmt.valign = gfx_valign_center;
192
193 rc = taskbar_clock_get_text(clock, buf, sizeof(buf));
194 if (rc != EOK)
195 goto error;
196
197 rc = gfx_puttext(&pos, &fmt, buf);
198 if (rc != EOK)
199 goto error;
200
201 rc = gfx_update(gc);
202 if (rc != EOK)
203 goto error;
204
205 return EOK;
206error:
207 return rc;
208}
209
210/** Handle task bar clock keyboard event.
211 *
212 * @param clock Task bar clock
213 * @param event Keyboard event
214 * @return ui_claimed iff event was claimed
215 */
216ui_evclaim_t taskbar_clock_kbd_event(taskbar_clock_t *clock, kbd_event_t *event)
217{
218 return ui_unclaimed;
219}
220
221/** Handle task bar clock position event.
222 *
223 * @param clock Task bar clock
224 * @param event Position event
225 * @return ui_claimed iff event was claimed
226 */
227ui_evclaim_t taskbar_clock_pos_event(taskbar_clock_t *clock, pos_event_t *event)
228{
229 gfx_coord2_t pos;
230
231 pos.x = event->hpos;
232 pos.y = event->vpos;
233 if (!gfx_pix_inside_rect(&pos, &clock->rect))
234 return ui_unclaimed;
235
236 return ui_claimed;
237}
238
239/** Get base control for task bar clock.
240 *
241 * @param clock Task bar clock
242 * @return Base UI control
243 */
244ui_control_t *taskbar_clock_ctl(taskbar_clock_t *clock)
245{
246 return clock->control;
247}
248
249/** Set task bar clock rectangle.
250 *
251 * @param clock Task bar clock
252 * @param rect Rectangle
253 */
254void taskbar_clock_set_rect(taskbar_clock_t *clock, gfx_rect_t *rect)
255{
256 gfx_rect_t irect;
257
258 clock->rect = *rect;
259
260 irect.p0.x = clock->rect.p0.x + 1;
261 irect.p0.y = clock->rect.p0.y + 1;
262 irect.p1.x = clock->rect.p1.x;
263 irect.p1.y = clock->rect.p1.y - 1;
264
265 (void)irect;
266}
267
268/** Destroy clock control.
269 *
270 * @param arg Argument (taskbar_clock_t *)
271 */
272void taskbar_clock_ctl_destroy(void *arg)
273{
274 taskbar_clock_t *clock = (taskbar_clock_t *) arg;
275
276 taskbar_clock_destroy(clock);
277}
278
279/** Paint task bar clock control.
280 *
281 * @param arg Argument (taskbar_clock_t *)
282 * @return EOK on success or an error code
283 */
284errno_t taskbar_clock_ctl_paint(void *arg)
285{
286 taskbar_clock_t *clock = (taskbar_clock_t *) arg;
287
288 return taskbar_clock_paint(clock);
289}
290
291/** Handle task bar clock control keyboard event.
292 *
293 * @param arg Argument (taskbar_clock_t *)
294 * @param kbd_event Keyboard event
295 * @return @c ui_claimed iff the event is claimed
296 */
297ui_evclaim_t taskbar_clock_ctl_kbd_event(void *arg, kbd_event_t *event)
298{
299 taskbar_clock_t *clock = (taskbar_clock_t *) arg;
300
301 return taskbar_clock_kbd_event(clock, event);
302}
303
304/** Handle task bar clock control position event.
305 *
306 * @param arg Argument (taskbar_clock_t *)
307 * @param pos_event Position event
308 * @return @c ui_claimed iff the event is claimed
309 */
310ui_evclaim_t taskbar_clock_ctl_pos_event(void *arg, pos_event_t *event)
311{
312 taskbar_clock_t *clock = (taskbar_clock_t *) arg;
313
314 return taskbar_clock_pos_event(clock, event);
315}
316
317/** Taskbar clock timer handler.
318 *
319 * @param arg Argument (taskbar_clock_t *)
320 */
321static void taskbar_clock_timer(void *arg)
322{
323 taskbar_clock_t *clock = (taskbar_clock_t *) arg;
324 ui_t *ui;
325
326 ui = ui_window_get_ui(clock->window);
327 ui_lock(ui);
328
329 fibril_mutex_lock(&clock->lock);
330 if (!ui_is_suspended(ui_window_get_ui(clock->window)))
331 (void) taskbar_clock_paint(clock);
332
333 if (!clock->timer_cleanup) {
334 fibril_timer_set(clock->timer, 1000000, taskbar_clock_timer,
335 clock);
336 } else {
337 /* Acknowledge timer cleanup */
338 clock->timer_done = true;
339 fibril_condvar_signal(&clock->timer_done_cv);
340 }
341
342 fibril_mutex_unlock(&clock->lock);
343 ui_unlock(ui);
344}
345
346/** @}
347 */
Note: See TracBrowser for help on using the repository browser.