blob: 6ee29d57b5e63b1be76a0d4cc4a724b45b26a750 [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_Troy51a0e822012-09-05 15:24:24 -040040#include "../minzip/Zip.h"
41#include <pixelflinger/pixelflinger.h>
42}
43
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"
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070050#ifndef TW_NO_SCREEN_TIMEOUT
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050051#include "blanktimer.hpp"
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070052#endif
Dees_Troy51a0e822012-09-05 15:24:24 -040053
Dees_Troy51a0e822012-09-05 15:24:24 -040054const static int CURTAIN_FADE = 32;
55
56using namespace rapidxml;
57
58// Global values
59static gr_surface gCurtain = NULL;
60static int gGuiInitialized = 0;
61static int gGuiConsoleRunning = 0;
62static int gGuiConsoleTerminate = 0;
63static int gForceRender = 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050064pthread_mutex_t gForceRendermutex;
Dees_Troyc8b199c2012-09-24 11:55:07 -040065static int gNoAnimation = 1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +000066static int gGuiInputRunning = 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070067#ifndef TW_NO_SCREEN_TIMEOUT
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050068blanktimer blankTimer;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070069#endif
Dees_Troy51a0e822012-09-05 15:24:24 -040070
71// Needed by pages.cpp too
72int gGuiRunning = 0;
73
74static int gRecorder = -1;
75
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020076extern "C" void gr_write_frame_to_file(int fd);
Dees_Troy51a0e822012-09-05 15:24:24 -040077
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020078void flip(void)
Dees_Troy51a0e822012-09-05 15:24:24 -040079{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020080 if (gRecorder != -1)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050081 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020082 timespec time;
83 clock_gettime(CLOCK_MONOTONIC, &time);
84 write(gRecorder, &time, sizeof(timespec));
85 gr_write_frame_to_file(gRecorder);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -050086 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020087 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -040088}
89
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020090void rapidxml::parse_error_handler(const char *what, void *where)
Dees_Troy51a0e822012-09-05 15:24:24 -040091{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020092 fprintf(stderr, "Parser error: %s\n", what);
93 fprintf(stderr, " Start of string: %s\n",(char *) where);
94 LOGERR("Error parsing XML file.\n");
95 //abort();
Dees_Troy51a0e822012-09-05 15:24:24 -040096}
97
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020098static void curtainSet()
Dees_Troy51a0e822012-09-05 15:24:24 -040099{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200100 gr_color(0, 0, 0, 255);
101 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
102 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
103 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400104}
105
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200106static void curtainRaise(gr_surface surface)
Dees_Troy51a0e822012-09-05 15:24:24 -0400107{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200108 int sy = 0;
109 int h = gr_get_height(gCurtain) - 1;
110 int w = gr_get_width(gCurtain);
111 int fy = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400112
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200113 int msw = gr_get_width(surface);
114 int msh = gr_get_height(surface);
115 int CURTAIN_RATE = msh / 30;
Dees_Troy51a0e822012-09-05 15:24:24 -0400116
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200117 if (gNoAnimation == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500118 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200119 for (; h > 0; h -= CURTAIN_RATE, sy += CURTAIN_RATE, fy += CURTAIN_RATE)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500120 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200121 gr_blit(surface, 0, 0, msw, msh, 0, 0);
122 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
123 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500124 }
125 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200126 gr_blit(surface, 0, 0, msw, msh, 0, 0);
127 flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400128}
129
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200130void curtainClose()
Dees_Troy51a0e822012-09-05 15:24:24 -0400131{
132#if 0
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200133 int w = gr_get_width(gCurtain);
134 int h = 1;
135 int sy = gr_get_height(gCurtain) - 1;
136 int fbh = gr_fb_height();
137 int CURTAIN_RATE = fbh / 30;
Dees_Troy51a0e822012-09-05 15:24:24 -0400138
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200139 if (gNoAnimation == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500140 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200141 for (; h < fbh; h += CURTAIN_RATE, sy -= CURTAIN_RATE)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500142 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200143 gr_blit(gCurtain, 0, sy, w, h, 0, 0);
144 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500145 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200146 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain),
147 gr_get_height(gCurtain), 0, 0);
148 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400149
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200150 if (gRecorder != -1)
151 close(gRecorder);
Dees_Troy51a0e822012-09-05 15:24:24 -0400152
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200153 int fade;
154 for (fade = 16; fade < 255; fade += CURTAIN_FADE)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500155 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200156 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain),
157 gr_get_height(gCurtain), 0, 0);
158 gr_color(0, 0, 0, fade);
159 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
160 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500161 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200162 gr_color(0, 0, 0, 255);
163 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
164 gr_flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400165 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500166#else
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200167 gr_blit(gCurtain, 0, 0, gr_get_width(gCurtain), gr_get_height(gCurtain), 0, 0);
168 gr_flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500169#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400170}
171
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200172static void * input_thread(void *cookie)
Dees_Troy51a0e822012-09-05 15:24:24 -0400173{
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700174
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200175 int drag = 0;
176 static int touch_and_hold = 0, dontwait = 0;
177 static int touch_repeat = 0, key_repeat = 0;
178 static int x = 0, y = 0;
179 static int lshift = 0, rshift = 0;
180 static struct timeval touchStart;
181 HardwareKeyboard kb;
182 string seconds;
Dees_Troy51a0e822012-09-05 15:24:24 -0400183
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700184#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200185 //start screen timeout threads
186 blankTimer.setTimerThread();
187 DataManager::GetValue("tw_screen_timeout_secs", seconds);
188 blankTimer.setTime(atoi(seconds.c_str()));
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700189#else
190 LOGINFO("Skipping screen timeout threads: TW_NO_SCREEN_TIMEOUT is set\n");
191#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400192
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200193 for (;;)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500194 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200195 // wait for the next event
196 struct input_event ev;
197 int state = 0, ret = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400198
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200199 ret = ev_get(&ev, dontwait);
Dees_Troy51a0e822012-09-05 15:24:24 -0400200
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200201 if (ret < 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500202 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200203 struct timeval curTime;
204 gettimeofday(&curTime, NULL);
205 long mtime, seconds, useconds;
Dees_Troy51a0e822012-09-05 15:24:24 -0400206
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200207 seconds = curTime.tv_sec - touchStart.tv_sec;
208 useconds = curTime.tv_usec - touchStart.tv_usec;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500209
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200210 mtime = ((seconds) * 1000 + useconds / 1000.0) + 0.5;
211 if (touch_and_hold && mtime > 500)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500212 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200213 touch_and_hold = 0;
214 touch_repeat = 1;
215 gettimeofday(&touchStart, NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400216#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200217 LOGERR("TOUCH_HOLD: %d,%d\n", x, y);
Dees_Troy51a0e822012-09-05 15:24:24 -0400218#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200219 PageManager::NotifyTouch(TOUCH_HOLD, x, y);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700220#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200221 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700222#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400223 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200224 else if (touch_repeat && mtime > 100)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500225 {
226#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200227 LOGERR("TOUCH_REPEAT: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500228#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200229 gettimeofday(&touchStart, NULL);
230 PageManager::NotifyTouch(TOUCH_REPEAT, x, y);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700231#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200232 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700233#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500234 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200235 else if (key_repeat == 1 && mtime > 500)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500236 {
237#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200238 LOGERR("KEY_HOLD: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500239#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200240 gettimeofday(&touchStart, NULL);
241 key_repeat = 2;
242 kb.KeyRepeat();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700243#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200244 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700245#endif
246
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500247 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200248 else if (key_repeat == 2 && mtime > 100)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500249 {
250#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200251 LOGERR("KEY_REPEAT: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500252#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200253 gettimeofday(&touchStart, NULL);
254 kb.KeyRepeat();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700255#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200256 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700257#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500258 }
259 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200260 else if (ev.type == EV_ABS)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500261 {
Dees_Troy51a0e822012-09-05 15:24:24 -0400262
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200263 x = ev.value >> 16;
264 y = ev.value & 0xFFFF;
Dees_Troy51a0e822012-09-05 15:24:24 -0400265
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200266 if (ev.code == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500267 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200268 if (state == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500269 {
Dees_Troy51a0e822012-09-05 15:24:24 -0400270#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200271 LOGERR("TOUCH_RELEASE: %d,%d\n", x, y);
Dees_Troy51a0e822012-09-05 15:24:24 -0400272#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200273 PageManager::NotifyTouch(TOUCH_RELEASE, x, y);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700274#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200275 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700276#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200277 touch_and_hold = 0;
278 touch_repeat = 0;
279 if (!key_repeat)
280 dontwait = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400281 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200282 state = 0;
283 drag = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400284 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200285 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500286 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200287 if (!drag)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500288 {
289#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200290 LOGERR("TOUCH_START: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500291#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200292 if (PageManager::NotifyTouch(TOUCH_START, x, y) > 0)
293 state = 1;
294 drag = 1;
295 touch_and_hold = 1;
296 dontwait = 1;
297 key_repeat = 0;
298 gettimeofday(&touchStart, NULL);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700299#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200300 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700301#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500302 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200303 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500304 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200305 if (state == 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500306 {
307#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200308 LOGERR("TOUCH_DRAG: %d,%d\n", x, y);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500309#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200310 if (PageManager::NotifyTouch(TOUCH_DRAG, x, y) > 0)
311 state = 1;
312 key_repeat = 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700313#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200314 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700315#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500316 }
317 }
318 }
319 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200320 else if (ev.type == EV_KEY)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500321 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200322 // Handle key-press here
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500323#ifdef _EVENT_LOGGING
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200324 LOGERR("TOUCH_KEY: %d\n", ev.code);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500325#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200326 if (ev.value != 0)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500327 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200328 // This is a key press
329 if (kb.KeyDown(ev.code))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500330 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200331 key_repeat = 1;
332 touch_and_hold = 0;
333 touch_repeat = 0;
334 dontwait = 1;
335 gettimeofday(&touchStart, NULL);
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700336#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200337 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700338#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500339 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200340 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500341 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200342 key_repeat = 0;
343 touch_and_hold = 0;
344 touch_repeat = 0;
345 dontwait = 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700346#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200347 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700348#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500349 }
350 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200351 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500352 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200353 // This is a key release
354 kb.KeyUp(ev.code);
355 key_repeat = 0;
356 touch_and_hold = 0;
357 touch_repeat = 0;
358 dontwait = 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700359#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200360 blankTimer.resetTimerAndUnblank();
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700361#endif
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500362 }
363 }
364 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200365 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400366}
367
368// This special function will return immediately the first time, but then
369// always returns 1/30th of a second (or immediately if called later) from
370// the last time it was called
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200371static void loopTimer(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400372{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200373 static timespec lastCall;
374 static int initialized = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400375
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200376 if (!initialized)
Dees_Troyc8b199c2012-09-24 11:55:07 -0400377 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200378 clock_gettime(CLOCK_MONOTONIC, &lastCall);
379 initialized = 1;
380 return;
Dees_Troyc8b199c2012-09-24 11:55:07 -0400381 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400382
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200383 do
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500384 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200385 timespec curTime;
386 clock_gettime(CLOCK_MONOTONIC, &curTime);
Dees_Troy51a0e822012-09-05 15:24:24 -0400387
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200388 timespec diff = TWFunc::timespec_diff(lastCall, curTime);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500389
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200390 // This is really 30 times per second
391 if (diff.tv_sec || diff.tv_nsec > 33333333)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500392 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200393 lastCall = curTime;
394 return;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500395 }
396
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200397 // We need to sleep some period time microseconds
398 unsigned int sleepTime = 33333 -(diff.tv_nsec / 1000);
399 usleep(sleepTime);
400 } while (1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400401}
402
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200403static int runPages(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500404{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200405 // Raise the curtain
406 if (gCurtain != NULL)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500407 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200408 gr_surface surface;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500409
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200410 PageManager::Render();
411 gr_get_surface(&surface);
412 curtainRaise(surface);
413 gr_free_surface(surface);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500414 }
415
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200416 gGuiRunning = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500417
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200418 DataManager::SetValue("tw_loaded", 1);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500419
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200420 for (;;)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500421 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200422 loopTimer();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500423
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200424 if (!gForceRender)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500425 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200426 int ret;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500427
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200428 ret = PageManager::Update();
429 if (ret > 1)
430 PageManager::Render();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500431
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200432 if (ret > 0)
433 flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500434 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200435 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500436 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200437 pthread_mutex_lock(&gForceRendermutex);
438 gForceRender = 0;
439 pthread_mutex_unlock(&gForceRendermutex);
440 PageManager::Render();
441 flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500442 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200443
Dees_Troy6ef66352013-02-21 08:26:57 -0600444 if (DataManager::GetIntValue("tw_gui_done") != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200445 break;
446 }
447
448 gGuiRunning = 0;
449 return 0;
450}
451
452static int runPage(const char *page_name)
453{
454 gui_changePage(page_name);
455
456 // Raise the curtain
457 if (gCurtain != NULL)
458 {
459 gr_surface surface;
460
461 PageManager::Render();
462 gr_get_surface(&surface);
463 curtainRaise(surface);
464 gr_free_surface(surface);
465 }
466
467 gGuiRunning = 1;
468
469 DataManager::SetValue("tw_loaded", 1);
470
471 for (;;)
472 {
473 loopTimer();
474
475 if (!gForceRender)
Dees_Troy6ef66352013-02-21 08:26:57 -0600476 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200477 int ret;
478
479 ret = PageManager::Update();
480 if (ret > 1)
481 PageManager::Render();
482
483 if (ret > 0)
484 flip();
485 }
486 else
487 {
488 pthread_mutex_lock(&gForceRendermutex);
489 gForceRender = 0;
490 pthread_mutex_unlock(&gForceRendermutex);
491 PageManager::Render();
492 flip();
493 }
494 if (DataManager::GetIntValue("tw_page_done") != 0)
495 {
496 gui_changePage("main");
Dees_Troy6ef66352013-02-21 08:26:57 -0600497 break;
498 }
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500499 }
500
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200501 gGuiRunning = 0;
502 return 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500503}
504
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200505int gui_forceRender(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500506{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200507 pthread_mutex_lock(&gForceRendermutex);
508 gForceRender = 1;
509 pthread_mutex_unlock(&gForceRendermutex);
510 return 0;
511}
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500512
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200513int gui_changePage(std::string newPage)
514{
515 LOGINFO("Set page: '%s'\n", newPage.c_str());
516 PageManager::ChangePage(newPage);
517 pthread_mutex_lock(&gForceRendermutex);
518 gForceRender = 1;
519 pthread_mutex_unlock(&gForceRendermutex);
520 return 0;
521}
522
523int gui_changeOverlay(std::string overlay)
524{
525 PageManager::ChangeOverlay(overlay);
526 pthread_mutex_lock(&gForceRendermutex);
527 gForceRender = 1;
528 pthread_mutex_unlock(&gForceRendermutex);
529 return 0;
530}
531
532int gui_changePackage(std::string newPackage)
533{
534 PageManager::SelectPackage(newPackage);
535 pthread_mutex_lock(&gForceRendermutex);
536 gForceRender = 1;
537 pthread_mutex_unlock(&gForceRendermutex);
538 return 0;
539}
540
541std::string gui_parse_text(string inText)
542{
543 // Copied from std::string GUIText::parseText(void)
544 // This function parses text for DataManager values encompassed by %value% in the XML
545 static int counter = 0;
546 std::string str = inText;
547 size_t pos = 0;
548 size_t next = 0, end = 0;
549
550 while (1)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500551 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200552 next = str.find('%', pos);
553 if (next == std::string::npos)
554 return str;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500555
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200556 end = str.find('%', next + 1);
557 if (end == std::string::npos)
558 return str;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500559
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200560 // We have a block of data
561 std::string var = str.substr(next + 1,(end - next) - 1);
562 str.erase(next,(end - next) + 1);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500563
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200564 if (next + 1 == end)
565 str.insert(next, 1, '%');
566 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500567 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200568 std::string value;
569 if (DataManager::GetValue(var, value) == 0)
570 str.insert(next, value);
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500571 }
572
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200573 pos = next + 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500574 }
575}
576
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200577extern "C" int gui_init(void)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500578{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200579 int fd;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500580
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200581 gr_init();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500582
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200583 if (res_create_surface("/res/images/curtain.jpg", &gCurtain))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500584 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200585 printf
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500586 ("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 +0200587 return -1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500588 }
589
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200590 curtainSet();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500591
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200592 ev_init();
593 return 0;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500594}
595
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200596extern "C" int gui_loadResources(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400597{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200598 // unlink("/sdcard/video.last");
599 // rename("/sdcard/video.bin", "/sdcard/video.last");
600 // gRecorder = open("/sdcard/video.bin", O_CREAT | O_WRONLY);
Dees_Troy51a0e822012-09-05 15:24:24 -0400601
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200602 int check = 0;
603 DataManager::GetValue(TW_IS_ENCRYPTED, check);
604 if (check)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500605 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200606 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "decrypt"))
Dees_Troy5bf43922012-09-07 16:07:55 -0400607 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200608 LOGERR("Failed to load base packages.\n");
609 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400610 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200611 else
612 check = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500613 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400614
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200615 if (check == 0 && PageManager::LoadPackage("TWRP", "/script/ui.xml", "main"))
616 {
617 std::string theme_path;
618
619 theme_path = DataManager::GetSettingsStoragePath();
620 if (!PartitionManager.Mount_Settings_Storage(false))
Dees_Troy51a0e822012-09-05 15:24:24 -0400621 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200622 int retry_count = 5;
623 while (retry_count > 0 && !PartitionManager.Mount_Settings_Storage(false))
Dees_Troy51a0e822012-09-05 15:24:24 -0400624 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200625 usleep(500000);
626 retry_count--;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500627 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200628
629 if (!PartitionManager.Mount_Settings_Storage(false))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500630 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200631 LOGERR("Unable to mount %s during GUI startup.\n",
632 theme_path.c_str());
633 check = 1;
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500634 }
635 }
636
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200637 theme_path += "/TWRP/theme/ui.zip";
638 if (check || PageManager::LoadPackage("TWRP", theme_path, "main"))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500639 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200640 if (PageManager::LoadPackage("TWRP", "/res/ui.xml", "main"))
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500641 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200642 LOGERR("Failed to load base packages.\n");
643 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400644 }
645 }
646 }
647
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200648 // Set the default package
649 PageManager::SelectPackage("TWRP");
Dees_Troy51a0e822012-09-05 15:24:24 -0400650
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200651 gGuiInitialized = 1;
652 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400653
654error:
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200655 LOGERR("An internal error has occurred.\n");
656 gGuiInitialized = 0;
657 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400658}
659
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200660extern "C" int gui_start(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400661{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200662 if (!gGuiInitialized)
663 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400664
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200665 gGuiConsoleTerminate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400666
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200667 while (gGuiConsoleRunning)
668 loopTimer();
Dees_Troy51a0e822012-09-05 15:24:24 -0400669
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200670 // Set the default package
671 PageManager::SelectPackage("TWRP");
672
673 if (!gGuiInputRunning)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500674 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200675 // Start by spinning off an input handler.
676 pthread_t t;
677 pthread_create(&t, NULL, input_thread, NULL);
678 gGuiInputRunning = 1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000679 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400680
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200681 return runPages();
Dees_Troy51a0e822012-09-05 15:24:24 -0400682}
683
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200684extern "C" int gui_startPage(const char *page_name)
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000685{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200686 if (!gGuiInitialized)
687 return -1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000688
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200689 gGuiConsoleTerminate = 1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000690
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200691 while (gGuiConsoleRunning)
692 loopTimer();
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000693
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200694 // Set the default package
695 PageManager::SelectPackage("TWRP");
696
697 if (!gGuiInputRunning)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500698 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200699 // Start by spinning off an input handler.
700 pthread_t t;
701 pthread_create(&t, NULL, input_thread, NULL);
702 gGuiInputRunning = 1;
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000703 }
704
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200705 DataManager::SetValue("tw_page_done", 0);
706 return runPage(page_name);
Dees_Troy4bc09ae2013-01-18 17:00:54 +0000707}
708
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200709static void * console_thread(void *cookie)
Dees_Troy51a0e822012-09-05 15:24:24 -0400710{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200711 PageManager::SwitchToConsole();
Dees_Troy51a0e822012-09-05 15:24:24 -0400712
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200713 while (!gGuiConsoleTerminate)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500714 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200715 loopTimer();
Dees_Troy51a0e822012-09-05 15:24:24 -0400716
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200717 if (!gForceRender)
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500718 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200719 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400720
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200721 ret = PageManager::Update();
722 if (ret > 1)
723 PageManager::Render();
Dees_Troy51a0e822012-09-05 15:24:24 -0400724
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200725 if (ret > 0)
726 flip();
Dees_Troy51a0e822012-09-05 15:24:24 -0400727
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200728 if (ret < 0)
729 LOGERR("An update request has failed.\n");
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500730 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200731 else
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500732 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200733 pthread_mutex_lock(&gForceRendermutex);
734 gForceRender = 0;
735 pthread_mutex_unlock(&gForceRendermutex);
736 PageManager::Render();
737 flip();
bigbiff bigbiff8a68c312013-02-10 14:28:30 -0500738 }
739 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200740 gGuiConsoleRunning = 0;
741 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400742}
743
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200744extern "C" int gui_console_only(void)
Dees_Troy51a0e822012-09-05 15:24:24 -0400745{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200746 if (!gGuiInitialized)
747 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400748
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200749 gGuiConsoleTerminate = 0;
750 gGuiConsoleRunning = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400751
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200752 // Start by spinning off an input handler.
753 pthread_t t;
754 pthread_create(&t, NULL, console_thread, NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400755
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200756 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400757}