A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Björn Stenberg
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <stdbool.h>
24#include "action.h"
25#include "font.h"
26#ifdef HAVE_REMOTE_LCD
27#include "lcd-remote.h"
28#endif
29#include "lang.h"
30#include "usb.h"
31#if defined(HAVE_USBSTACK)
32#include "usb_core.h"
33#ifdef USB_ENABLE_HID
34#include "usb_keymaps.h"
35#endif
36#endif
37#include "settings.h"
38#include "led.h"
39#include "appevents.h"
40#include "usb_screen.h"
41#include "skin_engine/skin_engine.h"
42#include "playlist.h"
43#include "misc.h"
44#include "icons.h"
45
46#include "bitmaps/usblogo.h"
47
48#ifdef HAVE_REMOTE_LCD
49#include "bitmaps/remote_usblogo.h"
50#endif
51
52#if (CONFIG_STORAGE & STORAGE_MMC)
53#include "ata_mmc.h"
54#endif
55
56#ifdef USB_ENABLE_HID
57int usb_keypad_mode;
58static bool usb_hid;
59#endif
60
61#ifndef SIMULATOR
62
63static int handle_usb_events(void)
64{
65#if (CONFIG_STORAGE & STORAGE_MMC)
66 int next_update=0;
67#endif /* STORAGE_MMC */
68
69 /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */
70 while(1)
71 {
72 int button;
73#ifdef USB_ENABLE_HID
74 if (usb_hid)
75 {
76 button = get_hid_usb_action();
77
78 /* On mode change, we need to refresh the screen */
79 if (button == ACTION_USB_HID_MODE_SWITCH_NEXT ||
80 button == ACTION_USB_HID_MODE_SWITCH_PREV)
81 {
82 break;
83 }
84 }
85 else
86#endif
87 {
88 button = button_get_w_tmo(HZ/2);
89 /* hid emits the event in get_action */
90 send_event(GUI_EVENT_ACTIONUPDATE, NULL);
91 }
92
93 switch(button)
94 {
95 case SYS_USB_DISCONNECTED:
96 return 1;
97 case SYS_CHARGER_DISCONNECTED:
98 reset_runtime();
99 break;
100 case SYS_TIMEOUT:
101 break;
102 }
103
104#if (CONFIG_STORAGE & STORAGE_MMC) /* USB-MMC bridge can report activity */
105 if(TIME_AFTER(current_tick,next_update))
106 {
107 if(usb_inserted()) {
108 led(mmc_usb_active(HZ));
109 }
110 next_update=current_tick+HZ/2;
111 }
112#endif /* STORAGE_MMC */
113 }
114
115 return 0;
116}
117#endif /* SIMULATOR */
118
119#define MODE_NAME_LEN 32
120
121struct usb_screen_vps_t
122{
123 struct viewport parent;
124 struct viewport logo;
125#ifdef USB_ENABLE_HID
126 struct viewport title;
127#endif
128};
129
130static void usb_screen_fix_viewports(struct screen *screen,
131 struct usb_screen_vps_t *usb_screen_vps)
132{
133 int logo_width, logo_height;
134 struct viewport *parent = &usb_screen_vps->parent;
135 struct viewport *logo = &usb_screen_vps->logo;
136
137#ifdef HAVE_REMOTE_LCD
138 if (screen->screen_type == SCREEN_REMOTE)
139 {
140 logo_width = BMPWIDTH_remote_usblogo;
141 logo_height = BMPHEIGHT_remote_usblogo;
142 }
143 else
144#endif
145 {
146 logo_width = BMPWIDTH_usblogo;
147 logo_height = BMPHEIGHT_usblogo;
148 }
149
150 viewportmanager_theme_enable(screen->screen_type, true, parent);
151
152 if (logo_width > parent->width)
153 logo_width = parent->width;
154 if (logo_height > parent->height)
155 logo_height = parent->height;
156
157 *logo = *parent;
158 logo->x = parent->x + parent->width - logo_width;
159#ifdef HAVE_LCD_SPLIT
160 switch (statusbar_position(screen))
161 {
162 /* start beyond split */
163 case STATUSBAR_OFF:
164 logo->y = parent->y + LCD_SPLIT_POS;
165 break;
166 case STATUSBAR_TOP:
167 logo->y = parent->y + LCD_SPLIT_POS - STATUSBAR_HEIGHT;
168 break;
169 /* start at the top for maximum space */
170 default:
171 logo->y = parent->y;
172 break;
173 }
174#else
175 logo->y = parent->y + (parent->height - logo_height) / 2;
176#endif
177 logo->width = logo_width;
178 logo->height = logo_height;
179
180#ifdef USB_ENABLE_HID
181 if (usb_hid)
182 {
183 struct viewport *title = &usb_screen_vps->title;
184 int char_height = font_get(parent->font)->height;
185 *title = *parent;
186 title->y = logo->y + logo->height + char_height;
187 title->height = char_height;
188 /* try to fit logo and title to parent */
189 if (parent->y + parent->height < title->y + title->height)
190 {
191 logo->y = parent->y;
192 title->y = parent->y + logo->height;
193 }
194
195 int i =0, langid = LANG_USB_KEYPAD_MODE;
196 while (langid >= 0) /* ensure the USB mode strings get cached */
197 {
198 font_getstringsize(str(langid), NULL, NULL, title->font);
199 langid = keypad_mode_name_get(i++);
200 }
201 }
202#endif
203}
204
205static void usb_screens_draw(struct usb_screen_vps_t *usb_screen_vps_ar)
206{
207 struct viewport *last_vp;
208 static const struct bitmap* logos[NB_SCREENS] = {
209 &bm_usblogo,
210#ifdef HAVE_REMOTE_LCD
211 &bm_remote_usblogo,
212#endif
213 };
214
215 FOR_NB_SCREENS(i)
216 {
217 struct screen *screen = &screens[i];
218
219 struct usb_screen_vps_t *usb_screen_vps = &usb_screen_vps_ar[i];
220 struct viewport *parent = &usb_screen_vps->parent;
221 struct viewport *logo = &usb_screen_vps->logo;
222
223 last_vp = screen->set_viewport(parent);
224 screen->clear_viewport();
225 screen->backlight_on();
226
227 screen->set_viewport(logo);
228 screen->bmp(logos[i], 0, 0);
229 if (i == SCREEN_MAIN)
230 {
231#ifdef USB_ENABLE_HID
232 if (usb_hid)
233 {
234 char modestring[100];
235 screen->set_viewport(&usb_screen_vps->title);
236 usb_screen_vps->title.flags |= VP_FLAG_ALIGN_CENTER;
237 snprintf(modestring, sizeof(modestring), "%s: %s",
238 str(LANG_USB_KEYPAD_MODE),
239 str(keypad_mode_name_get(usb_keypad_mode)));
240 screen->puts_scroll(0, 0, modestring);
241 }
242#endif /* USB_ENABLE_HID */
243 }
244 screen->set_viewport(parent);
245
246 screen->set_viewport(last_vp);
247 screen->update_viewport();
248 }
249}
250
251void gui_usb_screen_run(bool early_usb)
252{
253#ifdef SIMULATOR /* the sim allows toggling USB fast enough to overflow viewportmanagers stack */
254 static bool in_usb_screen = false;
255 if (in_usb_screen)
256 return;
257 in_usb_screen = true;
258#endif
259
260 struct usb_screen_vps_t usb_screen_vps_ar[NB_SCREENS];
261#if defined HAVE_TOUCHSCREEN
262 enum touchscreen_mode old_mode = touchscreen_get_mode();
263
264 /* TODO: Paint buttons on screens OR switch to point mode and use
265 * touchscreen as a touchpad to move the host's mouse cursor */
266 touchscreen_set_mode(TOUCHSCREEN_BUTTON);
267#endif
268
269 push_current_activity(ACTIVITY_USBSCREEN);
270
271#ifdef USB_ENABLE_HID
272 usb_hid = global_settings.usb_hid;
273 usb_keypad_mode = global_settings.usb_keypad_mode;
274#endif
275
276 FOR_NB_SCREENS(i)
277 {
278 struct screen *screen = &screens[i];
279 /* we might be coming from anywhere, and the originating screen
280 * can't be practically expected to cleanup the UI because
281 * we're invoked via default_event_handler(), therefore we make a
282 * generic cleanup here */
283 screen->set_viewport(NULL);
284 screen->scroll_stop();
285 usb_screen_fix_viewports(screen, &usb_screen_vps_ar[i]);
286 }
287
288#if 0 /* handled in usb_screen_fix_viewports() */
289 /* update the UI before disabling fonts, this maximizes the propability
290 * that font cache lookups succeed during USB */
291 send_event(GUI_EVENT_ACTIONUPDATE, NULL);
292#endif
293
294 if(!early_usb)
295 {
296 /* The font system leaves the .fnt fd's open, so we need for force close them all */
297 font_disable_all();
298 }
299
300 usb_acknowledge(SYS_USB_CONNECTED_ACK);
301
302 while (1)
303 {
304 usb_screens_draw(usb_screen_vps_ar);
305#ifdef SIMULATOR
306 if (button_get_w_tmo(HZ/2))
307 break;
308 send_event(GUI_EVENT_ACTIONUPDATE, NULL);
309#else
310 if (handle_usb_events())
311 break;
312#endif /* SIMULATOR */
313 }
314
315 FOR_NB_SCREENS(i)
316 {
317 const struct viewport* vp = NULL;
318
319#if defined(USB_ENABLE_HID)
320 vp = usb_hid ? &usb_screen_vps_ar[i].title : NULL;
321#endif
322 if (vp)
323 screens[i].scroll_stop_viewport(vp);
324 }
325#ifdef USB_ENABLE_HID
326 if (global_settings.usb_keypad_mode != usb_keypad_mode)
327 {
328 global_settings.usb_keypad_mode = usb_keypad_mode;
329 settings_save();
330 }
331#endif
332
333#ifdef HAVE_TOUCHSCREEN
334 touchscreen_set_mode(old_mode);
335#endif
336
337 if(!early_usb)
338 {
339 font_enable_all();
340 /* Not pretty, reload all settings so fonts are loaded again correctly */
341 settings_apply(true);
342 /* Reload playlist */
343 playlist_resume();
344 }
345
346 FOR_NB_SCREENS(i)
347 {
348 screens[i].backlight_on();
349 viewportmanager_theme_undo(i, false);
350 }
351
352 pop_current_activity();
353#ifdef SIMULATOR
354 in_usb_screen = false;
355#endif
356}