blob: 63baeee92a6618f5c1635f7a8473186fdbd9be22 [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>
36#include <stdlib.h>
37
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050038extern "C"
39{
Dees_Troy2673cec2013-04-02 20:22:16 +000040#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040041#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040042#include <pixelflinger/pixelflinger.h>
43}
44
45#include "rapidxml.hpp"
46#include "objects.hpp"
47#include "../data.hpp"
48#include "../variables.h"
Dees_Troy5bf43922012-09-07 16:07:55 -040049#include "../partitions.hpp"
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050050#include "../twrp-functions.hpp"
Ethan Yonker03a42f62014-08-08 11:03:51 -050051#include "../openrecoveryscript.hpp"
52#include "../orscmd/orscmd.h"
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050053#include "blanktimer.hpp"
Ethan Yonker04536952015-01-27 08:41:28 -060054#include "../tw_atomic.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040055
Vojtech Boceke5ffcd12014-02-06 21:17:32 +010056// Enable to print render time of each frame to the log file
57//#define PRINT_RENDER_TIME 1
58
that9fa51532015-01-29 02:04:47 +010059#ifdef _EVENT_LOGGING
thatc5837f32015-02-01 01:59:43 +010060#define LOGEVENT(...) LOGERR(__VA_ARGS__)
that9fa51532015-01-29 02:04:47 +010061#else
62#define LOGEVENT(...) do {} while (0)
63#endif
64
Dees_Troy51a0e822012-09-05 15:24:24 -040065const static int CURTAIN_FADE = 32;
66
67using namespace rapidxml;
68
69// Global values
70static gr_surface gCurtain = NULL;
71static int gGuiInitialized = 0;
Ethan Yonker04536952015-01-27 08:41:28 -060072static TWAtomicInt gForceRender;
73const int gNoAnimation = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050074blanktimer blankTimer;
Ethan Yonkerfd0439e2015-01-14 11:08:13 -060075int ors_read_fd = -1;
that10ae24f2015-12-26 20:53:51 +010076static FILE* orsout = NULL;
Ethan Yonker63e414f2015-02-06 15:44:39 -060077static float scale_theme_w = 1;
78static float scale_theme_h = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -040079
80// Needed by pages.cpp too
81int gGuiRunning = 0;
82
83static 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
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020087void 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
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200107static void curtainSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400108{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200109 gr_color(0, 0, 0, 255);
110 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Ethan Yonker751a85e2014-12-12 16:59:10 -0600111 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), TW_X_OFFSET, TW_Y_OFFSET);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200112 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400113}
114
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200115static void curtainRaise(gr_surface surface)
Dees_Troy51a0e822012-09-05 15:24:24 -0400116{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200117 int sy = 0;
118 int h = gr_get_height(gCurtain) - 1;
119 int w = gr_get_width(gCurtain);
120 int fy = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400121
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200122 int msw = gr_get_width(surface);
123 int msh = gr_get_height(surface);
124 int CURTAIN_RATE = msh / 30;
Dees_Troy51a0e822012-09-05 15:24:24 -0400125
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200126 if (gNoAnimation == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500127 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200128 for (; h > 0; h -= CURTAIN_RATE, sy += CURTAIN_RATE, fy += CURTAIN_RATE)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500129 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200130 gr_blit(surface, 0, 0, msw, msh, 0, 0);
131 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
132 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500133 }
134 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200135 gr_blit(surface, 0, 0, msw, msh, 0, 0);
136 flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400137}
138
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200139void curtainClose()
Dees_Troy51a0e822012-09-05 15:24:24 -0400140{
141#if 0
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200142 int w = gr_get_width(gCurtain);
143 int h = 1;
144 int sy = gr_get_height(gCurtain) - 1;
145 int fbh = gr_fb_height();
146 int CURTAIN_RATE = fbh / 30;
Dees_Troy51a0e822012-09-05 15:24:24 -0400147
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200148 if (gNoAnimation == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500149 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200150 for (; h < fbh; h += CURTAIN_RATE, sy -= CURTAIN_RATE)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500151 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200152 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
153 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500154 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200155 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain),
156 gr_get_height(gCurtain), 0, 0);
157 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400158
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200159 if (gRecorder != -1)
160 close(gRecorder);
Dees_Troy51a0e822012-09-05 15:24:24 -0400161
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200162 int fade;
163 for (fade = 16; fade < 255; fade += CURTAIN_FADE)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500164 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200165 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain),
166 gr_get_height(gCurtain), 0, 0);
167 gr_color(0, 0, 0, fade);
168 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
169 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500170 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200171 gr_color(0, 0, 0, 255);
172 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
173 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400174 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500175#else
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200176 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
177 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500178#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400179}
180
that9fa51532015-01-29 02:04:47 +0100181class InputHandler
Dees_Troy51a0e822012-09-05 15:24:24 -0400182{
that9fa51532015-01-29 02:04:47 +0100183public:
184 void init()
thatfb759d42015-01-11 12:16:53 +0100185 {
that9fa51532015-01-29 02:04:47 +0100186 // these might be read from DataManager in the future
187 touch_hold_ms = 500;
188 touch_repeat_ms = 100;
189 key_hold_ms = 500;
190 key_repeat_ms = 100;
191 touch_status = TS_NONE;
192 key_status = KS_NONE;
193 state = AS_NO_ACTION;
194 x = y = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400195
that9fa51532015-01-29 02:04:47 +0100196#ifndef TW_NO_SCREEN_TIMEOUT
197 {
198 string seconds;
199 DataManager::GetValue("tw_screen_timeout_secs", seconds);
200 blankTimer.setTime(atoi(seconds.c_str()));
201 blankTimer.resetTimerAndUnblank();
Ethan Yonkere13fa632015-01-27 11:30:03 -0600202 }
that9fa51532015-01-29 02:04:47 +0100203#else
204 LOGINFO("Skipping screen timeout: TW_NO_SCREEN_TIMEOUT is set\n");
205#endif
Ethan Yonkere13fa632015-01-27 11:30:03 -0600206 }
207
thatc5837f32015-02-01 01:59:43 +0100208 // process input events. returns true if any event was received.
thatde72b6d2015-02-08 08:55:00 +0100209 bool processInput(int timeout_ms);
thatc5837f32015-02-01 01:59:43 +0100210
that9fa51532015-01-29 02:04:47 +0100211 void handleDrag();
212
213private:
214 // timeouts for touch/key hold and repeat
215 int touch_hold_ms;
216 int touch_repeat_ms;
217 int key_hold_ms;
218 int key_repeat_ms;
219
220 enum touch_status_enum {
221 TS_NONE = 0,
222 TS_TOUCH_AND_HOLD = 1,
223 TS_TOUCH_REPEAT = 2,
224 };
225
226 enum key_status_enum {
227 KS_NONE = 0,
228 KS_KEY_PRESSED = 1,
229 KS_KEY_REPEAT = 2,
230 };
231
232 enum action_state_enum {
233 AS_IN_ACTION_AREA = 0, // we've touched a spot with an action
234 AS_NO_ACTION = 1, // we've touched in an empty area (no action) and ignore remaining events until touch release
235 };
236 touch_status_enum touch_status;
237 key_status_enum key_status;
238 action_state_enum state;
239 int x, y; // x and y coordinates of last touch
240 struct timeval touchStart; // used to track time for long press / key repeat
241
242 void processHoldAndRepeat();
243 void process_EV_REL(input_event& ev);
244 void process_EV_ABS(input_event& ev);
245 void process_EV_KEY(input_event& ev);
246
247 void doTouchStart();
248};
249
250InputHandler input_handler;
251
252
thatde72b6d2015-02-08 08:55:00 +0100253bool InputHandler::processInput(int timeout_ms)
that9fa51532015-01-29 02:04:47 +0100254{
255 input_event ev;
thatde72b6d2015-02-08 08:55:00 +0100256 int ret = ev_get(&ev, timeout_ms);
Ethan Yonkere13fa632015-01-27 11:30:03 -0600257
258 if (ret < 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500259 {
Ethan Yonkere13fa632015-01-27 11:30:03 -0600260 // This path means that we did not get any new touch data, but
261 // we do not get new touch data if you press and hold on either
262 // the screen or on a keyboard key or mouse button
that9fa51532015-01-29 02:04:47 +0100263 if (touch_status || key_status)
264 processHoldAndRepeat();
thatc5837f32015-02-01 01:59:43 +0100265 return (ret != -2); // -2 means no more events in the queue
Ethan Yonkere13fa632015-01-27 11:30:03 -0600266 }
that9fa51532015-01-29 02:04:47 +0100267
268 switch (ev.type)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600269 {
that9fa51532015-01-29 02:04:47 +0100270 case EV_ABS:
271 process_EV_ABS(ev);
272 break;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600273
that9fa51532015-01-29 02:04:47 +0100274 case EV_REL:
275 process_EV_REL(ev);
276 break;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600277
that9fa51532015-01-29 02:04:47 +0100278 case EV_KEY:
279 process_EV_KEY(ev);
280 break;
281 }
thatc5837f32015-02-01 01:59:43 +0100282
283 blankTimer.resetTimerAndUnblank();
284 return true; // we got an event, so there might be more in the queue
that9fa51532015-01-29 02:04:47 +0100285}
286
287void InputHandler::processHoldAndRepeat()
288{
289 HardwareKeyboard *kb = PageManager::GetHardwareKeyboard();
290
291 // touch and key repeat section
292 struct timeval curTime;
293 gettimeofday(&curTime, NULL);
294 long seconds = curTime.tv_sec - touchStart.tv_sec;
295 long useconds = curTime.tv_usec - touchStart.tv_usec;
296 long mtime = ((seconds) * 1000 + useconds / 1000.0) + 0.5;
297
298 if (touch_status == TS_TOUCH_AND_HOLD && mtime > touch_hold_ms)
299 {
300 touch_status = TS_TOUCH_REPEAT;
301 gettimeofday(&touchStart, NULL);
302 LOGEVENT("TOUCH_HOLD: %d,%d\n", x, y);
303 PageManager::NotifyTouch(TOUCH_HOLD, x, y);
that9fa51532015-01-29 02:04:47 +0100304 }
305 else if (touch_status == TS_TOUCH_REPEAT && mtime > touch_repeat_ms)
306 {
307 LOGEVENT("TOUCH_REPEAT: %d,%d\n", x, y);
308 gettimeofday(&touchStart, NULL);
309 PageManager::NotifyTouch(TOUCH_REPEAT, x, y);
that9fa51532015-01-29 02:04:47 +0100310 }
311 else if (key_status == KS_KEY_PRESSED && mtime > key_hold_ms)
312 {
313 LOGEVENT("KEY_HOLD: %d,%d\n", x, y);
314 gettimeofday(&touchStart, NULL);
315 key_status = KS_KEY_REPEAT;
316 kb->KeyRepeat();
that9fa51532015-01-29 02:04:47 +0100317 }
318 else if (key_status == KS_KEY_REPEAT && mtime > key_repeat_ms)
319 {
320 LOGEVENT("KEY_REPEAT: %d,%d\n", x, y);
321 gettimeofday(&touchStart, NULL);
322 kb->KeyRepeat();
that9fa51532015-01-29 02:04:47 +0100323 }
324}
325
326void InputHandler::doTouchStart()
327{
328 LOGEVENT("TOUCH_START: %d,%d\n", x, y);
329 if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
330 state = AS_NO_ACTION;
331 else
332 state = AS_IN_ACTION_AREA;
333 touch_status = TS_TOUCH_AND_HOLD;
334 gettimeofday(&touchStart, NULL);
that9fa51532015-01-29 02:04:47 +0100335}
336
337void InputHandler::process_EV_ABS(input_event& ev)
338{
339 x = ev.value >> 16;
340 y = ev.value & 0xFFFF;
341
342 if (ev.code == 0)
343 {
Ethan Yonker30fa3352015-03-09 13:57:21 -0500344#ifndef TW_USE_KEY_CODE_TOUCH_SYNC
that9fa51532015-01-29 02:04:47 +0100345 if (state == AS_IN_ACTION_AREA)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500346 {
that9fa51532015-01-29 02:04:47 +0100347 LOGEVENT("TOUCH_RELEASE: %d,%d\n", x, y);
348 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
that9fa51532015-01-29 02:04:47 +0100349 }
350 touch_status = TS_NONE;
Ethan Yonker30fa3352015-03-09 13:57:21 -0500351#endif
that9fa51532015-01-29 02:04:47 +0100352 }
353 else
354 {
355 if (!touch_status)
356 {
Ethan Yonker30fa3352015-03-09 13:57:21 -0500357#ifndef TW_USE_KEY_CODE_TOUCH_SYNC
that9fa51532015-01-29 02:04:47 +0100358 doTouchStart();
Ethan Yonker30fa3352015-03-09 13:57:21 -0500359#endif
Ethan Yonkere13fa632015-01-27 11:30:03 -0600360 }
361 else
362 {
that9fa51532015-01-29 02:04:47 +0100363 if (state == AS_IN_ACTION_AREA)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600364 {
that9fa51532015-01-29 02:04:47 +0100365 LOGEVENT("TOUCH_DRAG: %d,%d\n", x, y);
Dees_Troy51a0e822012-09-05 15:24:24 -0400366 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500367 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500368 }
that9fa51532015-01-29 02:04:47 +0100369}
370
371void InputHandler::process_EV_KEY(input_event& ev)
372{
373 HardwareKeyboard *kb = PageManager::GetHardwareKeyboard();
374
375 // Handle key-press here
376 LOGEVENT("TOUCH_KEY: %d\n", ev.code);
377 // Left mouse button is treated as a touch
378 if(ev.code == BTN_LEFT)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600379 {
that9fa51532015-01-29 02:04:47 +0100380 MouseCursor *cursor = PageManager::GetMouseCursor();
381 if(ev.value == 1)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600382 {
that9fa51532015-01-29 02:04:47 +0100383 cursor->GetPos(x, y);
384 doTouchStart();
385 }
386 else if(touch_status)
387 {
388 // Left mouse button was previously pressed and now is
389 // being released so send a TOUCH_RELEASE
390 if (state == AS_IN_ACTION_AREA)
Ethan Yonkere13fa632015-01-27 11:30:03 -0600391 {
392 cursor->GetPos(x, y);
Ethan Yonkere13fa632015-01-27 11:30:03 -0600393
that9fa51532015-01-29 02:04:47 +0100394 LOGEVENT("Mouse TOUCH_RELEASE: %d,%d\n", x, y);
395 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
Ethan Yonkere13fa632015-01-27 11:30:03 -0600396 }
that9fa51532015-01-29 02:04:47 +0100397 touch_status = TS_NONE;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600398 }
that9fa51532015-01-29 02:04:47 +0100399 }
400 // side mouse button, often used for "back" function
401 else if(ev.code == BTN_SIDE)
402 {
403 if(ev.value == 1)
404 kb->KeyDown(KEY_BACK);
405 else
406 kb->KeyUp(KEY_BACK);
407 } else if (ev.value != 0) {
408 // This is a key press
Ethan Yonker30fa3352015-03-09 13:57:21 -0500409#ifdef TW_USE_KEY_CODE_TOUCH_SYNC
410 if (ev.code == TW_USE_KEY_CODE_TOUCH_SYNC) {
411 LOGEVENT("key code %i key press == touch start %i %i\n", TW_USE_KEY_CODE_TOUCH_SYNC, x, y);
412 doTouchStart();
413 return;
414 }
415#endif
that9fa51532015-01-29 02:04:47 +0100416 if (kb->KeyDown(ev.code)) {
417 // Key repeat is enabled for this key
418 key_status = KS_KEY_PRESSED;
419 touch_status = TS_NONE;
420 gettimeofday(&touchStart, NULL);
Ethan Yonkere13fa632015-01-27 11:30:03 -0600421 } else {
Ethan Yonkere13fa632015-01-27 11:30:03 -0600422 key_status = KS_NONE;
423 touch_status = TS_NONE;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600424 }
that9fa51532015-01-29 02:04:47 +0100425 } else {
426 // This is a key release
427 kb->KeyUp(ev.code);
428 key_status = KS_NONE;
429 touch_status = TS_NONE;
Ethan Yonker30fa3352015-03-09 13:57:21 -0500430#ifdef TW_USE_KEY_CODE_TOUCH_SYNC
431 if (ev.code == TW_USE_KEY_CODE_TOUCH_SYNC) {
432 LOGEVENT("key code %i key release == touch release %i %i\n", TW_USE_KEY_CODE_TOUCH_SYNC, x, y);
433 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
434 }
435#endif
Ethan Yonkere13fa632015-01-27 11:30:03 -0600436 }
that9fa51532015-01-29 02:04:47 +0100437}
Ethan Yonkere13fa632015-01-27 11:30:03 -0600438
that9fa51532015-01-29 02:04:47 +0100439void InputHandler::process_EV_REL(input_event& ev)
440{
441 // Mouse movement
442 MouseCursor *cursor = PageManager::GetMouseCursor();
443 LOGEVENT("EV_REL %d %d\n", ev.code, ev.value);
444 if(ev.code == REL_X)
445 cursor->Move(ev.value, 0);
446 else if(ev.code == REL_Y)
447 cursor->Move(0, ev.value);
448
449 if(touch_status) {
450 cursor->GetPos(x, y);
451 LOGEVENT("Mouse TOUCH_DRAG: %d, %d\n", x, y);
452 key_status = KS_NONE;
Ethan Yonkere13fa632015-01-27 11:30:03 -0600453 }
that9fa51532015-01-29 02:04:47 +0100454}
455
456void InputHandler::handleDrag()
457{
458 // This allows us to only send one NotifyTouch event per render
459 // cycle to reduce overhead and perceived input latency.
460 static int prevx = 0, prevy = 0; // these track where the last drag notice was so that we don't send duplicate drag notices
461 if (touch_status && (x != prevx || y != prevy)) {
462 prevx = x;
463 prevy = y;
464 if (PageManager::NotifyTouch(TOUCH_DRAG, x, y) > 0)
465 state = AS_NO_ACTION;
466 else
467 state = AS_IN_ACTION_AREA;
468 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400469}
470
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600471static void setup_ors_command()
Ethan Yonker03a42f62014-08-08 11:03:51 -0500472{
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600473 ors_read_fd = -1;
Ethan Yonker03a42f62014-08-08 11:03:51 -0500474
475 unlink(ORS_INPUT_FILE);
476 if (mkfifo(ORS_INPUT_FILE, 06660) != 0) {
477 LOGINFO("Unable to mkfifo %s\n", ORS_INPUT_FILE);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600478 return;
Ethan Yonker03a42f62014-08-08 11:03:51 -0500479 }
480 unlink(ORS_OUTPUT_FILE);
481 if (mkfifo(ORS_OUTPUT_FILE, 06666) != 0) {
482 LOGINFO("Unable to mkfifo %s\n", ORS_OUTPUT_FILE);
483 unlink(ORS_INPUT_FILE);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600484 return;
Ethan Yonker03a42f62014-08-08 11:03:51 -0500485 }
486
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600487 ors_read_fd = open(ORS_INPUT_FILE, O_RDONLY | O_NONBLOCK);
488 if (ors_read_fd < 0) {
Ethan Yonker03a42f62014-08-08 11:03:51 -0500489 LOGINFO("Unable to open %s\n", ORS_INPUT_FILE);
490 unlink(ORS_INPUT_FILE);
491 unlink(ORS_OUTPUT_FILE);
Ethan Yonker03a42f62014-08-08 11:03:51 -0500492 }
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600493}
Ethan Yonker03a42f62014-08-08 11:03:51 -0500494
that10ae24f2015-12-26 20:53:51 +0100495// callback called after a CLI command was executed
496static void ors_command_done()
497{
498 gui_set_FILE(NULL);
499 fclose(orsout);
500 orsout = NULL;
501
502 if (DataManager::GetIntValue("tw_page_done") == 0) {
503 // The select function will return ready to read and the
504 // read function will return errno 19 no such device unless
505 // we set everything up all over again.
506 close(ors_read_fd);
507 setup_ors_command();
508 }
509}
510
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600511static void ors_command_read()
512{
that10ae24f2015-12-26 20:53:51 +0100513 char command[1024];
514 int read_ret = read(ors_read_fd, &command, sizeof(command));
Ethan Yonker03a42f62014-08-08 11:03:51 -0500515
that10ae24f2015-12-26 20:53:51 +0100516 if (read_ret > 0) {
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600517 command[1022] = '\n';
518 command[1023] = '\0';
519 LOGINFO("Command '%s' received\n", command);
520 orsout = fopen(ORS_OUTPUT_FILE, "w");
521 if (!orsout) {
522 close(ors_read_fd);
523 ors_read_fd = -1;
524 LOGINFO("Unable to fopen %s\n", ORS_OUTPUT_FILE);
525 unlink(ORS_INPUT_FILE);
526 unlink(ORS_OUTPUT_FILE);
527 return;
528 }
529 if (DataManager::GetIntValue("tw_busy") != 0) {
that10ae24f2015-12-26 20:53:51 +0100530 fputs("Failed, operation in progress\n", orsout);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600531 LOGINFO("Command cannot be performed, operation in progress.\n");
that10ae24f2015-12-26 20:53:51 +0100532 fclose(orsout);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600533 } else {
Ethan Yonker74db1572015-10-28 12:44:49 -0500534 if (strlen(command) == 11 && strncmp(command, "dumpstrings", 11) == 0) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500535 gui_set_FILE(orsout);
536 PageManager::GetResources()->DumpStrings();
that10ae24f2015-12-26 20:53:51 +0100537 ors_command_done();
538 } else {
539 // mirror output messages
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600540 gui_set_FILE(orsout);
that10ae24f2015-12-26 20:53:51 +0100541 // close orsout and restart listener after command is done
542 OpenRecoveryScript::Call_After_CLI_Command(ors_command_done);
543 // run the command in a threaded action...
544 DataManager::SetValue("tw_action", "twcmd");
545 DataManager::SetValue("tw_action_param", command);
546 // ...and switch back to the current page when finished
547 std::string currentPage = PageManager::GetCurrentPage();
548 DataManager::SetValue("tw_has_action2", "1");
549 DataManager::SetValue("tw_action2", "page");
550 DataManager::SetValue("tw_action2_param", currentPage);
551 DataManager::SetValue("tw_action_text1", gui_lookup("running_recovery_commands", "Running Recovery Commands"));
552 DataManager::SetValue("tw_action_text2", "");
553 gui_changePage("singleaction_page");
554 // now immediately return to the GUI main loop (the action runs in the background thread)
555 // 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 -0500556 }
Ethan Yonker03a42f62014-08-08 11:03:51 -0500557 }
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600558 } else {
559 LOGINFO("ORS command line read returned an error: %i, %i, %s\n", read_ret, errno, strerror(errno));
Ethan Yonker03a42f62014-08-08 11:03:51 -0500560 }
Ethan Yonker03a42f62014-08-08 11:03:51 -0500561}
562
that10ae24f2015-12-26 20:53:51 +0100563// Get and dispatch input events until it's time to draw the next frame
Dees_Troy51a0e822012-09-05 15:24:24 -0400564// This special function will return immediately the first time, but then
565// always returns 1/30th of a second (or immediately if called later) from
566// the last time it was called
thatde72b6d2015-02-08 08:55:00 +0100567static void loopTimer(int input_timeout_ms)
Dees_Troy51a0e822012-09-05 15:24:24 -0400568{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200569 static timespec lastCall;
570 static int initialized = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400571
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200572 if (!initialized)
Dees_Troyc8b199c2012-09-24 11:55:07 -0400573 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200574 clock_gettime(CLOCK_MONOTONIC, &lastCall);
575 initialized = 1;
576 return;
Dees_Troyc8b199c2012-09-24 11:55:07 -0400577 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400578
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200579 do
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500580 {
thatde72b6d2015-02-08 08:55:00 +0100581 bool got_event = input_handler.processInput(input_timeout_ms); // get inputs but don't send drag notices
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200582 timespec curTime;
583 clock_gettime(CLOCK_MONOTONIC, &curTime);
Dees_Troy51a0e822012-09-05 15:24:24 -0400584
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200585 timespec diff = TWFunc::timespec_diff(lastCall, curTime);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500586
thatc5837f32015-02-01 01:59:43 +0100587 // This is really 2 or 30 times per second
588 // As long as we get events, increase the timeout so we can catch up with input
589 long timeout = got_event ? 500000000 : 33333333;
590
591 if (diff.tv_sec || diff.tv_nsec > timeout)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500592 {
thatc5837f32015-02-01 01:59:43 +0100593 // int32_t input_time = TWFunc::timespec_diff_ms(lastCall, curTime);
594 // LOGINFO("loopTimer(): %u ms, count: %u\n", input_time, count);
595
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200596 lastCall = curTime;
that9fa51532015-01-29 02:04:47 +0100597 input_handler.handleDrag(); // send only drag notices if needed
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200598 return;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500599 }
600
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200601 // We need to sleep some period time microseconds
Ethan Yonkere13fa632015-01-27 11:30:03 -0600602 //unsigned int sleepTime = 33333 -(diff.tv_nsec / 1000);
603 //usleep(sleepTime); // removed so we can scan for input
thatde72b6d2015-02-08 08:55:00 +0100604 input_timeout_ms = 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200605 } while (1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400606}
607
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600608static int runPages(const char *page_name, const int stop_on_page_done)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500609{
Ethan Yonker3f15be42015-02-09 09:39:47 -0600610 DataManager::SetValue("tw_page_done", 0);
611 DataManager::SetValue("tw_gui_done", 0);
612
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600613 if (page_name)
614 gui_changePage(page_name);
615
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200616 // Raise the curtain
617 if (gCurtain != NULL)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500618 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200619 gr_surface surface;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500620
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200621 PageManager::Render();
622 gr_get_surface(&surface);
623 curtainRaise(surface);
624 gr_free_surface(surface);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500625 }
626
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200627 gGuiRunning = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500628
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200629 DataManager::SetValue("tw_loaded", 1);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500630
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600631#ifndef TW_OEM_BUILD
632 struct timeval timeout;
633 fd_set fdset;
634 int has_data = 0;
635#endif
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100636
thatde72b6d2015-02-08 08:55:00 +0100637 int input_timeout_ms = 0;
638 int idle_frames = 0;
639
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200640 for (;;)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500641 {
thatde72b6d2015-02-08 08:55:00 +0100642 loopTimer(input_timeout_ms);
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600643#ifndef TW_OEM_BUILD
that10ae24f2015-12-26 20:53:51 +0100644 if (ors_read_fd > 0 && !orsout) { // orsout is non-NULL if a command is still running
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600645 FD_ZERO(&fdset);
646 FD_SET(ors_read_fd, &fdset);
647 timeout.tv_sec = 0;
648 timeout.tv_usec = 1;
649 has_data = select(ors_read_fd+1, &fdset, NULL, NULL, &timeout);
650 if (has_data > 0) {
651 ors_command_read();
652 }
653 }
654#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500655
Ethan Yonker04536952015-01-27 08:41:28 -0600656 if (!gForceRender.get_value())
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500657 {
thatde72b6d2015-02-08 08:55:00 +0100658 int ret = PageManager::Update();
659 if (ret == 0)
660 ++idle_frames;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500661 else if (ret == -2)
662 break; // Theme reload failure
thatde72b6d2015-02-08 08:55:00 +0100663 else
664 idle_frames = 0;
665 // due to possible animation objects, we need to delay activating the input timeout
666 input_timeout_ms = idle_frames > 15 ? 1000 : 0;
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100667
668#ifndef PRINT_RENDER_TIME
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200669 if (ret > 1)
670 PageManager::Render();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500671
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200672 if (ret > 0)
673 flip();
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100674#else
675 if (ret > 1)
676 {
that9fa51532015-01-29 02:04:47 +0100677 timespec start, end;
678 int32_t render_t, flip_t;
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100679 clock_gettime(CLOCK_MONOTONIC, &start);
680 PageManager::Render();
681 clock_gettime(CLOCK_MONOTONIC, &end);
682 render_t = TWFunc::timespec_diff_ms(start, end);
683
684 flip();
685 clock_gettime(CLOCK_MONOTONIC, &start);
686 flip_t = TWFunc::timespec_diff_ms(end, start);
687
688 LOGINFO("Render(): %u ms, flip(): %u ms, total: %u ms\n", render_t, flip_t, render_t+flip_t);
689 }
thatde72b6d2015-02-08 08:55:00 +0100690 else if (ret > 0)
Vojtech Boceke5ffcd12014-02-06 21:17:32 +0100691 flip();
692#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500693 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200694 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500695 {
Ethan Yonker04536952015-01-27 08:41:28 -0600696 gForceRender.set_value(0);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200697 PageManager::Render();
698 flip();
thatde72b6d2015-02-08 08:55:00 +0100699 input_timeout_ms = 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500700 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200701
thatfb759d42015-01-11 12:16:53 +0100702 blankTimer.checkForTimeout();
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600703 if (stop_on_page_done && DataManager::GetIntValue("tw_page_done") != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200704 {
705 gui_changePage("main");
Dees_Troy6ef66352013-02-21 08:26:57 -0600706 break;
707 }
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600708 if (DataManager::GetIntValue("tw_gui_done") != 0)
709 break;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500710 }
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600711 if (ors_read_fd > 0)
712 close(ors_read_fd);
713 ors_read_fd = -1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200714 gGuiRunning = 0;
715 return 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500716}
717
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200718int gui_forceRender(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500719{
Ethan Yonker04536952015-01-27 08:41:28 -0600720 gForceRender.set_value(1);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200721 return 0;
722}
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500723
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200724int gui_changePage(std::string newPage)
725{
726 LOGINFO("Set page: '%s'\n", newPage.c_str());
727 PageManager::ChangePage(newPage);
Ethan Yonker04536952015-01-27 08:41:28 -0600728 gForceRender.set_value(1);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200729 return 0;
730}
731
732int gui_changeOverlay(std::string overlay)
733{
Ethan Yonker1c273312015-03-16 12:18:56 -0500734 LOGINFO("Set overlay: '%s'\n", overlay.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200735 PageManager::ChangeOverlay(overlay);
Ethan Yonker04536952015-01-27 08:41:28 -0600736 gForceRender.set_value(1);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200737 return 0;
738}
739
thatb2e8f672015-03-05 20:25:39 +0100740std::string gui_parse_text(std::string str)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200741{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200742 // This function parses text for DataManager values encompassed by %value% in the XML
thatb2e8f672015-03-05 20:25:39 +0100743 // and string resources (%@resource_name%)
Ethan Yonker74db1572015-10-28 12:44:49 -0500744 size_t pos = 0, next, end;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200745
746 while (1)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500747 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500748 next = str.find("{@", pos);
749 if (next == std::string::npos)
750 break;
751
752 end = str.find('}', next + 1);
753 if (end == std::string::npos)
754 break;
755
756 std::string var = str.substr(next + 2, (end - next) - 2);
757 str.erase(next, (end - next) + 1);
758
759 size_t default_loc = var.find('=', 0);
760 std::string lookup;
761 if (default_loc == std::string::npos) {
762 str.insert(next, PageManager::GetResources()->FindString(var));
763 } else {
764 lookup = var.substr(0, default_loc);
765 std::string default_string = var.substr(default_loc + 1, var.size() - default_loc - 1);
766 str.insert(next, PageManager::GetResources()->FindString(lookup, default_string));
767 }
768 }
769 pos = 0;
770 while (1)
771 {
772 next = str.find('%', pos);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200773 if (next == std::string::npos)
774 return str;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500775
Ethan Yonker74db1572015-10-28 12:44:49 -0500776 end = str.find('%', next + 1);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200777 if (end == std::string::npos)
778 return str;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500779
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200780 // We have a block of data
thatb2e8f672015-03-05 20:25:39 +0100781 std::string var = str.substr(next + 1, (end - next) - 1);
782 str.erase(next, (end - next) + 1);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500783
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200784 if (next + 1 == end)
785 str.insert(next, 1, '%');
786 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500787 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200788 std::string value;
thatb2e8f672015-03-05 20:25:39 +0100789 if (var.size() > 0 && var[0] == '@') {
790 // this is a string resource ("%@string_name%")
791 value = PageManager::GetResources()->FindString(var.substr(1));
792 str.insert(next, value);
793 }
794 else if (DataManager::GetValue(var, value) == 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200795 str.insert(next, value);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500796 }
797
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200798 pos = next + 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500799 }
800}
801
Ethan Yonker74db1572015-10-28 12:44:49 -0500802std::string gui_lookup(const std::string& resource_name, const std::string& default_value) {
803 return PageManager::GetResources()->FindString(resource_name, default_value);
804}
805
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200806extern "C" int gui_init(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500807{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200808 gr_init();
Dees Troy3454ade2015-01-20 19:21:04 +0000809 std::string curtain_path = TWRES "images/curtain.jpg";
Ethan Yonker63e414f2015-02-06 15:44:39 -0600810 gr_surface source_Surface = NULL;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500811
Ethan Yonker63e414f2015-02-06 15:44:39 -0600812 if (res_create_surface(curtain_path.c_str(), &source_Surface))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500813 {
Ethan Yonker591b9202015-03-11 11:17:15 -0500814 printf("Unable to locate '%s'\nDid you set a TW_THEME in your config files?\n", curtain_path.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200815 return -1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500816 }
Ethan Yonkerd0514ba2015-10-22 14:17:47 -0500817 if (gr_get_width(source_Surface) != (unsigned)gr_fb_width() || gr_get_height(source_Surface) != (unsigned)gr_fb_height()) {
Ethan Yonker63e414f2015-02-06 15:44:39 -0600818 // We need to scale the curtain to fit the screen
819 float scale_w = (float)gr_fb_width() / (float)gr_get_width(source_Surface);
820 float scale_h = (float)gr_fb_height() / (float)gr_get_height(source_Surface);
821 if (res_scale_surface(source_Surface, &gCurtain, scale_w, scale_h)) {
822 LOGINFO("Failed to scale curtain\n");
823 gCurtain = source_Surface;
824 } else {
825 LOGINFO("Scaling the curtain width %fx and height %fx\n", scale_w, scale_h);
826 }
827 } else {
828 gCurtain = source_Surface;
829 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500830
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200831 curtainSet();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500832
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200833 ev_init();
834 return 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500835}
836
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200837extern "C" int gui_loadResources(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400838{
Ethan Yonker83e82572014-04-04 10:59:28 -0500839#ifndef TW_OEM_BUILD
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200840 int check = 0;
841 DataManager::GetValue(TW_IS_ENCRYPTED, check);
Dees Troy3454ade2015-01-20 19:21:04 +0000842
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200843 if (check)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500844 {
Dees Troy3454ade2015-01-20 19:21:04 +0000845 if (PageManager::LoadPackage("TWRP", TWRES "ui.xml", "decrypt"))
Dees_Troy5bf43922012-09-07 16:07:55 -0400846 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500847 gui_err("base_pkg_err=Failed to load base packages.");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200848 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400849 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200850 else
851 check = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500852 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400853
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200854 if (check == 0 && PageManager::LoadPackage("TWRP", "/script/ui.xml", "main"))
855 {
856 std::string theme_path;
857
858 theme_path = DataManager::GetSettingsStoragePath();
859 if (!PartitionManager.Mount_Settings_Storage(false))
Dees_Troy51a0e822012-09-05 15:24:24 -0400860 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200861 int retry_count = 5;
862 while (retry_count > 0 && !PartitionManager.Mount_Settings_Storage(false))
Dees_Troy51a0e822012-09-05 15:24:24 -0400863 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200864 usleep(500000);
865 retry_count--;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500866 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200867
Ethan Yonker74db1572015-10-28 12:44:49 -0500868 if (!PartitionManager.Mount_Settings_Storage(true))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500869 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500870 LOGINFO("Unable to mount %s during GUI startup.\n", theme_path.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200871 check = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500872 }
873 }
874
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200875 theme_path += "/TWRP/theme/ui.zip";
876 if (check || PageManager::LoadPackage("TWRP", theme_path, "main"))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500877 {
Ethan Yonker83e82572014-04-04 10:59:28 -0500878#endif // ifndef TW_OEM_BUILD
Dees Troy3454ade2015-01-20 19:21:04 +0000879 if (PageManager::LoadPackage("TWRP", TWRES "ui.xml", "main"))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500880 {
Ethan Yonker74db1572015-10-28 12:44:49 -0500881 gui_err("base_pkg_err=Failed to load base packages.");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200882 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400883 }
Ethan Yonker83e82572014-04-04 10:59:28 -0500884#ifndef TW_OEM_BUILD
Dees_Troy51a0e822012-09-05 15:24:24 -0400885 }
886 }
Ethan Yonker83e82572014-04-04 10:59:28 -0500887#endif // ifndef TW_OEM_BUILD
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200888 // Set the default package
889 PageManager::SelectPackage("TWRP");
Dees_Troy51a0e822012-09-05 15:24:24 -0400890
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200891 gGuiInitialized = 1;
892 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400893
894error:
Ethan Yonker83e82572014-04-04 10:59:28 -0500895 LOGERR("An internal error has occurred: unable to load theme.\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200896 gGuiInitialized = 0;
897 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400898}
899
Ethan Yonkercf50da52015-01-12 21:59:07 -0600900extern "C" int gui_loadCustomResources(void)
901{
902#ifndef TW_OEM_BUILD
903 if (!PartitionManager.Mount_Settings_Storage(false)) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500904 LOGINFO("Unable to mount settings storage during GUI startup.\n");
Ethan Yonkercf50da52015-01-12 21:59:07 -0600905 return -1;
906 }
907
908 std::string theme_path = DataManager::GetSettingsStoragePath();
909 theme_path += "/TWRP/theme/ui.zip";
910 // Check for a custom theme
911 if (TWFunc::Path_Exists(theme_path)) {
912 // There is a custom theme, try to load it
913 if (PageManager::ReloadPackage("TWRP", theme_path)) {
914 // Custom theme failed to load, try to load stock theme
Dees Troy3454ade2015-01-20 19:21:04 +0000915 if (PageManager::ReloadPackage("TWRP", TWRES "ui.xml")) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500916 gui_err("base_pkg_err=Failed to load base packages.");
Ethan Yonkercf50da52015-01-12 21:59:07 -0600917 goto error;
918 }
919 }
920 }
921 // Set the default package
922 PageManager::SelectPackage("TWRP");
923#endif
924 return 0;
925
926error:
927 LOGERR("An internal error has occurred: unable to load theme.\n");
928 gGuiInitialized = 0;
929 return -1;
930}
931
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200932extern "C" int gui_start(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400933{
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600934 return gui_startPage(NULL, 1, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400935}
936
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600937extern "C" int gui_startPage(const char *page_name, const int allow_commands, int stop_on_page_done)
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000938{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200939 if (!gGuiInitialized)
940 return -1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000941
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200942 // Set the default package
943 PageManager::SelectPackage("TWRP");
944
that9fa51532015-01-29 02:04:47 +0100945 input_handler.init();
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600946#ifndef TW_OEM_BUILD
947 if (allow_commands)
948 {
949 if (ors_read_fd < 0)
950 setup_ors_command();
951 } else {
952 if (ors_read_fd >= 0) {
953 close(ors_read_fd);
954 ors_read_fd = -1;
955 }
956 }
957#endif
Ethan Yonkerfd0439e2015-01-14 11:08:13 -0600958 return runPages(page_name, stop_on_page_done);
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000959}
960
Ethan Yonker63e414f2015-02-06 15:44:39 -0600961
962extern "C" void set_scale_values(float w, float h)
963{
964 scale_theme_w = w;
965 scale_theme_h = h;
966}
967
968extern "C" int scale_theme_x(int initial_x)
969{
970 if (scale_theme_w != 1) {
thatba75a0e2015-02-14 21:20:10 +0100971 int scaled = (float)initial_x * scale_theme_w;
972 if (scaled == 0 && initial_x > 0)
973 return 1;
974 return scaled;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600975 }
976 return initial_x;
977}
978
979extern "C" int scale_theme_y(int initial_y)
980{
981 if (scale_theme_h != 1) {
thatba75a0e2015-02-14 21:20:10 +0100982 int scaled = (float)initial_y * scale_theme_h;
983 if (scaled == 0 && initial_y > 0)
984 return 1;
985 return scaled;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600986 }
987 return initial_y;
988}
989
990extern "C" int scale_theme_min(int initial_value)
991{
992 if (scale_theme_w != 1 || scale_theme_h != 1) {
993 if (scale_theme_w < scale_theme_h)
994 return scale_theme_x(initial_value);
995 else
996 return scale_theme_y(initial_value);
997 }
998 return initial_value;
999}
1000
1001extern "C" float get_scale_w()
1002{
1003 return scale_theme_w;
1004}
1005
1006extern "C" float get_scale_h()
1007{
1008 return scale_theme_h;
1009}