source: mainline/uspace/app/viewer/viewer.c@ 901b302

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

Viewer needs to use UI_DISPLAY_DEFAULT

Fixes viewer crashing if executed without -d.

  • Property mode set to 100644
File size: 7.5 KB
Line 
1/*
2 * Copyright (c) 2020 Jiri Svoboda
3 * Copyright (c) 2013 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup viewer
31 * @{
32 */
33/** @file
34 */
35
36#include <errno.h>
37#include <gfximage/tga.h>
38#include <stdbool.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <str.h>
42#include <ui/image.h>
43#include <ui/ui.h>
44#include <ui/wdecor.h>
45#include <ui/window.h>
46#include <vfs/vfs.h>
47
48#define NAME "viewer"
49
50typedef struct {
51 ui_t *ui;
52} viewer_t;
53
54static size_t imgs_count;
55static size_t imgs_current = 0;
56static char **imgs;
57
58static ui_window_t *window;
59static gfx_bitmap_t *bitmap = NULL;
60static ui_image_t *image = NULL;
61static gfx_context_t *window_gc;
62
63static gfx_rect_t img_rect;
64
65static bool img_load(gfx_context_t *gc, const char *, gfx_bitmap_t **,
66 gfx_rect_t *);
67static bool img_setup(gfx_context_t *, gfx_bitmap_t *, gfx_rect_t *);
68
69static void wnd_close(ui_window_t *, void *);
70static void wnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
71
72static ui_window_cb_t window_cb = {
73 .close = wnd_close,
74 .kbd = wnd_kbd_event
75};
76
77/** Window close request
78 *
79 * @param window Window
80 * @param arg Argument (calc_t *)
81 */
82static void wnd_close(ui_window_t *window, void *arg)
83{
84 viewer_t *viewer = (viewer_t *) arg;
85
86 ui_quit(viewer->ui);
87}
88
89static void wnd_kbd_event(ui_window_t *window, void *arg,
90 kbd_event_t *event)
91{
92 bool update = false;
93
94 if ((event->type == KEY_PRESS) && (event->c == 'q'))
95 exit(0);
96
97 if ((event->type == KEY_PRESS) && (event->key == KC_PAGE_DOWN)) {
98 if (imgs_current == imgs_count - 1)
99 imgs_current = 0;
100 else
101 imgs_current++;
102
103 update = true;
104 }
105
106 if ((event->type == KEY_PRESS) && (event->key == KC_PAGE_UP)) {
107 if (imgs_current == 0)
108 imgs_current = imgs_count - 1;
109 else
110 imgs_current--;
111
112 update = true;
113 }
114
115 if (update) {
116 gfx_bitmap_t *lbitmap;
117 gfx_rect_t lrect;
118
119 if (!img_load(window_gc, imgs[imgs_current], &lbitmap, &lrect)) {
120 printf("Cannot load image \"%s\".\n", imgs[imgs_current]);
121 exit(4);
122 }
123 if (!img_setup(window_gc, lbitmap, &lrect)) {
124 printf("Cannot setup image \"%s\".\n", imgs[imgs_current]);
125 exit(6);
126 }
127 }
128}
129
130static bool img_load(gfx_context_t *gc, const char *fname,
131 gfx_bitmap_t **rbitmap, gfx_rect_t *rect)
132{
133 int fd;
134 errno_t rc = vfs_lookup_open(fname, WALK_REGULAR, MODE_READ, &fd);
135 if (rc != EOK)
136 return false;
137
138 vfs_stat_t stat;
139 rc = vfs_stat(fd, &stat);
140 if (rc != EOK) {
141 vfs_put(fd);
142 return false;
143 }
144
145 void *tga = malloc(stat.size);
146 if (tga == NULL) {
147 vfs_put(fd);
148 return false;
149 }
150
151 size_t nread;
152 rc = vfs_read(fd, (aoff64_t []) { 0 }, tga, stat.size, &nread);
153 if (rc != EOK || nread != stat.size) {
154 free(tga);
155 vfs_put(fd);
156 return false;
157 }
158
159 vfs_put(fd);
160
161 rc = decode_tga(gc, tga, stat.size, rbitmap, rect);
162 if (rc != EOK) {
163 free(tga);
164 return false;
165 }
166
167 free(tga);
168
169 img_rect = *rect;
170 return true;
171}
172
173static bool img_setup(gfx_context_t *gc, gfx_bitmap_t *bmp, gfx_rect_t *rect)
174{
175 gfx_rect_t arect;
176 gfx_rect_t irect;
177 ui_resource_t *ui_res;
178 errno_t rc;
179
180 ui_res = ui_window_get_res(window);
181
182 ui_window_get_app_rect(window, &arect);
183
184 /* Center image on application area */
185 gfx_rect_ctr_on_rect(rect, &arect, &irect);
186
187 if (image != NULL) {
188 ui_image_set_bmp(image, bmp, rect);
189 (void) ui_image_paint(image);
190 ui_image_set_rect(image, &irect);
191 } else {
192 rc = ui_image_create(ui_res, bmp, rect, &image);
193 if (rc != EOK) {
194 gfx_bitmap_destroy(bmp);
195 return false;
196 }
197
198 ui_image_set_rect(image, &irect);
199 ui_window_add(window, ui_image_ctl(image));
200 }
201
202 if (bitmap != NULL)
203 gfx_bitmap_destroy(bitmap);
204
205 bitmap = bmp;
206 return true;
207}
208
209static void print_syntax(void)
210{
211 printf("Syntax: %s [<options] <image-file>...\n", NAME);
212 printf("\t-d <display-spec> Use the specified display\n");
213 printf("\t-f Full-screen mode\n");
214}
215
216int main(int argc, char *argv[])
217{
218 const char *display_spec = UI_DISPLAY_DEFAULT;
219 gfx_bitmap_t *lbitmap;
220 gfx_rect_t lrect;
221 bool fullscreen = false;
222 gfx_rect_t rect;
223 gfx_rect_t wrect;
224 gfx_coord2_t off;
225 ui_t *ui;
226 ui_wnd_params_t params;
227 viewer_t viewer;
228 errno_t rc;
229 int i;
230
231 i = 1;
232 while (i < argc && argv[i][0] == '-') {
233 if (str_cmp(argv[i], "-d") == 0) {
234 ++i;
235 if (i >= argc) {
236 printf("Argument missing.\n");
237 print_syntax();
238 return 1;
239 }
240
241 display_spec = argv[i++];
242 } else if (str_cmp(argv[i], "-f") == 0) {
243 ++i;
244 fullscreen = true;
245 } else {
246 printf("Invalid option '%s'.\n", argv[i]);
247 print_syntax();
248 return 1;
249 }
250 }
251
252 if (i >= argc) {
253 printf("No image files specified.\n");
254 print_syntax();
255 return 1;
256 }
257
258 imgs_count = argc - i;
259 imgs = calloc(imgs_count, sizeof(char *));
260 if (imgs == NULL) {
261 printf("Out of memory.\n");
262 return 1;
263 }
264
265 for (int j = 0; j < argc - i; j++) {
266 imgs[j] = str_dup(argv[i + j]);
267 if (imgs[j] == NULL) {
268 printf("Out of memory.\n");
269 return 3;
270 }
271 }
272
273 rc = ui_create(display_spec, &ui);
274 if (rc != EOK) {
275 printf("Error creating UI on display %s.\n", display_spec);
276 return 1;
277 }
278
279 viewer.ui = ui;
280
281 /*
282 * We don't know the image size yet, so create tiny window and resize
283 * later.
284 */
285 ui_wnd_params_init(&params);
286 params.caption = "Viewer";
287 params.rect.p0.x = 0;
288 params.rect.p0.y = 0;
289 params.rect.p1.x = 1;
290 params.rect.p1.y = 1;
291
292 if (fullscreen) {
293 params.style &= ~ui_wds_decorated;
294 params.placement = ui_wnd_place_full_screen;
295 }
296
297 rc = ui_window_create(ui, &params, &window);
298 if (rc != EOK) {
299 printf("Error creating window.\n");
300 return 1;
301 }
302
303 window_gc = ui_window_get_gc(window);
304
305 ui_window_set_cb(window, &window_cb, (void *) &viewer);
306
307 if (!img_load(window_gc, imgs[imgs_current], &lbitmap, &lrect)) {
308 printf("Cannot load image \"%s\".\n", imgs[imgs_current]);
309 return 1;
310 }
311
312 /*
313 * Compute window rectangle such that application area corresponds
314 * to rect
315 */
316 ui_wdecor_rect_from_app(params.style, &lrect, &wrect);
317 off = wrect.p0;
318 gfx_rect_rtranslate(&off, &wrect, &rect);
319
320 if (!fullscreen) {
321 rc = ui_window_resize(window, &rect);
322 if (rc != EOK) {
323 printf("Error resizing window.\n");
324 return 1;
325 }
326 }
327
328 if (!img_setup(window_gc, lbitmap, &lrect)) {
329 printf("Cannot setup image \"%s\".\n", imgs[imgs_current]);
330 return 1;
331 }
332
333 rc = ui_window_paint(window);
334 if (rc != EOK) {
335 printf("Error painting window.\n");
336 return 1;
337 }
338
339 ui_run(ui);
340
341 return 0;
342}
343
344/** @}
345 */
Note: See TracBrowser for help on using the repository browser.