blob: 8329827e3f07824d88503948ef39b10d7a67f447 [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <linux/input.h>
18#include <pthread.h>
19#include <stdarg.h>
20#include <stdio.h>
21#include <errno.h>
22#include <stdlib.h>
23#include <string.h>
24#include <fcntl.h>
25#include <sys/reboot.h>
26#include <sys/stat.h>
27#include <sys/time.h>
28#include <sys/mman.h>
29#include <sys/types.h>
30#include <sys/ioctl.h>
31#include <sys/mount.h>
32#include <time.h>
33#include <unistd.h>
34#include <stdlib.h>
35
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050036extern "C"
37{
Dees_Troy2673cec2013-04-02 20:22:16 +000038#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040039#include "../minuitwrp/minui.h"
Dees Troyb7ae0982013-09-10 20:47:35 +000040#ifdef HAVE_SELINUX
Dees_Troy51a0e822012-09-05 15:24:24 -040041#include "../minzip/Zip.h"
Dees Troyb7ae0982013-09-10 20:47:35 +000042#else
43#include "../minzipold/Zip.h"
44#endif
Dees_Troy51a0e822012-09-05 15:24:24 -040045#include <pixelflinger/pixelflinger.h>
46}
47
48#include "rapidxml.hpp"
49#include "objects.hpp"
50#include "../data.hpp"
51#include "../variables.h"
Dees_Troy5bf43922012-09-07 16:07:55 -040052#include "../partitions.hpp"
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050053#include "../twrp-functions.hpp"
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070054#ifndef TW_NO_SCREEN_TIMEOUT
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050055#include "blanktimer.hpp"
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070056#endif
Dees_Troy51a0e822012-09-05 15:24:24 -040057
Dees_Troy51a0e822012-09-05 15:24:24 -040058const static int CURTAIN_FADE = 32;
59
60using namespace rapidxml;
61
62// Global values
63static gr_surface gCurtain = NULL;
64static int gGuiInitialized = 0;
65static int gGuiConsoleRunning = 0;
66static int gGuiConsoleTerminate = 0;
67static int gForceRender = 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050068pthread_mutex_t gForceRendermutex;
Dees_Troyc8b199c2012-09-24 11:55:07 -040069static int gNoAnimation = 1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +000070static int gGuiInputRunning = 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070071#ifndef TW_NO_SCREEN_TIMEOUT
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050072blanktimer blankTimer;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070073#endif
Dees_Troy51a0e822012-09-05 15:24:24 -040074
75// Needed by pages.cpp too
76int gGuiRunning = 0;
77
78static int gRecorder = -1;
79
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020080extern "C" void gr_write_frame_to_file(int fd);
Dees_Troy51a0e822012-09-05 15:24:24 -040081
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020082void flip(void)
Dees_Troy51a0e822012-09-05 15:24:24 -040083{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020084 if (gRecorder != -1)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050085 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020086 timespec time;
87 clock_gettime(CLOCK_MONOTONIC, &time);
88 write(gRecorder, &time, sizeof(timespec));
89 gr_write_frame_to_file(gRecorder);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050090 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020091 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -040092}
93
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020094void rapidxml::parse_error_handler(const char *what, void *where)
Dees_Troy51a0e822012-09-05 15:24:24 -040095{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020096 fprintf(stderr, "Parser error: %s\n", what);
97 fprintf(stderr, " Start of string: %s\n",(char *) where);
98 LOGERR("Error parsing XML file.\n");
99 //abort();
Dees_Troy51a0e822012-09-05 15:24:24 -0400100}
101
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200102static void curtainSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400103{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200104 gr_color(0, 0, 0, 255);
105 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
106 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
107 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400108}
109
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200110static void curtainRaise(gr_surface surface)
Dees_Troy51a0e822012-09-05 15:24:24 -0400111{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200112 int sy = 0;
113 int h = gr_get_height(gCurtain) - 1;
114 int w = gr_get_width(gCurtain);
115 int fy = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400116
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200117 int msw = gr_get_width(surface);
118 int msh = gr_get_height(surface);
119 int CURTAIN_RATE = msh / 30;
Dees_Troy51a0e822012-09-05 15:24:24 -0400120
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200121 if (gNoAnimation == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500122 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200123 for (; h > 0; h -= CURTAIN_RATE, sy += CURTAIN_RATE, fy += CURTAIN_RATE)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500124 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200125 gr_blit(surface, 0, 0, msw, msh, 0, 0);
126 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
127 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500128 }
129 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200130 gr_blit(surface, 0, 0, msw, msh, 0, 0);
131 flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400132}
133
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200134void curtainClose()
Dees_Troy51a0e822012-09-05 15:24:24 -0400135{
136#if 0
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200137 int w = gr_get_width(gCurtain);
138 int h = 1;
139 int sy = gr_get_height(gCurtain) - 1;
140 int fbh = gr_fb_height();
141 int CURTAIN_RATE = fbh / 30;
Dees_Troy51a0e822012-09-05 15:24:24 -0400142
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200143 if (gNoAnimation == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500144 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200145 for (; h < fbh; h += CURTAIN_RATE, sy -= CURTAIN_RATE)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500146 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200147 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
148 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500149 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200150 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain),
151 gr_get_height(gCurtain), 0, 0);
152 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400153
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200154 if (gRecorder != -1)
155 close(gRecorder);
Dees_Troy51a0e822012-09-05 15:24:24 -0400156
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200157 int fade;
158 for (fade = 16; fade < 255; fade += CURTAIN_FADE)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500159 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200160 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain),
161 gr_get_height(gCurtain), 0, 0);
162 gr_color(0, 0, 0, fade);
163 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
164 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500165 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200166 gr_color(0, 0, 0, 255);
167 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
168 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400169 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500170#else
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200171 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
172 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500173#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400174}
175
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200176static void * input_thread(void *cookie)
Dees_Troy51a0e822012-09-05 15:24:24 -0400177{
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700178
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200179 int drag = 0;
180 static int touch_and_hold = 0, dontwait = 0;
181 static int touch_repeat = 0, key_repeat = 0;
182 static int x = 0, y = 0;
183 static int lshift = 0, rshift = 0;
184 static struct timeval touchStart;
185 HardwareKeyboard kb;
186 string seconds;
Dees_Troy51a0e822012-09-05 15:24:24 -0400187
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700188#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200189 //start screen timeout threads
190 blankTimer.setTimerThread();
191 DataManager::GetValue("tw_screen_timeout_secs", seconds);
192 blankTimer.setTime(atoi(seconds.c_str()));
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700193#else
194 LOGINFO("Skipping screen timeout threads: TW_NO_SCREEN_TIMEOUT is set\n");
195#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400196
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200197 for (;;)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500198 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200199 // wait for the next event
200 struct input_event ev;
201 int state = 0, ret = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400202
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200203 ret = ev_get(&ev, dontwait);
Dees_Troy51a0e822012-09-05 15:24:24 -0400204
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200205 if (ret < 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500206 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200207 struct timeval curTime;
208 gettimeofday(&curTime, NULL);
209 long mtime, seconds, useconds;
Dees_Troy51a0e822012-09-05 15:24:24 -0400210
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200211 seconds = curTime.tv_sec - touchStart.tv_sec;
212 useconds = curTime.tv_usec - touchStart.tv_usec;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500213
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200214 mtime = ((seconds) * 1000 + useconds / 1000.0) + 0.5;
215 if (touch_and_hold && mtime > 500)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500216 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200217 touch_and_hold = 0;
218 touch_repeat = 1;
219 gettimeofday(&touchStart, NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400220#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200221 LOGERR("TOUCH_HOLD: %d,%d\n", x, y);
Dees_Troy51a0e822012-09-05 15:24:24 -0400222#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200223 PageManager::NotifyTouch(TOUCH_HOLD, x, y);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700224#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200225 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700226#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400227 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200228 else if (touch_repeat && mtime > 100)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500229 {
230#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200231 LOGERR("TOUCH_REPEAT: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500232#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200233 gettimeofday(&touchStart, NULL);
234 PageManager::NotifyTouch(TOUCH_REPEAT, x, y);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700235#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200236 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700237#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500238 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200239 else if (key_repeat == 1 && mtime > 500)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500240 {
241#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200242 LOGERR("KEY_HOLD: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500243#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200244 gettimeofday(&touchStart, NULL);
245 key_repeat = 2;
246 kb.KeyRepeat();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700247#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200248 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700249#endif
250
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500251 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200252 else if (key_repeat == 2 && mtime > 100)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500253 {
254#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200255 LOGERR("KEY_REPEAT: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500256#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200257 gettimeofday(&touchStart, NULL);
258 kb.KeyRepeat();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700259#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200260 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700261#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500262 }
263 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200264 else if (ev.type == EV_ABS)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500265 {
Dees_Troy51a0e822012-09-05 15:24:24 -0400266
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200267 x = ev.value >> 16;
268 y = ev.value & 0xFFFF;
Dees_Troy51a0e822012-09-05 15:24:24 -0400269
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200270 if (ev.code == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500271 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200272 if (state == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500273 {
Dees_Troy51a0e822012-09-05 15:24:24 -0400274#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200275 LOGERR("TOUCH_RELEASE: %d,%d\n", x, y);
Dees_Troy51a0e822012-09-05 15:24:24 -0400276#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200277 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700278#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200279 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700280#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200281 touch_and_hold = 0;
282 touch_repeat = 0;
283 if (!key_repeat)
284 dontwait = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400285 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200286 state = 0;
287 drag = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400288 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200289 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500290 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200291 if (!drag)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500292 {
293#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200294 LOGERR("TOUCH_START: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500295#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200296 if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
297 state = 1;
298 drag = 1;
299 touch_and_hold = 1;
300 dontwait = 1;
301 key_repeat = 0;
302 gettimeofday(&touchStart, NULL);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700303#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200304 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700305#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500306 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200307 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500308 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200309 if (state == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500310 {
311#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200312 LOGERR("TOUCH_DRAG: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500313#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200314 if (PageManager::NotifyTouch(TOUCH_DRAG, x, y) > 0)
315 state = 1;
316 key_repeat = 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700317#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200318 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700319#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500320 }
321 }
322 }
323 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200324 else if (ev.type == EV_KEY)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500325 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200326 // Handle key-press here
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500327#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200328 LOGERR("TOUCH_KEY: %d\n", ev.code);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500329#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200330 if (ev.value != 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500331 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200332 // This is a key press
333 if (kb.KeyDown(ev.code))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500334 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200335 key_repeat = 1;
336 touch_and_hold = 0;
337 touch_repeat = 0;
338 dontwait = 1;
339 gettimeofday(&touchStart, NULL);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700340#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200341 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700342#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500343 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200344 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500345 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200346 key_repeat = 0;
347 touch_and_hold = 0;
348 touch_repeat = 0;
349 dontwait = 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700350#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200351 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700352#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500353 }
354 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200355 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500356 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200357 // This is a key release
358 kb.KeyUp(ev.code);
359 key_repeat = 0;
360 touch_and_hold = 0;
361 touch_repeat = 0;
362 dontwait = 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700363#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200364 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700365#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500366 }
367 }
368 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200369 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400370}
371
372// This special function will return immediately the first time, but then
373// always returns 1/30th of a second (or immediately if called later) from
374// the last time it was called
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200375static void loopTimer(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400376{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200377 static timespec lastCall;
378 static int initialized = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400379
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200380 if (!initialized)
Dees_Troyc8b199c2012-09-24 11:55:07 -0400381 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200382 clock_gettime(CLOCK_MONOTONIC, &lastCall);
383 initialized = 1;
384 return;
Dees_Troyc8b199c2012-09-24 11:55:07 -0400385 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400386
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200387 do
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500388 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200389 timespec curTime;
390 clock_gettime(CLOCK_MONOTONIC, &curTime);
Dees_Troy51a0e822012-09-05 15:24:24 -0400391
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200392 timespec diff = TWFunc::timespec_diff(lastCall, curTime);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500393
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200394 // This is really 30 times per second
395 if (diff.tv_sec || diff.tv_nsec > 33333333)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500396 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200397 lastCall = curTime;
398 return;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500399 }
400
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200401 // We need to sleep some period time microseconds
402 unsigned int sleepTime = 33333 -(diff.tv_nsec / 1000);
403 usleep(sleepTime);
404 } while (1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400405}
406
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200407static int runPages(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500408{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200409 // Raise the curtain
410 if (gCurtain != NULL)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500411 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200412 gr_surface surface;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500413
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200414 PageManager::Render();
415 gr_get_surface(&surface);
416 curtainRaise(surface);
417 gr_free_surface(surface);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500418 }
419
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200420 gGuiRunning = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500421
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200422 DataManager::SetValue("tw_loaded", 1);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500423
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200424 for (;;)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500425 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200426 loopTimer();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500427
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200428 if (!gForceRender)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500429 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200430 int ret;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500431
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200432 ret = PageManager::Update();
433 if (ret > 1)
434 PageManager::Render();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500435
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200436 if (ret > 0)
437 flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500438 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200439 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500440 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200441 pthread_mutex_lock(&gForceRendermutex);
442 gForceRender = 0;
443 pthread_mutex_unlock(&gForceRendermutex);
444 PageManager::Render();
445 flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500446 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200447
Dees_Troy6ef66352013-02-21 08:26:57 -0600448 if (DataManager::GetIntValue("tw_gui_done") != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200449 break;
450 }
451
452 gGuiRunning = 0;
453 return 0;
454}
455
456static int runPage(const char *page_name)
457{
458 gui_changePage(page_name);
459
460 // Raise the curtain
461 if (gCurtain != NULL)
462 {
463 gr_surface surface;
464
465 PageManager::Render();
466 gr_get_surface(&surface);
467 curtainRaise(surface);
468 gr_free_surface(surface);
469 }
470
471 gGuiRunning = 1;
472
473 DataManager::SetValue("tw_loaded", 1);
474
475 for (;;)
476 {
477 loopTimer();
478
479 if (!gForceRender)
Dees_Troy6ef66352013-02-21 08:26:57 -0600480 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200481 int ret;
482
483 ret = PageManager::Update();
484 if (ret > 1)
485 PageManager::Render();
486
487 if (ret > 0)
488 flip();
489 }
490 else
491 {
492 pthread_mutex_lock(&gForceRendermutex);
493 gForceRender = 0;
494 pthread_mutex_unlock(&gForceRendermutex);
495 PageManager::Render();
496 flip();
497 }
498 if (DataManager::GetIntValue("tw_page_done") != 0)
499 {
500 gui_changePage("main");
Dees_Troy6ef66352013-02-21 08:26:57 -0600501 break;
502 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500503 }
504
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200505 gGuiRunning = 0;
506 return 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500507}
508
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200509int gui_forceRender(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500510{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200511 pthread_mutex_lock(&gForceRendermutex);
512 gForceRender = 1;
513 pthread_mutex_unlock(&gForceRendermutex);
514 return 0;
515}
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500516
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200517int gui_changePage(std::string newPage)
518{
519 LOGINFO("Set page: '%s'\n", newPage.c_str());
520 PageManager::ChangePage(newPage);
521 pthread_mutex_lock(&gForceRendermutex);
522 gForceRender = 1;
523 pthread_mutex_unlock(&gForceRendermutex);
524 return 0;
525}
526
527int gui_changeOverlay(std::string overlay)
528{
529 PageManager::ChangeOverlay(overlay);
530 pthread_mutex_lock(&gForceRendermutex);
531 gForceRender = 1;
532 pthread_mutex_unlock(&gForceRendermutex);
533 return 0;
534}
535
536int gui_changePackage(std::string newPackage)
537{
538 PageManager::SelectPackage(newPackage);
539 pthread_mutex_lock(&gForceRendermutex);
540 gForceRender = 1;
541 pthread_mutex_unlock(&gForceRendermutex);
542 return 0;
543}
544
545std::string gui_parse_text(string inText)
546{
547 // Copied from std::string GUIText::parseText(void)
548 // This function parses text for DataManager values encompassed by %value% in the XML
549 static int counter = 0;
550 std::string str = inText;
551 size_t pos = 0;
552 size_t next = 0, end = 0;
553
554 while (1)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500555 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200556 next = str.find('%', pos);
557 if (next == std::string::npos)
558 return str;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500559
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200560 end = str.find('%', next + 1);
561 if (end == std::string::npos)
562 return str;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500563
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200564 // We have a block of data
565 std::string var = str.substr(next + 1,(end - next) - 1);
566 str.erase(next,(end - next) + 1);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500567
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200568 if (next + 1 == end)
569 str.insert(next, 1, '%');
570 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500571 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200572 std::string value;
573 if (DataManager::GetValue(var, value) == 0)
574 str.insert(next, value);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500575 }
576
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200577 pos = next + 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500578 }
579}
580
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200581extern "C" int gui_init(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500582{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200583 int fd;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500584
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200585 gr_init();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500586
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200587 if (res_create_surface("/res/images/curtain.jpg", &gCurtain))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500588 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200589 printf
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500590 ("Unable to locate '/res/images/curtain.jpg'\nDid you set a DEVICE_RESOLUTION in your config files?\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200591 return -1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500592 }
593
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200594 curtainSet();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500595
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200596 ev_init();
597 return 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500598}
599
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200600extern "C" int gui_loadResources(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400601{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200602 // unlink("/sdcard/video.last");
603 // rename("/sdcard/video.bin", "/sdcard/video.last");
604 // gRecorder = open("/sdcard/video.bin", O_CREAT | O_WRONLY);
Dees_Troy51a0e822012-09-05 15:24:24 -0400605
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200606 int check = 0;
607 DataManager::GetValue(TW_IS_ENCRYPTED, check);
608 if (check)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500609 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200610 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "decrypt"))
Dees_Troy5bf43922012-09-07 16:07:55 -0400611 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200612 LOGERR("Failed to load base packages.\n");
613 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400614 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200615 else
616 check = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500617 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400618
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200619 if (check == 0 && PageManager::LoadPackage("TWRP", "/script/ui.xml", "main"))
620 {
621 std::string theme_path;
622
623 theme_path = DataManager::GetSettingsStoragePath();
624 if (!PartitionManager.Mount_Settings_Storage(false))
Dees_Troy51a0e822012-09-05 15:24:24 -0400625 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200626 int retry_count = 5;
627 while (retry_count > 0 && !PartitionManager.Mount_Settings_Storage(false))
Dees_Troy51a0e822012-09-05 15:24:24 -0400628 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200629 usleep(500000);
630 retry_count--;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500631 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200632
633 if (!PartitionManager.Mount_Settings_Storage(false))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500634 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200635 LOGERR("Unable to mount %s during GUI startup.\n",
636 theme_path.c_str());
637 check = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500638 }
639 }
640
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200641 theme_path += "/TWRP/theme/ui.zip";
642 if (check || PageManager::LoadPackage("TWRP", theme_path, "main"))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500643 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200644 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "main"))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500645 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200646 LOGERR("Failed to load base packages.\n");
647 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400648 }
649 }
650 }
651
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200652 // Set the default package
653 PageManager::SelectPackage("TWRP");
Dees_Troy51a0e822012-09-05 15:24:24 -0400654
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200655 gGuiInitialized = 1;
656 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400657
658error:
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200659 LOGERR("An internal error has occurred.\n");
660 gGuiInitialized = 0;
661 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400662}
663
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200664extern "C" int gui_start(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400665{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200666 if (!gGuiInitialized)
667 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400668
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200669 gGuiConsoleTerminate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400670
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200671 while (gGuiConsoleRunning)
672 loopTimer();
Dees_Troy51a0e822012-09-05 15:24:24 -0400673
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200674 // Set the default package
675 PageManager::SelectPackage("TWRP");
676
677 if (!gGuiInputRunning)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500678 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200679 // Start by spinning off an input handler.
680 pthread_t t;
681 pthread_create(&t, NULL, input_thread, NULL);
682 gGuiInputRunning = 1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000683 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400684
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200685 return runPages();
Dees_Troy51a0e822012-09-05 15:24:24 -0400686}
687
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200688extern "C" int gui_startPage(const char *page_name)
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000689{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200690 if (!gGuiInitialized)
691 return -1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000692
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200693 gGuiConsoleTerminate = 1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000694
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200695 while (gGuiConsoleRunning)
696 loopTimer();
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000697
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200698 // Set the default package
699 PageManager::SelectPackage("TWRP");
700
701 if (!gGuiInputRunning)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500702 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200703 // Start by spinning off an input handler.
704 pthread_t t;
705 pthread_create(&t, NULL, input_thread, NULL);
706 gGuiInputRunning = 1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000707 }
708
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200709 DataManager::SetValue("tw_page_done", 0);
710 return runPage(page_name);
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000711}
712
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200713static void * console_thread(void *cookie)
Dees_Troy51a0e822012-09-05 15:24:24 -0400714{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200715 PageManager::SwitchToConsole();
Dees_Troy51a0e822012-09-05 15:24:24 -0400716
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200717 while (!gGuiConsoleTerminate)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500718 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200719 loopTimer();
Dees_Troy51a0e822012-09-05 15:24:24 -0400720
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200721 if (!gForceRender)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500722 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200723 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400724
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200725 ret = PageManager::Update();
726 if (ret > 1)
727 PageManager::Render();
Dees_Troy51a0e822012-09-05 15:24:24 -0400728
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200729 if (ret > 0)
730 flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400731
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200732 if (ret < 0)
733 LOGERR("An update request has failed.\n");
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500734 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200735 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500736 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200737 pthread_mutex_lock(&gForceRendermutex);
738 gForceRender = 0;
739 pthread_mutex_unlock(&gForceRendermutex);
740 PageManager::Render();
741 flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500742 }
743 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200744 gGuiConsoleRunning = 0;
745 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400746}
747
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200748extern "C" int gui_console_only(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400749{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200750 if (!gGuiInitialized)
751 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400752
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200753 gGuiConsoleTerminate = 0;
754 gGuiConsoleRunning = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400755
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200756 // Start by spinning off an input handler.
757 pthread_t t;
758 pthread_create(&t, NULL, console_thread, NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400759
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200760 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400761}