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 by Daniel 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#include "config.h"
22#include "system.h"
23#include "kernel.h"
24#include "button.h"
25#ifdef HAVE_SDL
26#include "SDL.h"
27#if SDL_MAJOR_VERSION > 1
28#include "window-sdl.h"
29#endif
30#endif
31
32static struct event_queue button_queue SHAREDBSS_ATTR;
33static intptr_t button_data; /* data value from last message dequeued */
34
35#ifdef HAVE_ADJUSTABLE_CPU_FREQ
36static bool button_boosted = false;
37static long button_unboost_tick;
38#define BUTTON_UNBOOST_TMO HZ
39
40static void button_boost(bool state)
41{
42 if (state)
43 {
44 /* update the unboost time each button_boost(true) call */
45 button_unboost_tick = current_tick + BUTTON_UNBOOST_TMO;
46
47 if (!button_boosted)
48 {
49 button_boosted = true;
50 cpu_boost(true);
51 }
52 }
53 else if (button_boosted && TIME_AFTER(current_tick, button_unboost_tick))
54 {
55 button_boosted = false;
56 cpu_boost(false);
57 }
58}
59
60static void button_queue_wait(struct queue_event *evp, int timeout)
61{
62 /* Loop once after wait time if boosted in order to unboost and wait the
63 full remaining time */
64 do
65 {
66 int ticks = timeout;
67
68 if (ticks == TIMEOUT_NOBLOCK)
69 ;
70 else if (ticks > 0)
71 {
72 if (button_boosted && ticks > BUTTON_UNBOOST_TMO)
73 ticks = BUTTON_UNBOOST_TMO;
74
75 timeout -= ticks;
76 }
77 else if (button_boosted) /* TIMEOUT_BLOCK (ticks < 0) */
78 {
79 ticks = BUTTON_UNBOOST_TMO;
80 }
81
82 queue_wait_w_tmo(&button_queue, evp, ticks);
83 if (evp->id != SYS_TIMEOUT)
84 {
85 /* GUI boost build gets immediate kick, otherwise at least 3
86 messages had to be there */
87 #ifndef HAVE_GUI_BOOST
88 if (queue_count(&button_queue) >= 2)
89 #endif
90 button_boost(true);
91
92 break;
93 }
94 button_boost(false);
95 }
96 while (timeout);
97}
98#else /* ndef HAVE_ADJUSTABLE_CPU_FREQ */
99static inline void button_queue_wait(struct queue_event *evp, int timeout)
100{
101#if defined(__APPLE__) && (CONFIG_PLATFORM & PLATFORM_SDL)
102 unsigned long initial_tick = current_tick;
103 unsigned long curr_tick, remaining;
104 while(true)
105 {
106 SDL_PumpEvents();
107 queue_wait_w_tmo(&button_queue, evp, TIMEOUT_NOBLOCK);
108 if (evp->id != SYS_TIMEOUT || timeout == TIMEOUT_NOBLOCK)
109 return;
110 else if (timeout == TIMEOUT_BLOCK)
111 sleep(HZ/60);
112 else
113 {
114 curr_tick = current_tick;
115 if (!TIME_AFTER(initial_tick + timeout, curr_tick))
116 return;
117 remaining = ((initial_tick + timeout) - curr_tick);
118 sleep(remaining < HZ/60 ? remaining : HZ/60);
119 }
120 }
121#else
122 queue_wait_w_tmo(&button_queue, evp, timeout);
123#if defined(HAVE_SDL) && (SDL_MAJOR_VERSION > 1)
124 sdl_window_adjust(); /* Window may have been resized */
125#endif
126#endif
127}
128#endif /* HAVE_ADJUSTABLE_CPU_FREQ */
129
130void button_queue_post(long id, intptr_t data)
131{
132 queue_post(&button_queue, id, data);
133}
134
135void button_queue_post_remove_head(long id, intptr_t data)
136{
137 queue_remove_from_head(&button_queue, id);
138 queue_post(&button_queue, id, data);
139}
140
141bool button_queue_try_post(long button, int data)
142{
143#ifdef HAVE_TOUCHSCREEN
144 /* one can swipe over the scren very quickly,
145 * for this to work we want to forget about old presses and
146 * only respect the very latest ones */
147 const bool force_post = true;
148#else
149 /* Only post events if the queue is empty,
150 * to avoid afterscroll effects.
151 * i.e. don't post new buttons if previous ones haven't been
152 * processed yet - but always post releases */
153 const bool force_post = button & BUTTON_REL;
154#endif
155
156 if (!queue_empty(&button_queue))
157 {
158 if (force_post)
159 queue_remove_from_head(&button_queue, button);
160 else
161 return false;
162 }
163
164 queue_post(&button_queue, button, data);
165
166 /* on touchscreen we posted unconditionally */
167 return true;
168}
169
170int button_queue_count(void)
171{
172 return queue_count(&button_queue);
173}
174
175bool button_queue_empty(void)
176{
177 return queue_empty(&button_queue);
178}
179
180bool button_queue_full(void)
181{
182 return queue_full(&button_queue);
183}
184
185void button_clear_queue(void)
186{
187 queue_clear(&button_queue);
188}
189
190/* clears anything but release and sysevents */
191void button_clear_pressed(void)
192{
193 long button;
194 for (int count = queue_count(&button_queue); count > 0; count--)
195 {
196 button = button_get(false);
197 if (button & (BUTTON_REL | SYS_EVENT))
198 {
199 button_queue_post(button, button_data);
200 }
201 }
202}
203
204long button_get_w_tmo(int ticks)
205{
206 struct queue_event ev;
207 button_queue_wait(&ev, ticks);
208
209 if (ev.id == SYS_TIMEOUT)
210 ev.id = BUTTON_NONE;
211 else
212 button_data = ev.data;
213
214 return ev.id;
215}
216
217long button_get(bool block)
218{
219 return button_get_w_tmo(block ? TIMEOUT_BLOCK : TIMEOUT_NOBLOCK);
220}
221
222intptr_t button_get_data(void)
223{
224 return button_data;
225}
226
227void INIT_ATTR button_queue_init(void)
228{
229 queue_init(&button_queue, true);
230}