A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 356 lines 9.6 kB view raw
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}