blob: 984cf5d21b4e303cbcaa152edd6f56133fb6941b [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/*
Dees Troy3be70a82013-10-22 14:25:12 +00002 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
Dees_Troy51a0e822012-09-05 15:24:24 -040018
19#include <linux/input.h>
20#include <pthread.h>
21#include <stdarg.h>
22#include <stdio.h>
23#include <errno.h>
24#include <stdlib.h>
25#include <string.h>
26#include <fcntl.h>
27#include <sys/reboot.h>
28#include <sys/stat.h>
29#include <sys/time.h>
30#include <sys/mman.h>
31#include <sys/types.h>
32#include <sys/ioctl.h>
33#include <sys/mount.h>
34#include <time.h>
35#include <unistd.h>
Dees_Troy51a0e822012-09-05 15:24:24 -040036
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050037extern "C"
38{
Dees_Troy2673cec2013-04-02 20:22:16 +000039#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040040#include <pixelflinger/pixelflinger.h>
41}
bigbiffd81833a2021-01-17 11:06:57 -050042#include "minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040043
44#include "rapidxml.hpp"
45#include "objects.hpp"
46#include "../data.hpp"
47#include "../variables.h"
Dees_Troy5bf43922012-09-07 16:07:55 -040048#include "../partitions.hpp"
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050049#include "../twrp-functions.hpp"
Ethan Yonker03a42f62014-08-08 11:03:51 -050050#include "../openrecoveryscript.hpp"
51#include "../orscmd/orscmd.h"
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050052#include "blanktimer.hpp"
bigbiffd58ba182020-03-23 10:02:29 -040053#include "tw_atomic.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040054
Vojtech Boceke5ffcd12014-02-06 21:17:32 +010055// Enable to print render time of each frame to the log file
56//#define PRINT_RENDER_TIME 1
57
that9fa51532015-01-29 02:04:47 +010058#ifdef _EVENT_LOGGING
thatc5837f32015-02-01 01:59:43 +010059#define LOGEVENT(...) LOGERR(__VA_ARGS__)
that9fa51532015-01-29 02:04:47 +010060#else
61#define LOGEVENT(...) do {} while (0)
62#endif
63
Dees_Troy51a0e822012-09-05 15:24:24 -040064using namespace rapidxml;
65
66// Global values
Dees_Troy51a0e822012-09-05 15:24:24 -040067static int gGuiInitialized = 0;
Ethan Yonker04536952015-01-27 08:41:28 -060068static TWAtomicInt gForceRender;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050069blanktimer blankTimer;
Ethan Yonkerfd0439e2015-01-14 11:08:13 -060070int ors_read_fd = -1;
that10ae24f2015-12-26 20:53:51 +010071static FILE* orsout = NULL;
Ethan Yonker63e414f2015-02-06 15:44:39 -060072static float scale_theme_w = 1;
73static float scale_theme_h = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -040074
75// Needed by pages.cpp too
76int gGuiRunning = 0;
77
that1964d192016-01-07 00:41:03 +010078int g_pty_fd = -1; // set by terminal on init
79void terminal_pty_read();
80
Ethan Yonker6e8c27a2016-12-22 17:55:57 -060081int select_fd = 0;
82
Dees_Troy51a0e822012-09-05 15:24:24 -040083static int gRecorder = -1;
84
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020085extern "C" void gr_write_frame_to_file(int fd);
Dees_Troy51a0e822012-09-05 15:24:24 -040086
Matt Mowerb68bff02017-01-11 15:46:26 -060087static void flip(void)
Dees_Troy51a0e822012-09-05 15:24:24 -040088{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020089 if (gRecorder != -1)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050090 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020091 timespec time;
92 clock_gettime(CLOCK_MONOTONIC, &time);
93 write(gRecorder, &time, sizeof(timespec));
94 gr_write_frame_to_file(gRecorder);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050095 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020096 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -040097}
98
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020099void rapidxml::parse_error_handler(const char *what, void *where)
Dees_Troy51a0e822012-09-05 15:24:24 -0400100{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200101 fprintf(stderr, "Parser error: %s\n", what);
102 fprintf(stderr, " Start of string: %s\n",(char *) where);
103 LOGERR("Error parsing XML file.\n");
104 //abort();
Dees_Troy51a0e822012-09-05 15:24:24 -0400105}
106
that9fa51532015-01-29 02:04:47 +0100107class InputHandler
Dees_Troy51a0e822012-09-05 15:24:24 -0400108{
that9fa51532015-01-29 02:04:47 +0100109public:
110 void init()
thatfb759d42015-01-11 12:16:53 +0100111 {
that9fa51532015-01-29 02:04:47 +0100112 // these might be read from DataManager in the future
113 touch_hold_ms = 500;
114 touch_repeat_ms = 100;
115 key_hold_ms = 500;
116 key_repeat_ms = 100;
117 touch_status = TS_NONE;
118 key_status = KS_NONE;
119 state = AS_NO_ACTION;
120 x = y = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400121
that9fa51532015-01-29 02:04:47 +0100122#ifndef TW_NO_SCREEN_TIMEOUT
123 {
124 string seconds;
125 DataManager::GetValue("tw_screen_timeout_secs", seconds);
126 blankTimer.setTime(atoi(seconds.c_str()));
127 blankTimer.resetTimerAndUnblank();
Ethan Yonkere13fa632015-01-27 11:30:03 -0600128 }
that9fa51532015-01-29 02:04:47 +0100129#else
130 LOGINFO("Skipping screen timeout: TW_NO_SCREEN_TIMEOUT is set\n");
131#endif
Ethan Yonkere13fa632015-01-27 11:30:03 -0600132 }
133
thatc5837f32015-02-01 01:59:43 +0100134 // process input events. returns true if any event was received.
thatde72b6d2015-02-08 08:55:00 +0100135 bool processInput(int timeout_ms);
thatc5837f32015-02-01 01:59:43 +0100136
that9fa51532015-01-29 02:04:47 +0100137 void handleDrag();
138
139private:
140 // timeouts for touch/key hold and repeat
141 int touch_hold_ms;
142 int touch_repeat_ms;
143 int key_hold_ms;
144 int key_repeat_ms;
145
146 enum touch_status_enum {
147 TS_NONE = 0,
148 TS_TOUCH_AND_HOLD = 1,
149 TS_TOUCH_REPEAT = 2,
150 };
151
152 enum key_status_enum {
153 KS_NONE = 0,
154 KS_KEY_PRESSED = 1,
155 KS_KEY_REPEAT = 2,
156 };
157
158 enum action_state_enum {
159 AS_IN_ACTION_AREA = 0, // we've touched a spot with an action
160 AS_NO_ACTION = 1, // we've touched in an empty area (no action) and ignore remaining events until touch release
161 };
162 touch_status_enum touch_status;
163 key_status_enum key_status;
164 action_state_enum state;
165 int x, y; // x and y coordinates of last touch
166 struct timeval touchStart; // used to track time for long press / key repeat
167
168 void processHoldAndRepeat();
169 void process_EV_REL(input_event& ev);
170 void process_EV_ABS(input_event& ev);
171 void process_EV_KEY(input_event& ev);
172
173 void doTouchStart();
174};
175
176InputHandler input_handler;
177
178
thatde72b6d2015-02-08 08:55:00 +0100179bool InputHandler::processInput(int timeout_ms)
that9fa51532015-01-29 02:04:47 +0100180{
181 input_event ev;
thatde72b6d2015-02-08 08:55:00 +0100182 int ret = ev_get(&ev, timeout_ms);
Ethan Yonkere13fa632015-01-27 11:30:03 -0600183
184 if (ret < 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500185 {
Ethan Yonkere13fa632015-01-27 11:30:03 -0600186 // This path means that we did not get any new touch data, but
187 // we do not get new touch data if you press and hold on either
188 // the screen or on a keyboard key or mouse button
that9fa51532015-01-29 02:04:47 +0100189 if (touch_status || key_status)
190 processHoldAndRepeat();
thatc5837f32015-02-01 01:59:43 +0100191 return (ret != -2); // -2 means no more events in the queue
Ethan Yonkere13fa632015-01-27 11:30:03 -0600192 }
that9fa51532015-01-29 02:04:47 +0100193
194 switch (ev.type)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600195 {
that9fa51532015-01-29 02:04:47 +0100196 case EV_ABS:
197 process_EV_ABS(ev);
198 break;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600199
that9fa51532015-01-29 02:04:47 +0100200 case EV_REL:
201 process_EV_REL(ev);
202 break;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600203
that9fa51532015-01-29 02:04:47 +0100204 case EV_KEY:
205 process_EV_KEY(ev);
206 break;
207 }
thatc5837f32015-02-01 01:59:43 +0100208
micky38716827032023-09-16 21:20:07 +0200209#ifndef TW_NO_SCREEN_BLANK
210 if (!blankTimer.isScreenOff()) {
211#endif
212 if (ev.code != KEY_POWER && ev.code > KEY_RESERVED)
213 blankTimer.resetTimerAndUnblank();
214#ifndef TW_NO_SCREEN_BLANK
215 }
216#endif
thatc5837f32015-02-01 01:59:43 +0100217 return true; // we got an event, so there might be more in the queue
that9fa51532015-01-29 02:04:47 +0100218}
219
220void InputHandler::processHoldAndRepeat()
221{
222 HardwareKeyboard *kb = PageManager::GetHardwareKeyboard();
223
224 // touch and key repeat section
225 struct timeval curTime;
226 gettimeofday(&curTime, NULL);
227 long seconds = curTime.tv_sec - touchStart.tv_sec;
228 long useconds = curTime.tv_usec - touchStart.tv_usec;
229 long mtime = ((seconds) * 1000 + useconds / 1000.0) + 0.5;
230
231 if (touch_status == TS_TOUCH_AND_HOLD && mtime > touch_hold_ms)
232 {
233 touch_status = TS_TOUCH_REPEAT;
234 gettimeofday(&touchStart, NULL);
235 LOGEVENT("TOUCH_HOLD: %d,%d\n", x, y);
236 PageManager::NotifyTouch(TOUCH_HOLD, x, y);
that9fa51532015-01-29 02:04:47 +0100237 }
238 else if (touch_status == TS_TOUCH_REPEAT && mtime > touch_repeat_ms)
239 {
240 LOGEVENT("TOUCH_REPEAT: %d,%d\n", x, y);
241 gettimeofday(&touchStart, NULL);
242 PageManager::NotifyTouch(TOUCH_REPEAT, x, y);
that9fa51532015-01-29 02:04:47 +0100243 }
244 else if (key_status == KS_KEY_PRESSED && mtime > key_hold_ms)
245 {
246 LOGEVENT("KEY_HOLD: %d,%d\n", x, y);
247 gettimeofday(&touchStart, NULL);
248 key_status = KS_KEY_REPEAT;
249 kb->KeyRepeat();
that9fa51532015-01-29 02:04:47 +0100250 }
251 else if (key_status == KS_KEY_REPEAT && mtime > key_repeat_ms)
252 {
253 LOGEVENT("KEY_REPEAT: %d,%d\n", x, y);
254 gettimeofday(&touchStart, NULL);
255 kb->KeyRepeat();
that9fa51532015-01-29 02:04:47 +0100256 }
257}
258
259void InputHandler::doTouchStart()
260{
261 LOGEVENT("TOUCH_START: %d,%d\n", x, y);
262 if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
263 state = AS_NO_ACTION;
264 else
265 state = AS_IN_ACTION_AREA;
266 touch_status = TS_TOUCH_AND_HOLD;
267 gettimeofday(&touchStart, NULL);
that9fa51532015-01-29 02:04:47 +0100268}
269
270void InputHandler::process_EV_ABS(input_event& ev)
271{
272 x = ev.value >> 16;
273 y = ev.value & 0xFFFF;
274
275 if (ev.code == 0)
276 {
Ethan Yonker30fa3352015-03-09 13:57:21 -0500277#ifndef TW_USE_KEY_CODE_TOUCH_SYNC
that9fa51532015-01-29 02:04:47 +0100278 if (state == AS_IN_ACTION_AREA)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500279 {
that9fa51532015-01-29 02:04:47 +0100280 LOGEVENT("TOUCH_RELEASE: %d,%d\n", x, y);
281 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
that9fa51532015-01-29 02:04:47 +0100282 }
283 touch_status = TS_NONE;
Ethan Yonker30fa3352015-03-09 13:57:21 -0500284#endif
that9fa51532015-01-29 02:04:47 +0100285 }
286 else
287 {
288 if (!touch_status)
289 {
Ethan Yonker30fa3352015-03-09 13:57:21 -0500290#ifndef TW_USE_KEY_CODE_TOUCH_SYNC
that9fa51532015-01-29 02:04:47 +0100291 doTouchStart();
Ethan Yonker30fa3352015-03-09 13:57:21 -0500292#endif
Ethan Yonkere13fa632015-01-27 11:30:03 -0600293 }
294 else
295 {
that9fa51532015-01-29 02:04:47 +0100296 if (state == AS_IN_ACTION_AREA)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600297 {
that9fa51532015-01-29 02:04:47 +0100298 LOGEVENT("TOUCH_DRAG: %d,%d\n", x, y);
Dees_Troy51a0e822012-09-05 15:24:24 -0400299 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500300 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500301 }
that9fa51532015-01-29 02:04:47 +0100302}
303
304void InputHandler::process_EV_KEY(input_event& ev)
305{
306 HardwareKeyboard *kb = PageManager::GetHardwareKeyboard();
307
308 // Handle key-press here
309 LOGEVENT("TOUCH_KEY: %d\n", ev.code);
310 // Left mouse button is treated as a touch
Matt Mowera8a89d12016-12-30 18:10:37 -0600311 if (ev.code == BTN_LEFT)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600312 {
that9fa51532015-01-29 02:04:47 +0100313 MouseCursor *cursor = PageManager::GetMouseCursor();
Matt Mowera8a89d12016-12-30 18:10:37 -0600314 if (ev.value == 1)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600315 {
that9fa51532015-01-29 02:04:47 +0100316 cursor->GetPos(x, y);
317 doTouchStart();
318 }
Matt Mowera8a89d12016-12-30 18:10:37 -0600319 else if (touch_status)
that9fa51532015-01-29 02:04:47 +0100320 {
321 // Left mouse button was previously pressed and now is
322 // being released so send a TOUCH_RELEASE
323 if (state == AS_IN_ACTION_AREA)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600324 {
325 cursor->GetPos(x, y);
Ethan Yonkere13fa632015-01-27 11:30:03 -0600326
that9fa51532015-01-29 02:04:47 +0100327 LOGEVENT("Mouse TOUCH_RELEASE: %d,%d\n", x, y);
328 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
Ethan Yonkere13fa632015-01-27 11:30:03 -0600329 }
that9fa51532015-01-29 02:04:47 +0100330 touch_status = TS_NONE;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600331 }
that9fa51532015-01-29 02:04:47 +0100332 }
333 // side mouse button, often used for "back" function
Matt Mowera8a89d12016-12-30 18:10:37 -0600334 else if (ev.code == BTN_SIDE)
that9fa51532015-01-29 02:04:47 +0100335 {
Matt Mowera8a89d12016-12-30 18:10:37 -0600336 if (ev.value == 1)
that9fa51532015-01-29 02:04:47 +0100337 kb->KeyDown(KEY_BACK);
338 else
339 kb->KeyUp(KEY_BACK);
340 } else if (ev.value != 0) {
341 // This is a key press
Ethan Yonker30fa3352015-03-09 13:57:21 -0500342#ifdef TW_USE_KEY_CODE_TOUCH_SYNC
343 if (ev.code == TW_USE_KEY_CODE_TOUCH_SYNC) {
344 LOGEVENT("key code %i key press == touch start %i %i\n", TW_USE_KEY_CODE_TOUCH_SYNC, x, y);
345 doTouchStart();
346 return;
347 }
348#endif
that9fa51532015-01-29 02:04:47 +0100349 if (kb->KeyDown(ev.code)) {
350 // Key repeat is enabled for this key
351 key_status = KS_KEY_PRESSED;
352 touch_status = TS_NONE;
353 gettimeofday(&touchStart, NULL);
Ethan Yonkere13fa632015-01-27 11:30:03 -0600354 } else {
Ethan Yonkere13fa632015-01-27 11:30:03 -0600355 key_status = KS_NONE;
356 touch_status = TS_NONE;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600357 }
that9fa51532015-01-29 02:04:47 +0100358 } else {
359 // This is a key release
360 kb->KeyUp(ev.code);
361 key_status = KS_NONE;
362 touch_status = TS_NONE;
Ethan Yonker30fa3352015-03-09 13:57:21 -0500363#ifdef TW_USE_KEY_CODE_TOUCH_SYNC
364 if (ev.code == TW_USE_KEY_CODE_TOUCH_SYNC) {
365 LOGEVENT("key code %i key release == touch release %i %i\n", TW_USE_KEY_CODE_TOUCH_SYNC, x, y);
366 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
367 }
368#endif
Ethan Yonkere13fa632015-01-27 11:30:03 -0600369 }
that9fa51532015-01-29 02:04:47 +0100370}
Ethan Yonkere13fa632015-01-27 11:30:03 -0600371
that9fa51532015-01-29 02:04:47 +0100372void InputHandler::process_EV_REL(input_event& ev)
373{
374 // Mouse movement
375 MouseCursor *cursor = PageManager::GetMouseCursor();
376 LOGEVENT("EV_REL %d %d\n", ev.code, ev.value);
Matt Mowera8a89d12016-12-30 18:10:37 -0600377 if (ev.code == REL_X)
that9fa51532015-01-29 02:04:47 +0100378 cursor->Move(ev.value, 0);
Matt Mowera8a89d12016-12-30 18:10:37 -0600379 else if (ev.code == REL_Y)
that9fa51532015-01-29 02:04:47 +0100380 cursor->Move(0, ev.value);
381
Matt Mowera8a89d12016-12-30 18:10:37 -0600382 if (touch_status) {
that9fa51532015-01-29 02:04:47 +0100383 cursor->GetPos(x, y);
384 LOGEVENT("Mouse TOUCH_DRAG: %d, %d\n", x, y);
385 key_status = KS_NONE;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600386 }
that9fa51532015-01-29 02:04:47 +0100387}
388
389void InputHandler::handleDrag()
390{
391 // This allows us to only send one NotifyTouch event per render
392 // cycle to reduce overhead and perceived input latency.
393 static int prevx = 0, prevy = 0; // these track where the last drag notice was so that we don't send duplicate drag notices
394 if (touch_status && (x != prevx || y != prevy)) {
395 prevx = x;
396 prevy = y;
397 if (PageManager::NotifyTouch(TOUCH_DRAG, x, y) > 0)
398 state = AS_NO_ACTION;
399 else
400 state = AS_IN_ACTION_AREA;
401 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400402}
403
Ethan Yonker6e8c27a2016-12-22 17:55:57 -0600404void set_select_fd() {
405 select_fd = ors_read_fd + 1;
406 if (g_pty_fd >= select_fd)
407 select_fd = g_pty_fd + 1;
408 if (PartitionManager.uevent_pfd.fd >= select_fd)
409 select_fd = PartitionManager.uevent_pfd.fd + 1;
410}
411
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600412static void setup_ors_command()
Ethan Yonker03a42f62014-08-08 11:03:51 -0500413{
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600414 ors_read_fd = -1;
Ethan Yonker6e8c27a2016-12-22 17:55:57 -0600415 set_select_fd();
Ethan Yonker03a42f62014-08-08 11:03:51 -0500416
417 unlink(ORS_INPUT_FILE);
418 if (mkfifo(ORS_INPUT_FILE, 06660) != 0) {
419 LOGINFO("Unable to mkfifo %s\n", ORS_INPUT_FILE);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600420 return;
Ethan Yonker03a42f62014-08-08 11:03:51 -0500421 }
422 unlink(ORS_OUTPUT_FILE);
423 if (mkfifo(ORS_OUTPUT_FILE, 06666) != 0) {
424 LOGINFO("Unable to mkfifo %s\n", ORS_OUTPUT_FILE);
425 unlink(ORS_INPUT_FILE);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600426 return;
Ethan Yonker03a42f62014-08-08 11:03:51 -0500427 }
428
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600429 ors_read_fd = open(ORS_INPUT_FILE, O_RDONLY | O_NONBLOCK);
430 if (ors_read_fd < 0) {
Ethan Yonker03a42f62014-08-08 11:03:51 -0500431 LOGINFO("Unable to open %s\n", ORS_INPUT_FILE);
432 unlink(ORS_INPUT_FILE);
433 unlink(ORS_OUTPUT_FILE);
Ethan Yonker03a42f62014-08-08 11:03:51 -0500434 }
Ethan Yonker6e8c27a2016-12-22 17:55:57 -0600435 set_select_fd();
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600436}
Ethan Yonker03a42f62014-08-08 11:03:51 -0500437
that10ae24f2015-12-26 20:53:51 +0100438// callback called after a CLI command was executed
439static void ors_command_done()
440{
441 gui_set_FILE(NULL);
442 fclose(orsout);
443 orsout = NULL;
444
445 if (DataManager::GetIntValue("tw_page_done") == 0) {
446 // The select function will return ready to read and the
447 // read function will return errno 19 no such device unless
448 // we set everything up all over again.
449 close(ors_read_fd);
450 setup_ors_command();
451 }
452}
453
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600454static void ors_command_read()
455{
that10ae24f2015-12-26 20:53:51 +0100456 char command[1024];
457 int read_ret = read(ors_read_fd, &command, sizeof(command));
Ethan Yonker03a42f62014-08-08 11:03:51 -0500458
that10ae24f2015-12-26 20:53:51 +0100459 if (read_ret > 0) {
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600460 command[1022] = '\n';
461 command[1023] = '\0';
462 LOGINFO("Command '%s' received\n", command);
463 orsout = fopen(ORS_OUTPUT_FILE, "w");
464 if (!orsout) {
465 close(ors_read_fd);
466 ors_read_fd = -1;
Ethan Yonker6e8c27a2016-12-22 17:55:57 -0600467 set_select_fd();
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600468 LOGINFO("Unable to fopen %s\n", ORS_OUTPUT_FILE);
469 unlink(ORS_INPUT_FILE);
470 unlink(ORS_OUTPUT_FILE);
471 return;
472 }
473 if (DataManager::GetIntValue("tw_busy") != 0) {
that10ae24f2015-12-26 20:53:51 +0100474 fputs("Failed, operation in progress\n", orsout);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600475 LOGINFO("Command cannot be performed, operation in progress.\n");
that10ae24f2015-12-26 20:53:51 +0100476 fclose(orsout);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600477 } else {
Ethan Yonker74db1572015-10-28 12:44:49 -0500478 if (strlen(command) == 11 && strncmp(command, "dumpstrings", 11) == 0) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500479 gui_set_FILE(orsout);
480 PageManager::GetResources()->DumpStrings();
that10ae24f2015-12-26 20:53:51 +0100481 ors_command_done();
Ethan Yonker64e0a652018-07-25 09:52:17 -0500482 } else if (strlen(command) == 11 && strncmp(command, "reloadtheme", 11) == 0) {
483 PageManager::RequestReload();
484 ors_command_done();
485 } else if (strlen(command) > 11 && strncmp(command, "changepage=", 11) == 0) {
486 char* pg = &command[11];
487 gui_changePage(pg);
488 ors_command_done();
that10ae24f2015-12-26 20:53:51 +0100489 } else {
490 // mirror output messages
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600491 gui_set_FILE(orsout);
that10ae24f2015-12-26 20:53:51 +0100492 // close orsout and restart listener after command is done
493 OpenRecoveryScript::Call_After_CLI_Command(ors_command_done);
494 // run the command in a threaded action...
495 DataManager::SetValue("tw_action", "twcmd");
496 DataManager::SetValue("tw_action_param", command);
497 // ...and switch back to the current page when finished
498 std::string currentPage = PageManager::GetCurrentPage();
499 DataManager::SetValue("tw_has_action2", "1");
500 DataManager::SetValue("tw_action2", "page");
501 DataManager::SetValue("tw_action2_param", currentPage);
502 DataManager::SetValue("tw_action_text1", gui_lookup("running_recovery_commands", "Running Recovery Commands"));
503 DataManager::SetValue("tw_action_text2", "");
504 gui_changePage("singleaction_page");
505 // now immediately return to the GUI main loop (the action runs in the background thread)
506 // put all things that need to be done after the command is finished into ors_command_done, not here
Ethan Yonker03a42f62014-08-08 11:03:51 -0500507 }
Ethan Yonker03a42f62014-08-08 11:03:51 -0500508 }
509 }
Ethan Yonker03a42f62014-08-08 11:03:51 -0500510}
511
that10ae24f2015-12-26 20:53:51 +0100512// Get and dispatch input events until it's time to draw the next frame
Dees_Troy51a0e822012-09-05 15:24:24 -0400513// This special function will return immediately the first time, but then
514// always returns 1/30th of a second (or immediately if called later) from
515// the last time it was called
thatde72b6d2015-02-08 08:55:00 +0100516static void loopTimer(int input_timeout_ms)
Dees_Troy51a0e822012-09-05 15:24:24 -0400517{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200518 static timespec lastCall;
519 static int initialized = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400520
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200521 if (!initialized)
Dees_Troyc8b199c2012-09-24 11:55:07 -0400522 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200523 clock_gettime(CLOCK_MONOTONIC, &lastCall);
524 initialized = 1;
525 return;
Dees_Troyc8b199c2012-09-24 11:55:07 -0400526 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400527
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200528 do
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500529 {
thatde72b6d2015-02-08 08:55:00 +0100530 bool got_event = input_handler.processInput(input_timeout_ms); // get inputs but don't send drag notices
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200531 timespec curTime;
532 clock_gettime(CLOCK_MONOTONIC, &curTime);
Dees_Troy51a0e822012-09-05 15:24:24 -0400533
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200534 timespec diff = TWFunc::timespec_diff(lastCall, curTime);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500535
Alexander Winkowski5d3e4882022-06-25 18:56:33 +0000536 // This is really 2 or TW_FRAMERATE times per second
thatc5837f32015-02-01 01:59:43 +0100537 // As long as we get events, increase the timeout so we can catch up with input
Alexander Winkowski5d3e4882022-06-25 18:56:33 +0000538 long timeout = got_event ? 500000000 : (1.0 / TW_FRAMERATE * 1000000000);
thatc5837f32015-02-01 01:59:43 +0100539
540 if (diff.tv_sec || diff.tv_nsec > timeout)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500541 {
thatc5837f32015-02-01 01:59:43 +0100542 // int32_t input_time = TWFunc::timespec_diff_ms(lastCall, curTime);
543 // LOGINFO("loopTimer(): %u ms, count: %u\n", input_time, count);
544
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200545 lastCall = curTime;
that9fa51532015-01-29 02:04:47 +0100546 input_handler.handleDrag(); // send only drag notices if needed
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200547 return;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500548 }
549
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200550 // We need to sleep some period time microseconds
Ethan Yonkere13fa632015-01-27 11:30:03 -0600551 //unsigned int sleepTime = 33333 -(diff.tv_nsec / 1000);
552 //usleep(sleepTime); // removed so we can scan for input
thatde72b6d2015-02-08 08:55:00 +0100553 input_timeout_ms = 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200554 } while (1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400555}
556
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600557static int runPages(const char *page_name, const int stop_on_page_done)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500558{
Ethan Yonker3f15be42015-02-09 09:39:47 -0600559 DataManager::SetValue("tw_page_done", 0);
560 DataManager::SetValue("tw_gui_done", 0);
561
Ethan Yonkerafde0982016-01-23 08:55:35 -0600562 if (page_name) {
563 PageManager::SetStartPage(page_name);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600564 gui_changePage(page_name);
Ethan Yonkerafde0982016-01-23 08:55:35 -0600565 }
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600566
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200567 gGuiRunning = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500568
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200569 DataManager::SetValue("tw_loaded", 1);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500570
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600571 struct timeval timeout;
572 fd_set fdset;
573 int has_data = 0;
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100574
thatde72b6d2015-02-08 08:55:00 +0100575 int input_timeout_ms = 0;
576 int idle_frames = 0;
577
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200578 for (;;)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500579 {
thatde72b6d2015-02-08 08:55:00 +0100580 loopTimer(input_timeout_ms);
Ethan Yonker6e8c27a2016-12-22 17:55:57 -0600581 FD_ZERO(&fdset);
582 timeout.tv_sec = 0;
583 timeout.tv_usec = 1;
that1964d192016-01-07 00:41:03 +0100584 if (g_pty_fd > 0) {
that1964d192016-01-07 00:41:03 +0100585 FD_SET(g_pty_fd, &fdset);
Ethan Yonker6e8c27a2016-12-22 17:55:57 -0600586 }
587 if (PartitionManager.uevent_pfd.fd > 0) {
588 FD_SET(PartitionManager.uevent_pfd.fd, &fdset);
that1964d192016-01-07 00:41:03 +0100589 }
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600590#ifndef TW_OEM_BUILD
that10ae24f2015-12-26 20:53:51 +0100591 if (ors_read_fd > 0 && !orsout) { // orsout is non-NULL if a command is still running
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600592 FD_SET(ors_read_fd, &fdset);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600593 }
594#endif
Ethan Yonker6e8c27a2016-12-22 17:55:57 -0600595 // TODO: combine this select with the poll done by input handling
596 has_data = select(select_fd, &fdset, NULL, NULL, &timeout);
597 if (has_data > 0) {
598 if (g_pty_fd > 0 && FD_ISSET(g_pty_fd, &fdset))
599 terminal_pty_read();
600 if (PartitionManager.uevent_pfd.fd > 0 && FD_ISSET(PartitionManager.uevent_pfd.fd, &fdset))
601 PartitionManager.read_uevent();
602 if (ors_read_fd > 0 && !orsout && FD_ISSET(ors_read_fd, &fdset))
603 ors_command_read();
604 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500605
Ethan Yonker04536952015-01-27 08:41:28 -0600606 if (!gForceRender.get_value())
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500607 {
thatde72b6d2015-02-08 08:55:00 +0100608 int ret = PageManager::Update();
609 if (ret == 0)
610 ++idle_frames;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500611 else if (ret == -2)
612 break; // Theme reload failure
thatde72b6d2015-02-08 08:55:00 +0100613 else
614 idle_frames = 0;
615 // due to possible animation objects, we need to delay activating the input timeout
616 input_timeout_ms = idle_frames > 15 ? 1000 : 0;
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100617
618#ifndef PRINT_RENDER_TIME
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200619 if (ret > 1)
620 PageManager::Render();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500621
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200622 if (ret > 0)
623 flip();
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100624#else
625 if (ret > 1)
626 {
that9fa51532015-01-29 02:04:47 +0100627 timespec start, end;
628 int32_t render_t, flip_t;
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100629 clock_gettime(CLOCK_MONOTONIC, &start);
630 PageManager::Render();
631 clock_gettime(CLOCK_MONOTONIC, &end);
632 render_t = TWFunc::timespec_diff_ms(start, end);
633
634 flip();
635 clock_gettime(CLOCK_MONOTONIC, &start);
636 flip_t = TWFunc::timespec_diff_ms(end, start);
637
638 LOGINFO("Render(): %u ms, flip(): %u ms, total: %u ms\n", render_t, flip_t, render_t+flip_t);
639 }
thatde72b6d2015-02-08 08:55:00 +0100640 else if (ret > 0)
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100641 flip();
642#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500643 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200644 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500645 {
Ethan Yonker04536952015-01-27 08:41:28 -0600646 gForceRender.set_value(0);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200647 PageManager::Render();
648 flip();
thatde72b6d2015-02-08 08:55:00 +0100649 input_timeout_ms = 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500650 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200651
thatfb759d42015-01-11 12:16:53 +0100652 blankTimer.checkForTimeout();
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600653 if (stop_on_page_done && DataManager::GetIntValue("tw_page_done") != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200654 {
655 gui_changePage("main");
Dees_Troy6ef66352013-02-21 08:26:57 -0600656 break;
657 }
bigbiffdf8436b2020-08-30 16:22:34 -0400658 if (DataManager::GetIntValue("tw_gui_done") != 0) {
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600659 break;
bigbiffdf8436b2020-08-30 16:22:34 -0400660 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500661 }
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600662 if (ors_read_fd > 0)
663 close(ors_read_fd);
664 ors_read_fd = -1;
Ethan Yonker6e8c27a2016-12-22 17:55:57 -0600665 set_select_fd();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200666 gGuiRunning = 0;
667 return 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500668}
669
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200670int gui_forceRender(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500671{
Ethan Yonker04536952015-01-27 08:41:28 -0600672 gForceRender.set_value(1);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200673 return 0;
674}
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500675
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200676int gui_changePage(std::string newPage)
677{
678 LOGINFO("Set page: '%s'\n", newPage.c_str());
679 PageManager::ChangePage(newPage);
Ethan Yonker04536952015-01-27 08:41:28 -0600680 gForceRender.set_value(1);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200681 return 0;
682}
683
684int gui_changeOverlay(std::string overlay)
685{
Ethan Yonker1c273312015-03-16 12:18:56 -0500686 LOGINFO("Set overlay: '%s'\n", overlay.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200687 PageManager::ChangeOverlay(overlay);
Ethan Yonker04536952015-01-27 08:41:28 -0600688 gForceRender.set_value(1);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200689 return 0;
690}
691
thatb2e8f672015-03-05 20:25:39 +0100692std::string gui_parse_text(std::string str)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200693{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200694 // This function parses text for DataManager values encompassed by %value% in the XML
thatb2e8f672015-03-05 20:25:39 +0100695 // and string resources (%@resource_name%)
Ethan Yonker74db1572015-10-28 12:44:49 -0500696 size_t pos = 0, next, end;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200697
698 while (1)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500699 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500700 next = str.find("{@", pos);
701 if (next == std::string::npos)
702 break;
703
704 end = str.find('}', next + 1);
705 if (end == std::string::npos)
706 break;
707
708 std::string var = str.substr(next + 2, (end - next) - 2);
709 str.erase(next, (end - next) + 1);
710
711 size_t default_loc = var.find('=', 0);
712 std::string lookup;
713 if (default_loc == std::string::npos) {
714 str.insert(next, PageManager::GetResources()->FindString(var));
715 } else {
716 lookup = var.substr(0, default_loc);
717 std::string default_string = var.substr(default_loc + 1, var.size() - default_loc - 1);
718 str.insert(next, PageManager::GetResources()->FindString(lookup, default_string));
719 }
720 }
721 pos = 0;
722 while (1)
723 {
724 next = str.find('%', pos);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200725 if (next == std::string::npos)
726 return str;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500727
Ethan Yonker74db1572015-10-28 12:44:49 -0500728 end = str.find('%', next + 1);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200729 if (end == std::string::npos)
730 return str;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500731
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200732 // We have a block of data
thatb2e8f672015-03-05 20:25:39 +0100733 std::string var = str.substr(next + 1, (end - next) - 1);
734 str.erase(next, (end - next) + 1);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500735
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200736 if (next + 1 == end)
737 str.insert(next, 1, '%');
738 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500739 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200740 std::string value;
thatb2e8f672015-03-05 20:25:39 +0100741 if (var.size() > 0 && var[0] == '@') {
742 // this is a string resource ("%@string_name%")
743 value = PageManager::GetResources()->FindString(var.substr(1));
744 str.insert(next, value);
745 }
746 else if (DataManager::GetValue(var, value) == 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200747 str.insert(next, value);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500748 }
749
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200750 pos = next + 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500751 }
752}
753
Ethan Yonker74db1572015-10-28 12:44:49 -0500754std::string gui_lookup(const std::string& resource_name, const std::string& default_value) {
755 return PageManager::GetResources()->FindString(resource_name, default_value);
756}
757
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200758extern "C" int gui_init(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500759{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200760 gr_init();
Matt Mowerb26c1162016-02-03 21:05:57 -0600761 TWFunc::Set_Brightness(DataManager::GetStrValue("tw_brightness"));
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500762
Sean hoytc3876222018-07-15 06:16:09 +0200763#ifdef TW_SCREEN_BLANK_ON_BOOT
764 printf("TW_SCREEN_BLANK_ON_BOOT := true\n");
765 blankTimer.blank();
766 blankTimer.resetTimerAndUnblank();
767#endif
768
that235c6482016-01-24 21:59:00 +0100769 // load and show splash screen
770 if (PageManager::LoadPackage("splash", TWRES "splash.xml", "splash")) {
771 LOGERR("Failed to load splash screen XML.\n");
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500772 }
that235c6482016-01-24 21:59:00 +0100773 else {
774 PageManager::SelectPackage("splash");
775 PageManager::Render();
776 flip();
777 PageManager::ReleasePackage("splash");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600778 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500779
bigbiff1f780662020-06-26 16:14:32 -0400780#ifdef TW_DELAY_TOUCH_INIT_MS
781 usleep(TW_DELAY_TOUCH_INIT_MS);
782#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200783 ev_init();
784 return 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500785}
786
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200787extern "C" int gui_loadResources(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400788{
Ethan Yonker83e82572014-04-04 10:59:28 -0500789#ifndef TW_OEM_BUILD
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200790 int check = 0;
791 DataManager::GetValue(TW_IS_ENCRYPTED, check);
792 if (check)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500793 {
Dees Troy3454ade2015-01-20 19:21:04 +0000794 if (PageManager::LoadPackage("TWRP", TWRES "ui.xml", "decrypt"))
Dees_Troy5bf43922012-09-07 16:07:55 -0400795 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500796 gui_err("base_pkg_err=Failed to load base packages.");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200797 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400798 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200799 else
800 check = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500801 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400802
Ethan Yonker86404bd2016-03-31 08:01:05 -0500803 if (check == 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200804 {
805 std::string theme_path;
806
Fernando Oliveira25062d72023-02-01 12:52:32 -0300807 theme_path = DataManager::GetCurrentStoragePath();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200808 if (!PartitionManager.Mount_Settings_Storage(false))
Dees_Troy51a0e822012-09-05 15:24:24 -0400809 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200810 int retry_count = 5;
811 while (retry_count > 0 && !PartitionManager.Mount_Settings_Storage(false))
Dees_Troy51a0e822012-09-05 15:24:24 -0400812 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200813 usleep(500000);
814 retry_count--;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500815 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200816
Ethan Yonker74db1572015-10-28 12:44:49 -0500817 if (!PartitionManager.Mount_Settings_Storage(true))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500818 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500819 LOGINFO("Unable to mount %s during GUI startup.\n", theme_path.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200820 check = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500821 }
822 }
823
Fernando Oliveira27d676a2023-01-12 16:12:55 -0300824 theme_path += TWFunc::Check_For_TwrpFolder() + "/theme/ui.zip";
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200825 if (check || PageManager::LoadPackage("TWRP", theme_path, "main"))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500826 {
Ethan Yonker83e82572014-04-04 10:59:28 -0500827#endif // ifndef TW_OEM_BUILD
Dees Troy3454ade2015-01-20 19:21:04 +0000828 if (PageManager::LoadPackage("TWRP", TWRES "ui.xml", "main"))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500829 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500830 gui_err("base_pkg_err=Failed to load base packages.");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200831 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400832 }
Ethan Yonker83e82572014-04-04 10:59:28 -0500833#ifndef TW_OEM_BUILD
Dees_Troy51a0e822012-09-05 15:24:24 -0400834 }
835 }
Ethan Yonker83e82572014-04-04 10:59:28 -0500836#endif // ifndef TW_OEM_BUILD
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200837 // Set the default package
838 PageManager::SelectPackage("TWRP");
Dees_Troy51a0e822012-09-05 15:24:24 -0400839
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200840 gGuiInitialized = 1;
841 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400842
843error:
Ethan Yonker83e82572014-04-04 10:59:28 -0500844 LOGERR("An internal error has occurred: unable to load theme.\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200845 gGuiInitialized = 0;
846 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400847}
848
Ethan Yonkercf50da52015-01-12 21:59:07 -0600849extern "C" int gui_loadCustomResources(void)
850{
851#ifndef TW_OEM_BUILD
852 if (!PartitionManager.Mount_Settings_Storage(false)) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500853 LOGINFO("Unable to mount settings storage during GUI startup.\n");
Ethan Yonkercf50da52015-01-12 21:59:07 -0600854 return -1;
855 }
856
Fernando Oliveira25062d72023-02-01 12:52:32 -0300857 std::string theme_path = DataManager::GetCurrentStoragePath();
Fernando Oliveira27d676a2023-01-12 16:12:55 -0300858 theme_path += TWFunc::Check_For_TwrpFolder() + "/theme/ui.zip";
Ethan Yonkercf50da52015-01-12 21:59:07 -0600859 // Check for a custom theme
860 if (TWFunc::Path_Exists(theme_path)) {
861 // There is a custom theme, try to load it
862 if (PageManager::ReloadPackage("TWRP", theme_path)) {
863 // Custom theme failed to load, try to load stock theme
Dees Troy3454ade2015-01-20 19:21:04 +0000864 if (PageManager::ReloadPackage("TWRP", TWRES "ui.xml")) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500865 gui_err("base_pkg_err=Failed to load base packages.");
Ethan Yonkercf50da52015-01-12 21:59:07 -0600866 goto error;
867 }
868 }
869 }
870 // Set the default package
871 PageManager::SelectPackage("TWRP");
872#endif
873 return 0;
874
Patrick Zacharias0edce1a2020-06-06 16:02:58 +0200875#ifndef TW_OEM_BUILD
Ethan Yonkercf50da52015-01-12 21:59:07 -0600876error:
877 LOGERR("An internal error has occurred: unable to load theme.\n");
878 gGuiInitialized = 0;
879 return -1;
Patrick Zacharias0edce1a2020-06-06 16:02:58 +0200880#endif
Ethan Yonkercf50da52015-01-12 21:59:07 -0600881}
882
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200883extern "C" int gui_start(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400884{
Ethan Yonkerafde0982016-01-23 08:55:35 -0600885 return gui_startPage("main", 1, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400886}
887
Patrick Zacharias0edce1a2020-06-06 16:02:58 +0200888extern "C" int gui_startPage(const char *page_name, __attribute__((unused)) const int allow_commands, int stop_on_page_done)
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000889{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200890 if (!gGuiInitialized)
891 return -1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000892
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200893 // Set the default package
894 PageManager::SelectPackage("TWRP");
895
that9fa51532015-01-29 02:04:47 +0100896 input_handler.init();
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600897#ifndef TW_OEM_BUILD
898 if (allow_commands)
899 {
900 if (ors_read_fd < 0)
901 setup_ors_command();
902 } else {
903 if (ors_read_fd >= 0) {
904 close(ors_read_fd);
905 ors_read_fd = -1;
906 }
907 }
908#endif
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600909 return runPages(page_name, stop_on_page_done);
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000910}
911
Ethan Yonker63e414f2015-02-06 15:44:39 -0600912
913extern "C" void set_scale_values(float w, float h)
914{
915 scale_theme_w = w;
916 scale_theme_h = h;
917}
918
919extern "C" int scale_theme_x(int initial_x)
920{
921 if (scale_theme_w != 1) {
thatba75a0e2015-02-14 21:20:10 +0100922 int scaled = (float)initial_x * scale_theme_w;
923 if (scaled == 0 && initial_x > 0)
924 return 1;
925 return scaled;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600926 }
927 return initial_x;
928}
929
930extern "C" int scale_theme_y(int initial_y)
931{
932 if (scale_theme_h != 1) {
thatba75a0e2015-02-14 21:20:10 +0100933 int scaled = (float)initial_y * scale_theme_h;
934 if (scaled == 0 && initial_y > 0)
935 return 1;
936 return scaled;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600937 }
938 return initial_y;
939}
940
941extern "C" int scale_theme_min(int initial_value)
942{
943 if (scale_theme_w != 1 || scale_theme_h != 1) {
944 if (scale_theme_w < scale_theme_h)
945 return scale_theme_x(initial_value);
946 else
947 return scale_theme_y(initial_value);
948 }
949 return initial_value;
950}
951
952extern "C" float get_scale_w()
953{
954 return scale_theme_w;
955}
956
957extern "C" float get_scale_h()
958{
959 return scale_theme_h;
960}