bugfix
[picodrive.git] / platform / uiq2 / main.cpp
1 // mainloop with window server event handling\r
2 // event polling mechnism was taken from\r
3 // Peter van Sebille's projects\r
4 \r
5 // (c) Copyright 2006, notaz\r
6 // All Rights Reserved\r
7 \r
8 #include <hal.h>\r
9 \r
10 #include <stdio.h>\r
11 #include <stdlib.h>\r
12 #include <sys/time.h>\r
13 \r
14 #include "debug.h"\r
15 \r
16 #include "pico/picoInt.h"\r
17 #include "vid.h"\r
18 #include "SimpleServer.h"\r
19 #include "ClientServer.h"\r
20 //#include "polledAS.h"\r
21 #include "audio.h"\r
22 \r
23 #include <EZlib.h>\r
24 #include "zlib/gzio_symb.h"\r
25 \r
26 \r
27 #define BENCHMARK\r
28 //#define TEST_FRAMEBUFF\r
29 \r
30 // keycodes we care about\r
31 enum TPxxxKeyCodes {\r
32     EKeyPxxxPower    = EKeyDevice0,              //0xF842\r
33     EKeyPxxxBrowser  = EKeyApplication0,\r
34     EKeyPxxxCamera   = EKeyApplication1,\r
35     EKeyPxxxJogUp    = EKeyDevice1,\r
36     EKeyPxxxJogDown  = EKeyDevice2,\r
37     EKeyPxxxJogLeft  = EKeyDevice3,\r
38     EKeyPxxxJogRight = EKeyDevice9,\r
39     EKeyPxxxJogInward= EKeyDevice8,\r
40         // FC keys\r
41     //EKeyPxxxFcOk     = EKeyDevice8, // don't care about FC keycodes\r
42 };\r
43 // EKeyScreenDimension1 ~ EStdKeyF24 is sent when flip is closed,\r
44 // EKeyScreenDimension0 ~ EStdKeyF23 when opened\r
45 \r
46 enum TMotAKeyCodes {\r
47     EKeyMotAUp       = EKeyDevice4,              //0xF846\r
48     EKeyMotADown     = EKeyDevice5,\r
49     EKeyMotALeft     = EKeyDevice6,\r
50     EKeyMotARight    = EKeyDevice7,\r
51     EKeyMotASelect   = EKeyDevice8,\r
52     EKeyMotAButton1  = EKeyApplicationA,\r
53     EKeyMotAButton2  = EKeyApplicationB,\r
54     EKeyMotAHome     = EKeyApplication0,\r
55     EKeyMotAShortcut = EKeyApplication1,\r
56     EKeyMotAVoice    = EKeyDeviceA,\r
57     EKeyMotACamera   = EKeyDeviceB,\r
58     EKeyMotAVolUp    = EKeyIncVolume,\r
59     EKeyMotAVolDn    = EKeyDecVolume,\r
60     EKeyMotASend     = EKeyYes,\r
61     EKeyMotAEnd      = EKeyNo,\r
62 };\r
63 \r
64 // scancodes we care about\r
65 enum TPxxxScanCodes {\r
66     EScanPxxxPower    = EStdKeyDevice0,          // 0xa4\r
67     EScanPxxxBrowser  = EStdKeyApplication0,\r
68     EScanPxxxCamera   = EStdKeyApplication1,\r
69     EScanPxxxJogUp    = EStdKeyDevice1,\r
70     EScanPxxxJogDown  = EStdKeyDevice2,\r
71     EScanPxxxJogLeft  = EStdKeyDeviceE, // not consistent\r
72     EScanPxxxJogRight = EStdKeyDeviceD,\r
73     EScanPxxxJogInward= EStdKeyDevice8,\r
74         // FC keys\r
75         EScanPxxxFcOk      = EStdKeyDeviceF,\r
76         EScanPxxxFcBack    = EStdKeyDevice3,\r
77         EScanPxxxFcC       = EStdKeyDeviceA,\r
78         EScanPxxxFcMenu    = EStdKeyDevice9,\r
79         EScanPxxxFc0       = '0',\r
80         EScanPxxxFc1       = '1',\r
81         EScanPxxxFc2       = '2',\r
82         EScanPxxxFc3       = '3',\r
83         EScanPxxxFc4       = '4',\r
84         EScanPxxxFc5       = '5',\r
85         EScanPxxxFc6       = '6',\r
86         EScanPxxxFc7       = '7',\r
87         EScanPxxxFc8       = '8',\r
88         EScanPxxxFc9       = '9',\r
89         EScanPxxxFcHash    = EStdKeyHash,\r
90         EScanPxxxFcAsterisk= EStdKeyNkpAsterisk,\r
91 };\r
92 \r
93 enum TMotAScanCodes {\r
94     EScanMotAUp       = EStdKeyDevice4,\r
95     EScanMotADown     = EStdKeyDevice5,\r
96     EScanMotALeft     = EStdKeyDevice6,\r
97     EScanMotARight    = EStdKeyDevice7,\r
98     EScanMotASelect   = EStdKeyDevice8,\r
99     EScanMotAButton1  = EStdKeyApplicationA,\r
100     EScanMotAButton2  = EStdKeyApplicationB,\r
101     EScanMotAHome     = EStdKeyApplication0,\r
102     EScanMotAShortcut = EStdKeyApplication1,\r
103     EScanMotAVoice    = EStdKeyDeviceA,\r
104     EScanMotACamera   = EStdKeyDeviceB,\r
105     EScanMotAVolUp    = EStdKeyIncVolume,\r
106     EScanMotAVolDn    = EStdKeyDecVolume,\r
107     EScanMotASend     = EStdKeyYes,\r
108     EScanMotAEnd      = EStdKeyNo,\r
109         // some extra codes, don't know if these are actually used\r
110         EScanMotAExtra    = EStdKeyApplicationC,\r
111         EScanMotAEsc      = EStdKeyApplicationD,\r
112         EScanMotAStart    = EStdKeyApplicationE,\r
113         EScanMotASelect2  = EStdKeyApplicationF,\r
114 };\r
115 \r
116 \r
117 // list of key names and codes\r
118 TPicoKeyConfigEntry keyConfigPXXX[] = {\r
119         { EKeyPxxxPower,     EScanPxxxPower,     0, -1, -1, "POWER" },     // 0\r
120         { EKeyPxxxBrowser,   EScanPxxxBrowser,   0, -1, -1, "BROWSER" },\r
121         { EKeyPxxxCamera,    EScanPxxxCamera,    0, -1, -1, "CAMERA" },\r
122         { EKeyPxxxJogUp,     EScanPxxxJogUp,     2, -1, -1, "JOG@UP" },\r
123         { EKeyPxxxJogDown,   EScanPxxxJogDown,   2, -1, -1, "JOG@DOWN" },\r
124         { EKeyPxxxJogLeft,       EScanPxxxJogLeft,   0, -1, -1, "JOG@LEFT" },  // 5\r
125         { EKeyPxxxJogRight,  EScanPxxxJogRight,  0, -1, -1, "JOG@RIGHT" },\r
126         { 0,                 EScanPxxxJogInward, 0, -1, -1, "JOG@INWARD" },\r
127         { 0,                 EScanPxxxFcOk,      0, -1, -1, "FC@OK" },\r
128         { 0,                 EScanPxxxFcBack,    0, -1, -1, "FC@BACK" },\r
129         { 0,                 EScanPxxxFcC,       0, -1, -1, "FC@C" },      // 10\r
130         { 0,                 EScanPxxxFcMenu,    0, -1, -1, "FC@MENU" },\r
131         { 0,                 EScanPxxxFc0,       0, -1, -1, "FC@0" },\r
132         { 0,                 EScanPxxxFc1,       0, -1, -1, "FC@1" },\r
133         { 0,                 EScanPxxxFc2,       0, -1, -1, "FC@2" },\r
134         { 0,                 EScanPxxxFc3,       0, -1, -1, "FC@3" },\r
135         { 0,                 EScanPxxxFc4,       0, -1, -1, "FC@4" },\r
136         { 0,                 EScanPxxxFc5,       0, -1, -1, "FC@5" },\r
137         { 0,                 EScanPxxxFc6,       0, -1, -1, "FC@6" },\r
138         { 0,                 EScanPxxxFc7,       0, -1, -1, "FC@7" },\r
139         { 0,                 EScanPxxxFc8,       0, -1, -1, "FC@8" },\r
140         { 0,                 EScanPxxxFc9,       0, -1, -1, "FC@9" },\r
141         { 0,                 EScanPxxxFcHash,    0, -1, -1, "FC@HASH" },\r
142         { 0,                 EScanPxxxFcAsterisk,0, -1, -1, "FC@AST" },\r
143         { 0,                 0,                  0,  0,  0, 0 }\r
144 };\r
145 \r
146 // Motorola A92x & A1000 support\r
147 TPicoKeyConfigEntry keyConfigMotA[] = {\r
148         { EKeyMotAUp,        EScanMotAUp,        0, -1, -1, "UP" },      // 0\r
149         { EKeyMotADown,      EScanMotADown,      0, -1, -1, "DOWN" },\r
150         { EKeyMotALeft,      EScanMotALeft,      0, -1, -1, "LEFT" },\r
151         { EKeyMotARight,     EScanMotARight,     0, -1, -1, "RIGHT" },\r
152         { EKeyMotASelect,    EScanMotASelect,    0, -1, -1, "SELECT" },\r
153         { EKeyMotAButton1,   EScanMotAButton1,   0, -1, -1, "BUTTON1" }, // 5\r
154         { EKeyMotAButton2,   EScanMotAButton2,   0, -1, -1, "BUTTON2" },\r
155         { EKeyMotAHome,      EScanMotAHome,      0, -1, -1, "HOME" },\r
156         { EKeyMotAShortcut,  EScanMotAShortcut,  0, -1, -1, "SHORTCUT" },\r
157         { EKeyMotAVoice,     EScanMotAVoice,     0, -1, -1, "VOICE" },\r
158         { EKeyMotACamera,    EScanMotACamera,    0, -1, -1, "CAMERA" },  // 10\r
159         { EKeyMotAVolUp,     EScanMotAVolUp,     0, -1, -1, "VOL@UP" },\r
160         { EKeyMotAVolDn,     EScanMotAVolDn,     0, -1, -1, "VOL@DOWN" },\r
161         { EKeyMotASend,      EScanMotASend,      0, -1, -1, "SEND" },\r
162         { EKeyMotAEnd,       EScanMotAEnd,       0, -1, -1, "END" },\r
163         { 0,                 EScanMotAExtra,     0, -1, -1, "EXTRA" },\r
164         { 0,                 EScanMotAEsc,       0, -1, -1, "ESC" },\r
165         { 0,                 EScanMotAStart,     0, -1, -1, "START" },\r
166         { 0,                 EScanMotASelect2,   0, -1, -1, "SELECT" },\r
167         { 0,                 0,                  0,  0,  0, 0 }\r
168 };\r
169 \r
170 \r
171 // list of areas\r
172 TPicoAreaConfigEntry areaConfig[] = {\r
173         { TRect(  0,   0,   0,   0) },\r
174         // small corner bottons\r
175         { TRect(  0,   0,  15,  15) },\r
176         { TRect(192,   0, 207,  15) },\r
177         { TRect(  0, 304,  15, 319) },\r
178         { TRect(192, 304, 207, 319) },\r
179         // normal buttons\r
180         { TRect(  0,   0,  68,  63) },\r
181         { TRect( 69,   0, 138,  63) },\r
182         { TRect(139,   0, 207,  63) },\r
183         { TRect(  0,  64,  68, 127) },\r
184         { TRect( 69,  64, 138, 127) },\r
185         { TRect(139,  64, 207, 127) },\r
186         { TRect(  0, 128,  68, 191) },\r
187         { TRect( 69, 128, 138, 191) },\r
188         { TRect(139, 128, 207, 191) },\r
189         { TRect(  0, 192,  68, 255) },\r
190         { TRect( 69, 192, 138, 255) },\r
191         { TRect(139, 192, 207, 255) },\r
192         { TRect(  0, 256,  68, 319) },\r
193         { TRect( 69, 256, 138, 319) },\r
194         { TRect(139, 256, 207, 319) },\r
195         { TRect(  0,   0,   0,   0) }\r
196 };\r
197 \r
198 // PicoPad[] format: SACB RLDU\r
199 const char *actionNames[] = {\r
200         "UP", "DOWN", "LEFT", "RIGHT", "B", "C", "A", "START",\r
201         0, 0, 0, 0, 0, 0, 0, 0, // Z, Y, X, MODE (enabled only when needed), ?, ?, ?, ?\r
202         0, 0, 0, 0, 0, 0, "NEXT@SAVE@SLOT", "PREV@SAVE@SLOT", // ?, ?, ?, ?, mot_vol_up, mot_vol_down, next_slot, prev_slot\r
203         0, 0, "PAUSE@EMU", "SAVE@STATE", "LOAD@STATE", "FRAMESKIP@8", "AUTO@FRAMESKIP", "DONE" // ?, switch_renderer\r
204 };\r
205 \r
206 \r
207 // globals are allowed, so why not to (ab)use them?\r
208 TInt machineUid = 0;\r
209 int gamestate = PGS_Paused, gamestate_prev = PGS_Paused;\r
210 TPicoConfig currentConfig;\r
211 TPicoKeyConfigEntry *keyConfig = 0;                     // currently used keys\r
212 static char noticeMsg[64];                                      // notice msg to draw\r
213 static timeval noticeMsgTime = { 0, 0 };        // when started showing\r
214 static RLibrary gameAudioLib;                           // audio object library\r
215 static _gameAudioNew gameAudioNew;                      // audio object maker\r
216 static IGameAudio *gameAudio = 0;                       // the audio object itself\r
217 static TProcessId launcherProcessId;\r
218 static int reset_timing, state_slot = 0;\r
219 extern const char *RomFileName;\r
220 extern int pico_was_reset;      \r
221 #ifdef TEST_FRAMEBUFF\r
222 static TUint8 *iFrameBuffer = 0;\r
223 #endif\r
224 \r
225 // some forward declarations\r
226 static void MainInit();\r
227 static void MainExit();\r
228 static void CheckForLauncher();\r
229 static void DumpMemInfo();\r
230 \r
231 // just for a nicer grouping of WS related stuff\r
232 class CGameWindow\r
233 {\r
234 public:\r
235         static void ConstructResourcesL();\r
236         static void FreeResources();\r
237         static void DoKeys(timeval &time);\r
238         static void DoKeysConfig(TUint &which);\r
239         static void RunEvents(TUint32 which);\r
240         static void SendClientWsEvent(TInt type);\r
241 \r
242         static RWsSession                               iWsSession;\r
243         static RWindowGroup                             iWsWindowGroup;\r
244         static RWindow                                  iWsWindow;\r
245         static CWsScreenDevice*                 iWsScreen;\r
246         static CWindowGc*                               iWindowGc;\r
247         static TRequestStatus                   iWsEventStatus;\r
248         static TThreadId                                iLauncherThreadId;\r
249         static RDirectScreenAccess*             iDSA;\r
250         static TRequestStatus                   iDSAstatus;\r
251 };\r
252 \r
253 \r
254 void SkipFrame(int do_sound)\r
255 {\r
256   PicoSkipFrame=1;\r
257   PicoFrame();\r
258   PicoSkipFrame=0;\r
259 \r
260   if(do_sound && PsndOut) {\r
261     PsndOut = gameAudio->NextFrameL();\r
262         if(!PsndOut) { // sound output problems?\r
263       strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED");\r
264       gettimeofday(&noticeMsgTime, 0);\r
265         }\r
266   }\r
267 \r
268 /*\r
269   int total=0;\r
270 \r
271   // V-Blanking period:\r
272   if (Pico.video.reg[1]&0x20) SekInterrupt(6); // Set IRQ\r
273   Pico.video.status|=0x88; // V-Int happened / go into vblank\r
274   total+=SekRun(18560);\r
275 \r
276   // Active Scan:\r
277   if (Pico.video.reg[1]&0x40) Pico.video.status&=~8; // Come out of vblank if display is enabled\r
278   SekInterrupt(0); // Clear IRQ\r
279   total+=SekRun(127969-total);\r
280 */\r
281 }\r
282 \r
283 \r
284 void TargetEpocGameL()\r
285 {\r
286         char buff[24]; // fps count c string\r
287         struct timeval tval; // timing\r
288         int thissec = 0, frames_done = 0, frames_shown = 0;\r
289         int target_fps, target_frametime, too_fast, too_fast_time;\r
290         int i, underflow;\r
291         TRawEvent blevent;\r
292 \r
293         MainInit();\r
294         buff[0] = 0;\r
295 \r
296         // just to keep the backlight on..\r
297         blevent.Set(TRawEvent::EActive);\r
298 \r
299         // loop?\r
300         for(;;) {\r
301                 if(gamestate == PGS_Running) {\r
302                         // prepare window and stuff\r
303                         CGameWindow::ConstructResourcesL();\r
304 \r
305                         // if the system has something to do, it should better do it now\r
306                         User::After(50000);\r
307                         //CPolledActiveScheduler::Instance()->Schedule();\r
308 \r
309                         // pal/ntsc might have changed, reset related stuff\r
310                         if(Pico.m.pal) {\r
311                                 target_fps = 50;\r
312                                 if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "PAL@SYSTEM@/@50@FPS");\r
313                         } else {\r
314                                 target_fps = 60;\r
315                                 if(!noticeMsgTime.tv_sec) strcpy(noticeMsg, "NTSC@SYSTEM@/@60@FPS");\r
316                         }\r
317                         target_frametime = 1000000/target_fps;\r
318                         if(!noticeMsgTime.tv_sec && pico_was_reset)\r
319                                 gettimeofday(&noticeMsgTime, 0);\r
320 \r
321                         pico_was_reset = too_fast = 0;\r
322                         reset_timing = 1;\r
323 \r
324                         while(gamestate == PGS_Running) {\r
325                                 gettimeofday(&tval, 0);\r
326                                 if(reset_timing) {\r
327                                         reset_timing = 0;\r
328                                         thissec = tval.tv_sec;\r
329                                         frames_done = tval.tv_usec/target_frametime;\r
330                                 }\r
331 \r
332                                 // show notice message?\r
333                                 char *notice = 0;\r
334                                 if(noticeMsgTime.tv_sec) {\r
335                                         if((tval.tv_sec*1000000+tval.tv_usec) - (noticeMsgTime.tv_sec*1000000+noticeMsgTime.tv_usec) > 2000000) // > 2.0 sec\r
336                                                  noticeMsgTime.tv_sec = noticeMsgTime.tv_usec = 0;\r
337                                         else notice = noticeMsg;\r
338                                 }\r
339 \r
340                                 // second changed?\r
341                                 if(thissec != tval.tv_sec) {\r
342 #ifdef BENCHMARK\r
343                                         static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];\r
344                                         if(++bench == 10) {\r
345                                                 bench = 0;\r
346                                                 bench_fps_s = bench_fps;\r
347                                                 bf[bfp++ & 3] = bench_fps;\r
348                                                 bench_fps = 0;\r
349                                         }\r
350                                         bench_fps += frames_shown;\r
351                                         sprintf(buff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);\r
352 #else\r
353                                         if(currentConfig.iFlags & 2) \r
354                                                 sprintf(buff, "%02i/%02i", frames_shown, frames_done);\r
355 #endif\r
356                                         thissec = tval.tv_sec;\r
357                                         if((thissec & 7) == 7) UserSvr::AddEvent(blevent);\r
358                                         // in is quite common for this implementation to leave 1 fame unfinished\r
359                                         // when second changes. This creates sound clicks, so it's probably better to\r
360                                         // skip that frame and render sound\r
361                                         if(PsndOut && frames_done < target_fps && frames_done > target_fps-5) {\r
362                                                 SkipFrame(1); frames_done++;\r
363                                         }\r
364                                         // try to prevent sound buffer underflows by making sure we did _exactly_\r
365                                         // target_fps sound updates and copying last samples over and over again\r
366                                         if(PsndOut && frames_done < target_fps)\r
367                                                 for(; frames_done < target_fps; frames_done++) {\r
368                                                         PsndOut = gameAudio->DupeFrameL(underflow);\r
369                                                         if(!PsndOut) { // sound output problems?\r
370                                                                 strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED");\r
371                                                                 gettimeofday(&noticeMsgTime, 0);\r
372                                                                 break;\r
373                                                         }\r
374                                                         if(underflow) break;\r
375                                                 }\r
376                                         frames_done = frames_shown = 0;\r
377                                 }\r
378 \r
379                                 if(currentConfig.iFrameskip >= 0) { // frameskip enabled\r
380                                         for(i = 0; i < currentConfig.iFrameskip; i++) {\r
381                                                 SkipFrame(frames_done < target_fps); frames_done++;\r
382                                                 CGameWindow::DoKeys(tval);\r
383                                         }\r
384                                 } else if(tval.tv_usec > (frames_done+1)*target_frametime) { // auto frameskip\r
385                                         // no time left for this frame - skip\r
386                                         SkipFrame(1); frames_done++;\r
387                                         CGameWindow::DoKeys(tval);\r
388                                         too_fast = 0;\r
389                                         continue;\r
390                                 } else if(tval.tv_usec < (too_fast_time=frames_done*target_frametime)) { // we are too fast\r
391                                         if(++too_fast > 2) { User::After(too_fast_time-tval.tv_usec); too_fast = 0; }// sleep, but only if we are _really_ fast\r
392                                 }\r
393 \r
394                                 // draw\r
395                                 vidDrawFrame(notice, buff, frames_shown);\r
396                                 if(PsndOut && frames_done < target_fps) {\r
397                                         PsndOut = gameAudio->NextFrameL();\r
398                                         if(!PsndOut) { // sound output problems?\r
399                                                 strcpy(noticeMsg, "SOUND@OUTPUT@ERROR;@SOUND@DISABLED");\r
400                                                 gettimeofday(&noticeMsgTime, 0);\r
401                                         }\r
402                                 }\r
403                                 frames_done++; frames_shown++;\r
404                                 CGameWindow::DoKeys(tval);\r
405                         }\r
406 \r
407                         // save SRAM\r
408                         if((currentConfig.iFlags & 1) && SRam.changed) {\r
409                                 saveLoadGame(0, 1);\r
410                                 SRam.changed = 0;\r
411                         }\r
412                         CGameWindow::SendClientWsEvent(EEventGamePaused);\r
413                         CGameWindow::FreeResources();\r
414                 } else if(gamestate == PGS_Paused) {\r
415                         for(i = 0; gamestate == PGS_Paused; i++) {\r
416                                 User::After(250000);\r
417                                 if(!(i & 0x7F)) CheckForLauncher(); // every 32 secs\r
418                         }\r
419                 } else if(gamestate == PGS_KeyConfig) {\r
420                         // prepare window and stuff\r
421                         CGameWindow::ConstructResourcesL();\r
422 \r
423                         TUint whichAction = 0;\r
424                         while(gamestate == PGS_KeyConfig) {\r
425                                 vidKeyConfigFrame(whichAction, CGameWindow::iWsScreen->CurrentScreenMode());\r
426                                 CGameWindow::DoKeysConfig(whichAction);\r
427                                 User::After(200000);\r
428                         }\r
429 \r
430                         CGameWindow::SendClientWsEvent(EEventKeyCfgDone);\r
431                         CGameWindow::SendClientWsEvent(EEventGamePaused);\r
432                         CGameWindow::FreeResources();\r
433                 } else if(gamestate == PGS_DebugHeap) {\r
434                         #ifdef __DEBUG_PRINT\r
435                         TInt cells = User::CountAllocCells();\r
436                         TInt mem;\r
437                         User::AllocSize(mem);\r
438                         DEBUGPRINT(_L("worker: cels=%d, size=%d KB"), cells, mem/1024);\r
439                         gamestate = gamestate_prev;\r
440                         #endif\r
441                 } else if(gamestate == PGS_Quit) {\r
442                         break;\r
443                 }\r
444         }\r
445 \r
446         MainExit();\r
447 }\r
448 \r
449 \r
450 // gameAudio default "maker", which simply leaves\r
451 IGameAudio *gameAudioNew_failer(TInt aRate, TBool aStereo, TInt aPcmFrames, TInt aBufferedFrames)\r
452 {\r
453         User::Leave(1);\r
454         return 0; // shouldn't happen\r
455 }\r
456 \r
457 \r
458 // main initialization\r
459 static void MainInit()\r
460 {\r
461         RProcess thisProcess, launcherProcess;\r
462         TInt err = KErrGeneral;\r
463 \r
464         DEBUGPRINT(_L("\r\n\r\nstarting.."));\r
465 \r
466         //CPolledActiveScheduler::NewL(); // create Polled AS for the sound engine\r
467 \r
468         // get launcher id\r
469         if(thisProcess.Owner(launcherProcess) == KErrNone) {\r
470                 launcherProcessId = launcherProcess.Id();\r
471                 launcherProcess.Close(); // messing with launcherProcess too much strangely reboots my phone\r
472         } else {\r
473                 DEBUGPRINT(_L("%i: couldn't find owner, terminating.."), thisProcess.Id());\r
474                 thisProcess.Terminate(1);\r
475         }\r
476 \r
477         // also get launcher thread id (for sending events, nasty way)\r
478         TFindThread findThread;\r
479         TFullName dummy1;\r
480         RThread  tmpThread;\r
481         RProcess tmpProcess;\r
482 \r
483         while(findThread.Next(dummy1) == KErrNone)\r
484         {\r
485                 tmpThread.Open(findThread);\r
486                 tmpThread.Process(tmpProcess);\r
487                 if(tmpProcess.Id() == launcherProcessId) {\r
488                         CGameWindow::iLauncherThreadId = tmpThread.Id();\r
489                         break;\r
490                 }\r
491                 tmpThread.Close();\r
492                 tmpProcess.Close();\r
493         }\r
494 \r
495         // start event listening thread, which waits for GUI commands\r
496         if(StartThread() < 0) {\r
497                 // communication thread failed to start, we serve no purpose now, so suicide\r
498                 DEBUGPRINT(_L("%i: StartThread() failed, terminating.."), thisProcess.Id());\r
499                 thisProcess.Terminate(1);\r
500         }\r
501 \r
502         HAL::Get(HALData::EMachineUid, machineUid); // find out the machine UID\r
503 \r
504         // get current dir\r
505         TFileName pfName = thisProcess.FileName();\r
506         TParse parse;\r
507         parse.Set(pfName, 0, 0);\r
508         TPtrC currDir = parse.DriveAndPath();\r
509         DEBUGPRINT(_L("current dir: %S"), &currDir);\r
510 \r
511         static TPtrC audio_dlls[] = { _L("audio_motorola.dll"), _L("audio_mediaserver.dll") };\r
512 \r
513         // find our audio object maker\r
514         for(TInt i=0; i < 2; i++) {\r
515                 DEBUGPRINT(_L("trying audio DLL: %S"), &audio_dlls[i]);\r
516                 err = gameAudioLib.Load(audio_dlls[i], currDir);\r
517                 if(err == KErrNone) { // great, we loaded a dll!\r
518                         gameAudioNew = (_gameAudioNew) gameAudioLib.Lookup(1);\r
519                         if(!gameAudioNew) {\r
520                                 gameAudioLib.Close();\r
521                                 err = KErrGeneral;\r
522                                 DEBUGPRINT(_L("  loaded, but Lookup(1) failed."));\r
523                         } else\r
524                                 break; // done\r
525                 } else\r
526                         DEBUGPRINT(_L("  load failed! (%i)"), err);;\r
527         }\r
528 \r
529         if(err != KErrNone)\r
530                  gameAudioNew = gameAudioNew_failer;\r
531         else DEBUGPRINT(_L("  audio dll loaded!"));;\r
532 \r
533         DumpMemInfo();\r
534 \r
535         // try to start pico\r
536         DEBUGPRINT(_L("PicoInit();"));\r
537         PicoInit();\r
538 \r
539 #ifdef TEST_FRAMEBUFF\r
540         iFrameBuffer = (TUint8 *) malloc(208*320*4);\r
541 #endif\r
542 }\r
543 \r
544 \r
545 // does not return\r
546 static void MainExit()\r
547 {\r
548         RProcess thisProcess;\r
549 \r
550         DEBUGPRINT(_L("%i: cleaning up.."), thisProcess.Id());\r
551 \r
552         // save SRAM\r
553         if((currentConfig.iFlags & 1) && SRam.changed) {\r
554                 saveLoadGame(0, 1);\r
555                 SRam.changed = 0;\r
556         }\r
557 \r
558         PicoExit();\r
559 \r
560         if(gameAudio) delete gameAudio;\r
561 \r
562         if(gameAudioLib.Handle()) gameAudioLib.Close();\r
563 \r
564         // Polled AS\r
565         //delete CPolledActiveScheduler::Instance();\r
566 \r
567         DEBUGPRINT(_L("%i: terminating.."), thisProcess.Id());  \r
568         thisProcess.Terminate(0);\r
569 }\r
570 \r
571 \r
572 static void CheckForLauncher()\r
573 {\r
574         RProcess launcherProcess;\r
575 \r
576         // check for launcher, we are useless without it\r
577         if(launcherProcess.Open(launcherProcessId) != KErrNone || launcherProcess.ExitCategory().Length() != 0) {\r
578                 #ifdef __DEBUG_PRINT\r
579                 RProcess thisProcess;\r
580                 DEBUGPRINT(_L("%i: launcher process is gone, terminating.."), thisProcess.Id());\r
581                 if(launcherProcess.Handle()) {\r
582                                 TExitCategoryName ecn = launcherProcess.ExitCategory();\r
583                         DEBUGPRINT(_L("%i: launcher exit category: %S"), thisProcess.Id(), &ecn);\r
584                         launcherProcess.Close();\r
585                 }\r
586                 #endif\r
587                 MainExit();\r
588         }\r
589         launcherProcess.Close();\r
590 }\r
591 \r
592 \r
593 void DumpMemInfo()\r
594 {\r
595         TInt    ramSize, ramSizeFree, romSize;\r
596         \r
597         HAL::Get(HALData::EMemoryRAM, ramSize);\r
598         HAL::Get(HALData::EMemoryRAMFree, ramSizeFree);\r
599         HAL::Get(HALData::EMemoryROM, romSize);\r
600 \r
601         DEBUGPRINT(_L("ram=%dKB, ram_free=%dKB, rom=%dKB"), ramSize/1024, ramSizeFree/1024, romSize/1024);\r
602 }\r
603 \r
604 \r
605 \r
606 TInt E32Main()\r
607 {\r
608         // first thing's first\r
609         RThread().SetExceptionHandler(&ExceptionHandler, -1);\r
610 \r
611         //TInt pc, sp;\r
612         //asm volatile ("str pc, %0" : "=m" (pc) );\r
613         //asm volatile ("str sp, %0" : "=m" (sp) );\r
614         //RDebug::Print(_L("executing @ 0x%08x, sp=0x%08x"), pc, sp);\r
615 \r
616 /*\r
617         RDebug::Print(_L("Base     Bottom   Top      Size     RW Name"));\r
618         TBuf<4> l_r(_L("R")), l_w(_L("W")), l_d(_L("-"));\r
619         RChunk chunk;\r
620         TFullName chunkname;\r
621         TFindChunk findChunk(_L("*"));\r
622         while( findChunk.Next(chunkname) != KErrNotFound ) {\r
623                 chunk.Open(findChunk);\r
624                 RDebug::Print(_L("%08x %08x %08x %08x %S%S %S"), chunk.Base(), chunk.Base()+chunk.Bottom(), chunk.Base()+chunk.Top(), chunk.Size(), chunk.IsReadable() ? &l_r : &l_d, chunk.IsWritable() ? &l_w : &l_d, &chunkname);\r
625                 chunk.Close();\r
626         }\r
627 */\r
628 \r
629         CTrapCleanup* cleanup=CTrapCleanup::New();\r
630 \r
631         TRAPD(error, TargetEpocGameL());\r
632 \r
633         __ASSERT_ALWAYS(!error, User::Panic(_L("Picosmall"), error));\r
634         delete cleanup;\r
635 \r
636         return 0;\r
637 }\r
638 \r
639 \r
640 void CGameWindow::ConstructResourcesL()\r
641 {\r
642 \r
643         // connect to window server\r
644         // tried to create it globally and not re-connect everytime,\r
645         // but my window started to lose focus strangely\r
646         User::LeaveIfError(iWsSession.Connect());\r
647 \r
648         //       * Tell the Window Server not to mess about with our process priority\r
649         //       * Also, because of the way legacy games are written, they never sleep\r
650         //       * and thus never voluntarily yield the CPU. We set our process priority\r
651         //       * to EPriorityForeground and hope that a Telephony application on\r
652         //       * this device runs at EPriorityForeground as well. If not, tough! ;-)\r
653 \r
654         CGameWindow::iWsSession.ComputeMode(RWsSession::EPriorityControlDisabled);\r
655         RProcess me;\r
656         me.SetPriority(EPriorityForeground);\r
657 \r
658         iWsScreen=new(ELeave) CWsScreenDevice(iWsSession);\r
659         User::LeaveIfError(iWsScreen->Construct());\r
660 //      User::LeaveIfError(iWsScreen->CreateContext(iWindowGc));\r
661 \r
662         iWsWindowGroup=RWindowGroup(iWsSession);\r
663         User::LeaveIfError(iWsWindowGroup.Construct((TUint32)&iWsWindowGroup));\r
664         //iWsWindowGroup.SetOrdinalPosition(0);\r
665         //iWsWindowGroup.SetName(KServerWGName);\r
666         iWsWindowGroup.EnableScreenChangeEvents(); // flip events (EEventScreenDeviceChanged)\r
667         iWsWindowGroup.EnableFocusChangeEvents(); // EEventFocusGroupChanged\r
668         iWsWindowGroup.SetOrdinalPosition(0, 1); // TInt aPos, TInt aOrdinalPriority\r
669 \r
670         iWsWindow=RWindow(iWsSession);\r
671         User::LeaveIfError(iWsWindow.Construct(iWsWindowGroup, (TUint32)&iWsWindow));\r
672         iWsWindow.SetSize(iWsScreen->SizeInPixels());\r
673         iWsWindow.PointerFilter(EPointerFilterDrag, 0);\r
674         iWsWindow.SetPointerGrab(ETrue);\r
675         iWsWindow.SetVisible(ETrue);\r
676         iWsWindow.Activate();\r
677 \r
678         // request access through RDirectScreenAccess api, but don't care about the result\r
679         RRegion *dsa_region = 0;\r
680         iDSA = new(ELeave) RDirectScreenAccess(iWsSession);\r
681         if(iDSA->Construct() == KErrNone)\r
682                 iDSA->Request(dsa_region, iDSAstatus, iWsWindow);\r
683         DEBUGPRINT(_L("DSA: %i"), dsa_region ? dsa_region->Count() : -1);\r
684 \r
685         // now get the screenbuffer\r
686         TScreenInfoV01                  screenInfo;\r
687         TPckg<TScreenInfoV01>   sI(screenInfo);\r
688         UserSvr::ScreenInfo(sI);\r
689 \r
690         if(!screenInfo.iScreenAddressValid)\r
691                 User::Leave(KErrNotSupported);\r
692 \r
693 #ifndef TEST_FRAMEBUFF\r
694         TUint8 *iFrameBuffer = (TUint8*) screenInfo.iScreenAddress;\r
695 #endif\r
696         TInt p800 = 0;\r
697 \r
698         switch(machineUid)\r
699         {\r
700                 case 0x101f6b26: // A9xx & A10xx\r
701                 case 0x101f6b27: // Chinese A10xx\r
702                 case 0x101fd279: // P3x\r
703                    iFrameBuffer += 32;\r
704                    keyConfig = keyConfigMotA;\r
705                    break;\r
706                 case 0x101f408b: // P800\r
707                    p800 = 1;\r
708                 //case 0x101fb2ae: // P900\r
709                 //case 0x10200ac6: // P910\r
710                 default:        \r
711                    keyConfig = keyConfigPXXX;\r
712                    break;\r
713         }\r
714         DEBUGPRINT(_L("framebuffer=0x%08x (%dx%d)"), iFrameBuffer,\r
715                                         screenInfo.iScreenSize.iWidth, screenInfo.iScreenSize.iHeight);\r
716 \r
717         // vidInit\r
718         User::LeaveIfError(vidInit(iWsScreen->DisplayMode(), iFrameBuffer, p800));\r
719 \r
720         // register for keyevents\r
721         for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++) {\r
722                 // release all keys\r
723                 e->flags &= ~1;\r
724                 if(e->flags & 0x80) {\r
725                         // key disabled\r
726                         e->handle1 = e->handle2 = -1;\r
727                         continue;\r
728                 }\r
729                 e->handle1 = iWsWindowGroup.CaptureKeyUpAndDowns(e->scanCode, 0, 0, 2);\r
730                 // although we only use UpAndDown events, register simple events too,\r
731                 // just to prevent fireing their default actions.\r
732                 if(e->keyCode) e->handle2 = iWsWindowGroup.CaptureKey(e->keyCode, 0, 0, 2); // priority of 1 is not enough on my phone\r
733         }\r
734 \r
735         // try to start the audio engine\r
736         static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;\r
737 \r
738         if(gamestate == PGS_Running && (currentConfig.iFlags & 4)) {\r
739                 TInt err = 0;\r
740                 if(PsndRate != PsndRate_old || (PicoOpt&11) != (PicoOpt_old&11) || Pico.m.pal != pal_old) {\r
741                         // if rate changed, reset all enabled chips, else reset only those chips, which were recently enabled\r
742                         //sound_reset(PsndRate != PsndRate_old ? PicoOpt : (PicoOpt&(PicoOpt^PicoOpt_old)));\r
743                         sound_rerate();\r
744                 }\r
745                 if(!gameAudio || PsndRate != PsndRate_old || ((PicoOpt&8) ^ (PicoOpt_old&8)) || Pico.m.pal != pal_old) { // rate or stereo or pal/ntsc changed\r
746                         if(gameAudio) delete gameAudio; gameAudio = 0;\r
747                         DEBUGPRINT(_L("starting audio: %i len: %i stereo: %i, pal: %i"), PsndRate, PsndLen, PicoOpt&8, Pico.m.pal);\r
748                         TRAP(err, gameAudio = gameAudioNew(PsndRate, (PicoOpt&8) ? 1 : 0, PsndLen, Pico.m.pal ? 10 : 12));\r
749                 }\r
750                 if( gameAudio)\r
751                         TRAP(err, PsndOut = gameAudio->ResumeL());\r
752                 if(err) {\r
753                         if(gameAudio) delete gameAudio;\r
754                         gameAudio = 0;\r
755                         PsndOut = 0;\r
756                         strcpy(noticeMsg, "SOUND@STARTUP@FAILED");\r
757                         gettimeofday(&noticeMsgTime, 0);\r
758                 }\r
759                 PsndRate_old = PsndRate;\r
760                 PicoOpt_old  = PicoOpt;\r
761                 pal_old = Pico.m.pal;\r
762         } else {\r
763                 if(gameAudio) delete gameAudio;\r
764                 gameAudio = 0;\r
765                 PsndOut = 0;\r
766         }\r
767 \r
768         // start key WS event polling\r
769         iWsSession.EventReady(&iWsEventStatus);\r
770         DEBUGPRINT(_L("CGameWindow::ConstructResourcesL() finished."));\r
771 }\r
772 \r
773 \r
774 void CGameWindow::FreeResources()\r
775 {\r
776         if(gameAudio) gameAudio->Pause();\r
777 \r
778         // free RDirectScreenAccess stuff\r
779         iDSA->Cancel();\r
780         iDSA->Close();\r
781         delete iDSA;\r
782         iDSA = NULL;\r
783 \r
784         iWsSession.EventReadyCancel();\r
785 \r
786         for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++) {\r
787                 if(e->handle2 >= 0) iWsWindowGroup.CancelCaptureKey(e->handle2);\r
788                 if(e->handle1 >= 0) iWsWindowGroup.CancelCaptureKeyUpAndDowns(e->handle1);\r
789         }\r
790 \r
791         if(iWsWindow.WsHandle())\r
792                 iWsWindow.Close();\r
793 \r
794         if(iWsWindowGroup.WsHandle())\r
795                 iWsWindowGroup.Close();\r
796 \r
797         // these must be deleted before calling iWsSession.Close()\r
798 //      delete iWindowGc;\r
799 //      iWindowGc = NULL;\r
800 \r
801         delete iWsScreen;\r
802         iWsScreen = NULL;\r
803 \r
804         // emu might change renderer by itself, so we may need to sync config\r
805         if(PicoOpt != currentConfig.iPicoOpt) {\r
806                 currentConfig.iFlags |= 0x80;\r
807                 CGameWindow::SendClientWsEvent(EEventKeyCfgDone);\r
808         }\r
809 \r
810         if(iWsSession.WsHandle())\r
811                 iWsSession.Close();\r
812         \r
813         vidFree();\r
814 \r
815 #ifdef TEST_FRAMEBUFF\r
816         FILE *tmp = fopen("d:\\temp\\screen.raw", "wb");\r
817         fwrite(iFrameBuffer, 1, 208*320*4, tmp);\r
818         fclose(tmp);\r
819 #endif\r
820 }\r
821 \r
822 \r
823 void CGameWindow::DoKeys(timeval &time)\r
824 {\r
825         TWsEvent iWsEvent;\r
826         TInt iWsEventType;\r
827         unsigned long allActions = 0;\r
828         static unsigned long areaActions = 0, forceUpdate = 0;\r
829         int i, nEvents;\r
830 \r
831         // detect if user is holding power button\r
832         static timeval powerPushed = { 0, 0 };\r
833         if(powerPushed.tv_sec) {\r
834                 if((time.tv_sec*1000000+time.tv_usec) - (powerPushed.tv_sec*1000000+powerPushed.tv_usec) > 1000000) { // > 1 sec\r
835                         gamestate = PGS_Paused;\r
836                         powerPushed.tv_sec = powerPushed.tv_usec = 0;\r
837                 }\r
838         }\r
839 \r
840         for(nEvents = 0; iWsEventStatus != KRequestPending; nEvents++)\r
841         {\r
842                 iWsSession.GetEvent(iWsEvent);\r
843                 iWsEventType = iWsEvent.Type();\r
844 \r
845                 // pointer events?\r
846                 if(iWsEventType == EEventPointer) {\r
847                         if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Up) {\r
848                                 areaActions = 0; // remove all directionals\r
849                         } else { // if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) {\r
850                                 TPoint p = iWsEvent.Pointer()->iPosition;\r
851                                 const TPicoAreaConfigEntry *e = areaConfig + 1;\r
852                                 for(i = 0; !e->rect.IsEmpty(); e++, i++)\r
853                                         if(e->rect.Contains(p)) {\r
854                                                 areaActions = currentConfig.iAreaBinds[i];\r
855                                                 break;\r
856                                         }\r
857                         }\r
858                 }\r
859                 else if(iWsEventType == EEventKeyDown || iWsEventType == EEventKeyUp) {\r
860                         TInt iScanCode = iWsEvent.Key()->iScanCode;\r
861 \r
862                         for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++)\r
863                                 if(iScanCode == e->scanCode) {\r
864                                         if(iWsEventType == EEventKeyDown) e->flags |=  1;\r
865                                         else if((e->flags & 2) == 0)      e->flags &= ~1;\r
866                                         break;\r
867                                 }\r
868 \r
869                         // power?\r
870                         if(iScanCode == EScanPxxxPower || iScanCode == EScanMotAEnd) {\r
871                                 if(iWsEventType == EEventKeyDown)\r
872                                          powerPushed = time;\r
873                                 else powerPushed.tv_sec = powerPushed.tv_usec = 0;\r
874                         }\r
875                 }\r
876                 else if(iWsEventType == EEventScreenDeviceChanged) {\r
877                         // we have the priority, so the launcher will not be able to process this, but it has to\r
878                         User::After(500000);\r
879                         reset_timing = 1;\r
880                 }\r
881                 else if(iWsEventType == EEventFocusGroupChanged) {\r
882                         TInt launcherGrpId = iWsSession.FindWindowGroupIdentifier(0, iLauncherThreadId);\r
883                         TInt focusGrpId = iWsSession.GetFocusWindowGroup();\r
884                         DEBUGPRINT(_L("EEventFocusGroupChanged: %i, our: %i, launcher: %i"),\r
885                                                 focusGrpId, iWsWindowGroup.Identifier(), launcherGrpId);\r
886                         // if it is not us and not launcher that got focus, pause emu\r
887                         if(focusGrpId != iWsWindowGroup.Identifier() && focusGrpId != launcherGrpId)\r
888                                 gamestate = PGS_Paused;\r
889                 }\r
890 \r
891                 iWsEventStatus = KRequestPending;\r
892                 iWsSession.EventReady(&iWsEventStatus);\r
893         }\r
894 \r
895         if(nEvents || forceUpdate) {\r
896                 allActions = areaActions;\r
897                 forceUpdate = 0;\r
898 \r
899                 // add all pushed button actions\r
900                 i = 0;\r
901                 for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++, i++) {\r
902                         if(e->flags & 1) allActions |= currentConfig.iKeyBinds[i];\r
903                         if((e->flags& 3) == 3) forceUpdate = 1;\r
904                         if(e->flags & 2) e->flags &= ~1;\r
905                 }\r
906 \r
907                 PicoPad[0] = (unsigned short) allActions;\r
908                 if(allActions & 0xFFFF0000) {\r
909                         RunEvents(allActions >> 16);\r
910                         areaActions = 0;\r
911                 }\r
912         }\r
913 }\r
914 \r
915 \r
916 void CGameWindow::DoKeysConfig(TUint &which)\r
917 {\r
918         TWsEvent iWsEvent;\r
919         int i;\r
920 \r
921         // to detect if user is holding power button\r
922         static int powerIters = 0;\r
923 \r
924         while(iWsEventStatus != KRequestPending)\r
925         {\r
926                 TUint currentActCode = 1 << which;\r
927 \r
928                 iWsSession.GetEvent(iWsEvent);\r
929 \r
930                 // pointer events?\r
931                 if(iWsEvent.Type() == EEventPointer) {\r
932                         TPoint p = iWsEvent.Pointer()->iPosition;\r
933                         TRect prev(190, 112, 208, 126);\r
934                         TRect next(190, 194, 208, 208);\r
935 \r
936                         if(iWsEvent.Pointer()->iType == TPointerEvent::EButton1Down) {\r
937                                      if(prev.Contains(p)) do { which = (which-1) & 0x1F; } while(!actionNames[which]);\r
938                                 else if(next.Contains(p)) do { which = (which+1) & 0x1F; } while(!actionNames[which]);\r
939                                 else if(which == 31) gamestate = PGS_Paused; // done\r
940                                 else {\r
941                                         const TPicoAreaConfigEntry *e = areaConfig + 1;\r
942                                         for(i = 0; e->rect != TRect(0,0,0,0); e++, i++)\r
943                                                 if(e->rect.Contains(p)) {\r
944                                                         currentConfig.iAreaBinds[i] ^= currentActCode;\r
945                                                         break;\r
946                                                 }\r
947                                 }\r
948                         }\r
949                 }\r
950                 else if(iWsEvent.Type() == EEventKeyDown || iWsEvent.Type() == EEventKeyUp)\r
951                 {\r
952                         //if(iWsEvent.Type() == EEventKey)\r
953                         //      DEBUGPRINT(_L("iWsEvent.Key()->iCode=0x%08x"), iWsEvent.Key()->iCode);\r
954 \r
955                         //if(iWsEvent.Type() == EEventKeyDown)\r
956                         //      DEBUGPRINT(_L("EEventKeyDown iScanCode=0x%08x"), iWsEvent.Key()->iScanCode);\r
957 \r
958                         //if(iWsEvent.Type() == EEventKeyUp)\r
959                         //      DEBUGPRINT(_L("EEventKeyUp   iScanCode=0x%08x"), iWsEvent.Key()->iScanCode);\r
960 \r
961                         // key events?\r
962                         if(iWsEvent.Type() == EEventKeyDown) {\r
963                                 if(iWsScreen->CurrentScreenMode() == 1 && iWsEvent.Key()->iScanCode == EScanPxxxJogUp) {\r
964                                         do { which = (which-1) & 0x1F; } while(!actionNames[which]);\r
965                                 } else if(iWsScreen->CurrentScreenMode() == 1 && iWsEvent.Key()->iScanCode == EScanPxxxJogDown) {\r
966                                         do { which = (which+1) & 0x1F; } while(!actionNames[which]);\r
967                                 } else if(which == 31) {\r
968                                         gamestate = PGS_Paused;\r
969                                         if(iWsScreen->CurrentScreenMode()) // flip closed\r
970                                                 vidDrawFCconfigDone();\r
971                                 } else {\r
972                                         i = 0;\r
973                                         for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++, i++)\r
974                                                 if(iWsEvent.Key()->iScanCode == e->scanCode)\r
975                                                         if(!(e->flags&0x40)) currentConfig.iKeyBinds[i] ^= currentActCode;\r
976                                 }\r
977                         }\r
978 \r
979                         // power?\r
980                         if(iWsEvent.Key()->iScanCode == EScanPxxxPower || iWsEvent.Key()->iScanCode == EScanMotAEnd)\r
981                         {\r
982                                          if(iWsEvent.Type() == EEventKeyDown) powerIters = 1;\r
983                                 else if(iWsEvent.Type() == EEventKeyUp)   powerIters = 0;\r
984                         }\r
985                 }\r
986                 else if(iWsEvent.Type() == EEventScreenDeviceChanged) {\r
987                         // trying to fix the P910 problem when something steals focus (and returns it after a while?)\r
988                         User::After(300000);\r
989                 }\r
990                 else if(iWsEvent.Type() == EEventFocusGroupChanged) {\r
991                         TInt launcherGrpId = iWsSession.FindWindowGroupIdentifier(0, iLauncherThreadId);\r
992                         TInt focusGrpId = iWsSession.GetFocusWindowGroup();\r
993                         DEBUGPRINT(_L("EEventFocusGroupChanged: %i, our: %i, launcher: %i"),\r
994                                                 focusGrpId, iWsWindowGroup.Identifier(), launcherGrpId);\r
995                         // if it is not us and not launcher that got focus, exit config mode\r
996                         if(focusGrpId != iWsWindowGroup.Identifier() && focusGrpId != launcherGrpId) {\r
997                                 // don't give up that easily. May be the focus will be given back.\r
998                                 for (int i = 0; i < 4; i++) {\r
999                                         User::After(200000);\r
1000                                         focusGrpId = iWsSession.GetFocusWindowGroup();\r
1001                                         if(focusGrpId == iWsWindowGroup.Identifier() || focusGrpId == launcherGrpId) break;\r
1002                                 }\r
1003                                 if(focusGrpId != iWsWindowGroup.Identifier() && focusGrpId != launcherGrpId) \r
1004                                         // we probably should give up now\r
1005                                         gamestate = PGS_Paused;\r
1006                         }\r
1007                 }\r
1008 \r
1009                 iWsEventStatus = KRequestPending;\r
1010                 iWsSession.EventReady(&iWsEventStatus);\r
1011         }\r
1012 \r
1013         if(powerIters) { // iterations when power was down\r
1014                 powerIters++;\r
1015                 if(powerIters > 5) {\r
1016                         gamestate = PGS_Paused;\r
1017                         powerIters = 0;\r
1018                 }\r
1019         }\r
1020 }\r
1021 \r
1022 \r
1023 void CGameWindow::RunEvents(TUint32 which)\r
1024 {\r
1025         if(which & 0x4000) currentConfig.iFrameskip = -1;\r
1026         if(which & 0x2000) currentConfig.iFrameskip =  8;\r
1027         if(which & 0x1800) { // save or load (but not both)\r
1028                 if(PsndOut) gameAudio->Pause(); // this may take a while, so we pause sound output\r
1029 \r
1030                 vidDrawNotice((which & 0x1000) ? "LOADING@GAME" : "SAVING@GAME");\r
1031                 saveLoadGame(which & 0x1000);\r
1032 \r
1033                 if(PsndOut) PsndOut = gameAudio->ResumeL();\r
1034                 reset_timing = 1;\r
1035         }\r
1036         if(which & 0x0400) gamestate = PGS_Paused;\r
1037         if(which & 0x0200) { // switch renderer\r
1038                 if(currentConfig.iScreenMode == TPicoConfig::PMCenter && !noticeMsgTime.tv_sec &&\r
1039                         (currentConfig.iScreenRotation == TPicoConfig::PRot90 || currentConfig.iScreenRotation == TPicoConfig::PRot270)) {\r
1040 \r
1041                         PicoOpt^=0x10;\r
1042                         vidInit(iWsScreen->DisplayMode(), 0, 0, 1);\r
1043 \r
1044                         strcpy(noticeMsg, (PicoOpt&0x10) ? "ALT@RENDERER" : "DEFAULT@RENDERER");\r
1045                         gettimeofday(&noticeMsgTime, 0);\r
1046                 }\r
1047         }\r
1048         if(which & 0x00c0) {\r
1049                 if(which&0x0080) {\r
1050                         state_slot -= 1;\r
1051                         if(state_slot < 0) state_slot = 9;\r
1052                 } else {\r
1053                         state_slot += 1;\r
1054                         if(state_slot > 9) state_slot = 0;\r
1055                 }\r
1056                 sprintf(noticeMsg, "SAVE@SLOT@%i@SELECTED", state_slot);\r
1057                 gettimeofday(&noticeMsgTime, 0);\r
1058         }\r
1059         if(which & 0x0020) if(gameAudio) gameAudio->ChangeVolume(0); // for Motorolas (broken?)\r
1060         if(which & 0x0010) if(gameAudio) gameAudio->ChangeVolume(1);\r
1061 }\r
1062 \r
1063 \r
1064 // send event to launcher windowgroup (WS session MUST be alive)\r
1065 void CGameWindow::SendClientWsEvent(TInt type)\r
1066 {\r
1067         if(!iWsSession.Handle()) {\r
1068                 DEBUGPRINT(_L("SendClientWsEvent(%i) called on dead iWsSession."), type);\r
1069                 return;\r
1070         }\r
1071 \r
1072         TWsEvent event;\r
1073         event.SetType(type);\r
1074         event.SetTimeNow();\r
1075 \r
1076         TInt launcherGrpId = iWsSession.FindWindowGroupIdentifier(0, iLauncherThreadId);\r
1077         if(launcherGrpId != KErrNotFound)\r
1078                  iWsSession.SendEventToWindowGroup(launcherGrpId, event);\r
1079         else DEBUGPRINT(_L("failed to send event %i to launcher."), event.Type());\r
1080 }\r
1081 \r
1082 \r
1083 size_t gzRead2(void *p, size_t _size, size_t _n, void *file)\r
1084 {\r
1085         return gzread(file, p, _n);\r
1086 }\r
1087 \r
1088 \r
1089 size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)\r
1090 {\r
1091         return gzwrite(file, p, _n);\r
1092 }\r
1093 \r
1094 \r
1095 // this function is shared between both threads\r
1096 int saveLoadGame(int load, int sram)\r
1097 {\r
1098         int res = 0;\r
1099 \r
1100         if(!RomFileName) return -1;\r
1101 \r
1102         // make save filename\r
1103         char saveFname[KMaxFileName];\r
1104         strcpy(saveFname, RomFileName);\r
1105         saveFname[KMaxFileName-8] = 0;\r
1106         if(saveFname[strlen(saveFname)-4] == '.') saveFname[strlen(saveFname)-4] = 0;\r
1107         if(sram) strcat(saveFname, ".srm");\r
1108         else {\r
1109                 if(state_slot > 0 && state_slot < 10) sprintf(saveFname, "%s.%i", saveFname, state_slot);\r
1110                 strcat(saveFname, ".mds");\r
1111         }\r
1112         \r
1113         DEBUGPRINT(_L("saveLoad (%i, %i): %S"), load, sram, DO_CONV(saveFname));\r
1114 \r
1115         if(sram) {\r
1116                 FILE *sramFile;\r
1117                 int sram_size = SRam.end-SRam.start+1;\r
1118                 if(SRam.reg_back & 4) sram_size=0x2000;\r
1119                 if(!SRam.data) return 0; // SRam forcefully disabled for this game\r
1120                 if(load) {\r
1121                         sramFile = fopen(saveFname, "rb");\r
1122                         if(!sramFile) return -1;\r
1123                         fread(SRam.data, 1, sram_size, sramFile);\r
1124                         fclose(sramFile);\r
1125                 } else {\r
1126                         // sram save needs some special processing\r
1127                         // see if we have anything to save\r
1128                         for(; sram_size > 0; sram_size--)\r
1129                                 if(SRam.data[sram_size-1]) break;\r
1130                         \r
1131                         if(sram_size) {\r
1132                                 sramFile = fopen(saveFname, "wb");\r
1133                                 res = fwrite(SRam.data, 1, sram_size, sramFile);\r
1134                                 res = (res != sram_size) ? -1 : 0;\r
1135                                 fclose((FILE *) sramFile);\r
1136                         }\r
1137                 }\r
1138                 return res;\r
1139         } else {\r
1140                 void *PmovFile = NULL;\r
1141                 // try gzip first\r
1142                 if(currentConfig.iFlags & 0x80) {\r
1143                         strcat(saveFname, ".gz");\r
1144                         if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) {\r
1145                                 areaRead  = gzRead2;\r
1146                                 areaWrite = gzWrite2;\r
1147                                 if(!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY);\r
1148                         } else\r
1149                                 saveFname[strlen(saveFname)-3] = 0;\r
1150                 }\r
1151                 if(!PmovFile) { // gzip failed or was disabled\r
1152                         if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) {\r
1153                                 areaRead  = fread;\r
1154                                 areaWrite = fwrite;\r
1155                         }\r
1156                 }\r
1157                 if(PmovFile) {\r
1158                         PmovState(load ? 6 : 5, PmovFile);\r
1159                         strcpy(noticeMsg, load ? "GAME@LOADED" : "GAME@SAVED");\r
1160                         if(areaRead == gzRead2)\r
1161                                  gzclose(PmovFile);\r
1162                         else fclose ((FILE *) PmovFile);\r
1163                         PmovFile = 0;\r
1164                 } else {\r
1165                         strcpy(noticeMsg, load ? "LOAD@FAILED" : "SAVE@FAILED");\r
1166                         res = -1;\r
1167                 }\r
1168 \r
1169                 gettimeofday(&noticeMsgTime, 0);\r
1170                 return res;\r
1171         }\r
1172 }\r
1173 \r
1174 // static class members\r
1175 RWsSession                              CGameWindow::iWsSession;\r
1176 RWindowGroup                    CGameWindow::iWsWindowGroup;\r
1177 RWindow                                 CGameWindow::iWsWindow;\r
1178 CWsScreenDevice*                CGameWindow::iWsScreen = NULL;\r
1179 CWindowGc*                              CGameWindow::iWindowGc = NULL;\r
1180 TRequestStatus                  CGameWindow::iWsEventStatus = KRequestPending;\r
1181 TThreadId                               CGameWindow::iLauncherThreadId = 0;\r
1182 RDirectScreenAccess*    CGameWindow::iDSA;\r
1183 TRequestStatus                  CGameWindow::iDSAstatus = KRequestPending;\r