Пример #1
0
static void *removalCallback (void *arg)
{
  while(devsleep > 0)
  {
    if(!rThreadRun)
      LWP_SuspendThread(removalThread);
      usleep(THREAD_SLEEP);
      devsleep -= THREAD_SLEEP;
  }

  while (1)
  {
    switch(sdMounted) //some kind of SD is mounted
    {
#ifdef HW_RVL
      case FRONTSD:   //check which one, if removed, set as unmounted
        if(!frontsd->isInserted()) {
          sdNeedsUnmount=sdMounted;
          sdMounted=0;
        }
        break;
#endif
/*    //Polling EXI is bad with locks, so lets not do it.
      case CARD_A:   //check which one, if removed, set as unmounted
        if(!carda->isInserted()) {
          sdNeedsUnmount=sdMounted;
          sdMounted=0;
        }
        break;
      case CARD_B:   //check which one, if removed, set as unmounted
        if(!cardb->isInserted()) {
          sdNeedsUnmount=sdMounted;
          sdMounted=0;
        }
        break;
*/
    }
#ifdef HW_RVL
    if(usbMounted) // check if the device was removed
      if(!usb->isInserted()) {
        usbMounted = 0;
        usbNeedsUnmount=1;
      }
#endif

    devsleep = 1000*1000; // 1 sec
    while(devsleep > 0)
    {
      if(!rThreadRun)
        LWP_SuspendThread(removalThread);
      usleep(THREAD_SLEEP);
      devsleep -= THREAD_SLEEP;
    }
  }
  return NULL;
}
void * GuiImageAsync::GuiImageAsyncThread(void *arg)
{
	while(!CloseThread)
	{
		if(ThreadSleep)
			LWP_SuspendThread(Thread);

		while(!List.empty() && !CloseThread)
		{
			LWP_MutexLock(ListLock);
			InUse = List.front();
			List.erase(List.begin());
			LWP_MutexUnlock(ListLock);

			if (!InUse)
				continue;

			InUse->imgData = InUse->callback(InUse->arg);

			if (InUse->imgData && InUse->imgData->GetImage())
			{
				InUse->width = InUse->imgData->GetWidth();
				InUse->height = InUse->imgData->GetHeight();
				InUse->image = InUse->imgData->GetImage();
			}

			InUse = NULL;
		}

		ThreadSleep = true;
	}

	return NULL;
}
Пример #3
0
/*********************************************************************************
 * Networkthread for background network initialize and update check with idle prio
 *********************************************************************************/
static void * networkinitcallback(void *arg)
{
	while (1)
	{
		if (!checkincomming && networkHalt)
			LWP_SuspendThread(networkthread);

		Initialize_Network();

		if (networkinitialized == true && updatechecked == false)
		{

			if (CheckUpdate() > 0) updateavailable = true;

			//suspend thread
			updatechecked = true;
			networkHalt = true;
		}

		if (checkincomming) NetworkWait();

		usleep(100000);
	}
	return NULL;
}
Пример #4
0
void ExitCleanup()
{
	LWP_SuspendThread (devicethread);
	UnmountAllFAT();
	CloseShare();

#ifdef HW_RVL
	DI_Close();
#endif
}
Пример #5
0
static void *
parsecallback (void *arg)
{
	while(1)
	{
		while(ParseDirEntries())
			usleep(THREAD_SLEEP);
		LWP_SuspendThread(parsethread);
	}
	return NULL;
}
Пример #6
0
// Init the GC/Wii net interface (wifi/bba/etc)
static void* init_network(void *args) {
 
  char ip[16];
  int res = 0, netsleep = 1*1000*1000;
  
  while(netsleep > 0) {
      if(netInitHalted) {
        LWP_SuspendThread(initnetthread);
      }
        usleep(100);
        netsleep -= 100;
  }

  while(1) {

    if(!net_initialized) {
      netInitPending = 1;
      res = if_config(ip, NULL, NULL, true, 5);
      if(res >= 0) {
        net_initialized = 1;
      }
      else {
        net_initialized = 0;
      }
      netInitPending = 0;
    }

    netsleep = 1000*1000; // 1 sec
    while(netsleep > 0) {
      if(netInitHalted) {
        LWP_SuspendThread(initnetthread);
      }
      usleep(100);
      netsleep -= 100;
    }
  }
  return NULL;
}
Пример #7
0
/****************************************************************************
 * UpdateGUI
 *
 * Primary thread to allow GUI to respond to state changes, and draws GUI
 ***************************************************************************/
static void * UpdateGUI(void *arg)
{
    u8 i;

    while (!ExitRequested)
    {
        if (guiHalt)
        {
            LWP_SuspendThread(guithread);
            continue;
        }

        UpdatePads();

        mainWindow->Draw();
        if (Settings.tooltips && Theme::ShowTooltips && mainWindow->GetState() != STATE_DISABLED)
            mainWindow->DrawTooltip();

        // Pointer modifies wpad data struct for easy implementation of "virtual pointer" with PAD-Sticks
        // That is why it has to be called right before updating other gui elements with the triggers
        i = 4;
        while(i--)
            pointer[i]->Draw(&userInput[i]);

        for (i = 0; i < 4; i++)
            mainWindow->Update(&userInput[i]);

        Menu_Render();

        if (bgMusic) bgMusic->UpdateState();
    }

    for (i = 5; i < 255; i += 10)
    {
        mainWindow->Draw();
        Menu_DrawRectangle(0, 0, screenwidth, screenheight, (GXColor) {
            0, 0, 0, i
        }, 1);
        Menu_Render();
    }

    mainWindow->RemoveAll();
    ShutoffRumble();

    return NULL;
}
Пример #8
0
static void *
UpdateGUI (void *arg)
{
	int i;

	while(1)
	{
		if(guiHalt)
		{
			LWP_SuspendThread(guithread);
		}
		else
		{
			UpdatePads();
			mainWindow->Draw();

			#ifdef HW_RVL
			for(i=3; i >= 0; i--) // so that player 1's cursor appears on top!
			{
				if(userInput[i].wpad->ir.valid)
					Menu_DrawImg(userInput[i].wpad->ir.x-48, userInput[i].wpad->ir.y-48,
						96, 96, pointer[i]->GetImage(), userInput[i].wpad->ir.angle, 1, 1, 255);
				DoRumble(i);
			}
			#endif

			Menu_Render();

			for(i=0; i < 4; i++)
				mainWindow->Update(&userInput[i]);

			if(ExitRequested)
			{
				for(i = 0; i < 255; i += 15)
				{
					mainWindow->Draw();
					Menu_DrawRectangle(0,0,screenwidth,screenheight,(GXColor){0, 0, 0, i},1);
					Menu_Render();
				}
				ExitApp();
			}
		}
	}
	return NULL;
}
Пример #9
0
static void *
devicecallback (void *arg)
{
	while (1)
	{
		if(isMounted[DEVICE_SD])
		{
			if(!sd->isInserted()) // check if the device was removed
			{
				unmountRequired[DEVICE_SD] = true;
				isMounted[DEVICE_SD] = false;
			}
		}

		if(isMounted[DEVICE_USB])
		{
			if(!usb->isInserted()) // check if the device was removed
			{
				unmountRequired[DEVICE_USB] = true;
				isMounted[DEVICE_USB] = false;
			}
		}

		if(isMounted[DEVICE_DVD])
		{
			if(!dvd->isInserted()) // check if the device was removed
			{
				unmountRequired[DEVICE_DVD] = true;
				isMounted[DEVICE_DVD] = false;
			}
		}

		devsleep = 1000*1000; // 1 sec

		while(devsleep > 0)
		{
			if(deviceHalt)
				LWP_SuspendThread(devicethread);
			usleep(THREAD_SLEEP);
			devsleep -= THREAD_SLEEP;
		}
		// UpdateCheck();
	}
	return NULL;
}
Пример #10
0
bool DownloadUpdate()
{
	bool result = false;
	if(strlen(updateURL) > 0)
	{
		// stop checking if devices were removed/inserted
		// since we're saving a file
		LWP_SuspendThread (devicethread);

		FILE * hfile;
		char updateFile[50];
		sprintf(updateFile, "sd:/%s Update.zip", APPNAME);
		hfile = fopen (updateFile, "wb");

		if (hfile > 0)
		{
			int retval;
			retval = http_request(updateURL, hfile, NULL, (1024*1024*5));
			fclose (hfile);
		}

		bool unzipResult = unzipArchive(updateFile, (char *)"sd:/");
		remove(updateFile); // delete update file

		if(unzipResult)
		{
			result = true;
			WaitPrompt("Update successful!");
		}
		else
		{
			result = false;
			WaitPrompt("Update failed!");
		}

		updateFound = false; // updating is finished (successful or not!)

		// go back to checking if devices were inserted/removed
		LWP_ResumeThread (devicethread);
	}
	return result;
}
Пример #11
0
void * ThreadedTask::ThreadCallback(void *arg)
{
	ThreadedTask * myInstance = (ThreadedTask *) arg;

	while(!myInstance->ExitRequested)
	{
		LWP_SuspendThread(myInstance->Thread);

		while(!myInstance->CallbackList.empty())
		{
			if(myInstance->CallbackList[0].first)
				myInstance->CallbackList[0].first->Execute(myInstance->ArgList[0]);

			else if(myInstance->CallbackList[0].second)
				myInstance->CallbackList[0].second(myInstance->ArgList[0]);

			myInstance->CallbackList.erase(myInstance->CallbackList.begin());
			myInstance->ArgList.erase(myInstance->ArgList.begin());
		}
	}

	return NULL;
}
Пример #12
0
void *DiHandler::ThreadMain( void *arg )
{
	enum State
	{
		St_Init,
		St_Reset,
		St_WaitForDisc,
		St_CheckDiscType,
		St_OpenPartition,
		St_WaitForDiscEject,	// some error happened, dont do anything until the current disc is ejected
		St_Idle
	};

	State state = St_Init;

	u32 coverState = 0;

	while( !threadExit )
	{
		usleep( 1000 );

		if( threadSleep )
			LWP_SuspendThread( thread );

		if( state == St_Init )
		{
			if( WDVD_Init() )
			{
				instance->ErrorHappened( E_Init, true );
				threadExit = true;
			}
			state = St_Reset;
			continue;
		}
		else if( state == St_Reset )
		{
			if( WDVD_Reset() )
			{
				instance->ErrorHappened( E_Init, false );
				continue;
			}
			state = St_WaitForDisc;
		}

		// check for disc
		u32 cover = 0;
		if( WDVD_GetCoverStatus( &cover ) )
		{
			gprintf( "WDVD_GetCoverStatus() failed\n" );
			WDVD_Close();
			state = St_Init;
			continue;
		}

		// check if disc status is changed
		if( cover != coverState )
		{
			//gprintf( "cover status: %08x %08x\n", cover, coverState );
			if( cover & 2 )// disc is present and wasnt before
			{
				//gprintf( "disc inserted\n" );
				instance->StartingToReadDisc();
				WDVD_Reset();
				state = St_CheckDiscType;
			}
			else if( coverState & 2 )// disc was present before isnt is gone now
			{
				instance->DiscEjected();
				//gprintf( "disc ejected\n" );
				state = St_WaitForDisc;
			}
			coverState = cover;
		}
		if( !( cover & 2 ) )// if theres no disc inserted, then loop
		{
			continue;
		}

		if( state == St_WaitForDiscEject )
		{
			continue;
		}
		else if( state == St_CheckDiscType )
		{
			s32 ret = WDVD_ReadDiskId( (void*)0x80000000 );
			if( ret < 0 )
			{
				gprintf("WDVD_ReadDiskId(): %d\n", ret );
				instance->ErrorHappened( E_DVD_ReadError, false );
				//state = St_WaitForDiscEject;
				WDVD_Close();
				state = St_Init;
				//coverState = 0;
				continue;
			}

			// check disc type
			if( *(u32*)( 0x80000018 ) == 0x5d1c9ea3 )
			{
				//gprintf( "disc is wii\n" );
				state = St_OpenPartition;
				//instance->DiscInserted( T_Wii );
			}
			else if( *(u32*)( 0x8000001c ) == 0xc2339f3d )
			{
				//gprintf( "disc is gamecube\n" );
				instance->DiscInserted( T_GC );
				state = St_Idle;
			}
			else
			{
				//gprintf( "disc is unknown\n" );
				instance->DiscInserted( T_Unknown );
				state = St_WaitForDiscEject;
				//hexdump( (void*)0x80000000, 0x20 );
			}
		}
		else if( state == St_OpenPartition )
		{
			if( WDVD_OpenDataPartition() < 0 )
			{
				instance->ErrorHappened( E_OpenPartition, false );
				state = St_WaitForDiscEject;
				continue;
			}
			//gprintf( "partition is open\n" );

			// search for the opening.bnr
			s32 ret;
			FST_INFO fst_info __attribute(( aligned( 32 ) ));

			//find FST inside partition
			ret = WDVD_Read( (u8*)&fst_info, sizeof( FST_INFO ), 0x420LL );
			if( ret < 0 )
			{
				gprintf("WDVD_Read( fst_info ): %d\n", ret );
				instance->ErrorHappened( E_DVD_ReadError, false );
				state = St_WaitForDiscEject;
				WDVD_ClosePartition();
				continue;
			}
			fst_info.fst_offset <<= 2;
			fst_info.fst_size <<= 2;
			//gprintf( "%s %i\n", __FILE__, __LINE__ );

			fst_buffer = (u8*)memalign( 32, RU( fst_info.fst_size, 0x40 ) );
			if( !fst_buffer )
			{
				instance->ErrorHappened( E_NoMem, true );
				threadExit = true;
				WDVD_ClosePartition();
				continue;
			}
			//gprintf( "%s %i\n", __FILE__, __LINE__ );
			//gprintf( " %p  %08x %08x\n", fst_buffer, fst_info.fst_size, fst_info.fst_offset );

			//read fst into memory
			ret = WDVD_Read( fst_buffer, fst_info.fst_size, fst_info.fst_offset );
			if( ret < 0 )
			{
				gprintf("WDVD_Read( fst_buffer ): %d\n", ret );
				instance->ErrorHappened( E_DVD_ReadError, false );
				state = St_WaitForDiscEject;
				WDVD_ClosePartition();
				continue;
			}
			//gprintf( "%s %i\n", __FILE__, __LINE__ );

			//set the pointers
			fst = (FST_ENTRY *)fst_buffer;
			u32 name_table_offset = fst->filelen * 0xC;
			name_table = (char *)( fst_buffer + name_table_offset );

			//gprintf( "%s %i\n", __FILE__, __LINE__ );
			// find the opening.bnr
			int fd = EntryFromPath( "/opening.bnr", 0 );
			if( fd < 2 )
			{
				instance->ErrorHappened( E_NoOpeningBnr, false );
				instance->DiscInserted( T_Wii );
				FREE( fst );
				name_table = NULL;
				state = St_Idle;
				WDVD_ClosePartition();
				continue;
			}
			//gprintf( "%s %i\n", __FILE__, __LINE__ );
			u32 len = fst[ fd ].filelen;
			u8 *buf = (u8*)memalign( 32, RU( len, 0x40 ) );
			if( !buf )
			{
				instance->ErrorHappened( E_NoMem, true );
				threadExit = true;
				FREE( fst );
				name_table = NULL;
				WDVD_ClosePartition();
				continue;
			}
			//gprintf( "%s %i\n", __FILE__, __LINE__ );
			ret = WDVD_Read( buf, len, (u64)( fst[ fd ].fileoffset ) << 2 );
			if( ret < 0 )
			{
				gprintf("WDVD_Read( opening.bnr ): %d\n", ret );
				instance->ErrorHappened( E_DVD_ReadError, false );
				state = St_WaitForDiscEject;
				FREE( fst );
				name_table = NULL;
				free( buf );
				WDVD_ClosePartition();
				continue;
			}

			//gprintf( "%s %i\n", __FILE__, __LINE__ );
			// done with these
			FREE( fst );
			name_table = NULL;
			WDVD_ClosePartition();

			//gprintf( "%s %i\n", __FILE__, __LINE__ );
			bool rec = false;
			// got the opening.bnr.  send it to whoever cares
			instance->OpeningBnrReady( buf, len, rec );
			if( !rec )
			{
				gprintf( "nobody got the banner.  freeing it\n" );
				free( buf );
			}
			instance->DiscInserted( T_Wii );
			//gprintf( "%s %i\n", __FILE__, __LINE__ );
			state = St_Idle;
		}
	}

	return NULL;
}
Пример #13
0
static void * PressKeys (void *arg)
{
	SDL_Event event;
	int shift;
	u16 i;
	
	memset(shiftkey, 0, sizeof(shiftkey));
	shiftkey[33] = 49;
	shiftkey[34] = 39;
	shiftkey[35] = 51;
	shiftkey[36] = 52;
	shiftkey[37] = 53;
	shiftkey[38] = 55;
	shiftkey[40] = 57;
	shiftkey[41] = 48;
	shiftkey[42] = 56;
	shiftkey[58] = 59;
	shiftkey[60] = 44;
	shiftkey[62] = 46;
	shiftkey[63] = 47;
	shiftkey[64] = 50;
	shiftkey[94] = 54;
	shiftkey[95] = 45;
	shiftkey[126] = 96;

	while(1)
	{
		LWP_SuspendThread(keythread);
		usleep(1200);

		for(i=0; i<strlen(dosboxCommand); i++)
		{
			shift=0;

			if((dosboxCommand[i] >= 65 && dosboxCommand[i] <= 90))
			{
				dosboxCommand[i] += 32;
				shift = 1;
			}
			else if(dosboxCommand[i] > 0 && dosboxCommand[i] < 130 && 
					shiftkey[(int)dosboxCommand[i]] > 0)
			{
				dosboxCommand[i] = shiftkey[(int)dosboxCommand[i]];
				shift = 1;
			}

			if(shift)
			{
				event.type = SDL_KEYDOWN;
				event.key.keysym.sym = SDLK_LSHIFT;
				MAPPER_CheckEvent(&event);
				usleep(600);
			}
			
			// hack to allow mappings of SDL keys > 127
			int keyoffset = 0;
			if(dosboxCommand[i] >= 14 && dosboxCommand[i] <= 25)
				keyoffset = 268; // F1-F12 (282-293)

			event.type = SDL_KEYDOWN;
			event.key.keysym.sym = (SDLKey)((int)dosboxCommand[i]+keyoffset);
			MAPPER_CheckEvent(&event);
			usleep(600);

			event.type = SDL_KEYUP;
			event.key.keysym.sym = (SDLKey)((int)dosboxCommand[i]+keyoffset);
			MAPPER_CheckEvent(&event);
			usleep(600);

			if(shift)
			{
				event.type = SDL_KEYUP;
				event.key.keysym.sym = SDLK_LSHIFT;
				MAPPER_CheckEvent(&event);
				usleep(600);
			}
		}
		dosboxCommand[0] = 0;
	}
	return NULL;
}
Пример #14
0
void DiHandler::Sleep()
{
	threadSleep = true;
	LWP_SuspendThread( thread );
}
Пример #15
0
int main(int argc, char *argv[])
{
	#ifdef HW_DOL
	ipl_set_config(6); // disable Qoob modchip
	#endif

	#ifdef WII_DVD
	DI_Init();	// first
	#endif

	int selectedMenu = -1;

	InitDeviceThread();

	InitGCVideo ();
	ResetVideo_Menu (); // change to menu video mode

	// Controllers
	PAD_Init();

	#ifdef HW_RVL
	WPAD_Init();
	// read wiimote accelerometer and IR data
	WPAD_SetDataFormat(WPAD_CHAN_ALL,WPAD_FMT_BTNS_ACC_IR);
	WPAD_SetVRes(WPAD_CHAN_ALL,640,480);

	// Wii Power/Reset buttons
	WPAD_SetPowerButtonCallback((WPADShutdownCallback)ShutdownCB);
	SYS_SetPowerCallback(ShutdownCB);
	SYS_SetResetCallback(ResetCB);
	#endif

	// Initialise FreeType
	if (FT_Init ())
	{
		printf ("Cannot initialise font subsystem!\n");
		while (1);
	}

	InitialiseAudio();

	// Initialize libFAT for SD and USB
	MountAllFAT();

	// Initialize DVD subsystem (GameCube only)
	#ifdef HW_DOL
	DVD_Init ();
	#endif

	// allocate memory to store rom
	nesrom = (unsigned char *)malloc(1024*1024*3); // 3 MB should be plenty

	/*** Minimal Emulation Loop ***/
	if ( !FCEUI_Initialize() )
	{
		WaitPrompt("Unable to initialize FCE Ultra\n");
		ExitToLoader();
	}

	FCEUI_SetGameGenie(0); // 0 - OFF, 1 - ON

	memset(FDSBIOS, 0, sizeof(FDSBIOS)); // clear FDS BIOS memory
	cleanSFMDATA(); // clear state data

	// Set defaults
	DefaultSettings();

	// store path app was loaded from
	sprintf(appPath, "fceugx");
	if(argc > 0 && argv[0] != NULL)
		CreateAppPath(argv[0]);

	// Load preferences
	if(!LoadPrefs())
	{
		WaitPrompt("Preferences reset - check settings!");
		selectedMenu = 1; // change to preferences menu
	}

	FCEUI_SetSoundQuality(1); // 0 - low, 1 - high, 2 - high (alt.)
	FCEUI_SetVidSystem(GCSettings.timing); // causes a small 'pop' in the audio

    while (1) // main loop
    {
		#ifdef HW_RVL
		if(ShutdownRequested)
			ShutdownWii();
		#endif

		// go back to checking if devices were inserted/removed
		// since we're entering the menu
		LWP_ResumeThread (devicethread);

    	MainMenu(selectedMenu);
		selectedMenu = 2; // return to game menu from now on

		// stop checking if devices were removed/inserted
		// since we're starting emulation again
		LWP_SuspendThread (devicethread);

		ResetVideo_Emu();

		setFrameTimer(); // set frametimer method before emulation
		SetPalette();

		static int fskipc=0;

		while(1) // emulation loop
		{
			uint8 *gfx;
			int32 *sound;
			int32 ssize;

			#ifdef FRAMESKIP
			fskipc=(fskipc+1)%(frameskip+1);
			#endif

			FCEUI_Emulate(&gfx, &sound, &ssize, fskipc);

			if(!fskipc)
			{
				xbsave = gfx;
				FCEUD_Update(gfx, sound, ssize);
			}

			if(ResetRequested)
			{
				PowerNES(); // reset game
				ResetRequested = 0;
			}

			if(ConfigRequested)
			{
				ResetVideo_Menu();
				if (GCSettings.AutoSave == 1)
				{
					SaveRAM(GCSettings.SaveMethod, SILENT);
				}
				else if (GCSettings.AutoSave == 2)
				{
					SaveState(GCSettings.SaveMethod, SILENT);
				}
				else if(GCSettings.AutoSave == 3)
				{
					SaveRAM(GCSettings.SaveMethod, SILENT);
					SaveState(GCSettings.SaveMethod, SILENT);
				}

				// save zoom level
				SavePrefs(SILENT);

				ConfigRequested = 0;
				break; // leave emulation loop
			}
		}
    }
}
Пример #16
0
static void * netcb (void *arg)
{
	s32 res=-1;
	int retry;
	int wait;
	static bool prevInit = false;

	while(netHalt != 2)
	{
		retry = 5;
		
		while (retry>0 && (netHalt != 2))
		{			
			if(prevInit) 
			{
				int i;
				net_deinit();
				for(i=0; i < 400 && (netHalt != 2); i++) // 10 seconds to try to reset
				{
					res = net_get_status();
					if(res != -EBUSY) // trying to init net so we can't kill the net
					{
						usleep(2000);
						net_wc24cleanup(); //kill the net 
						prevInit=false; // net_wc24cleanup is called only once
						usleep(20000);
						break;					
					}
					usleep(20000);
				}
			}

			usleep(2000);
			res = net_init_async(NULL, NULL);

			if(res != 0)
			{
				sleep(1);
				retry--;
				continue;
			}

			res = net_get_status();
			wait = 400; // only wait 8 sec
			while (res == -EBUSY && wait > 0  && (netHalt != 2))
			{
				usleep(20000);
				res = net_get_status();
				wait--;
			}

			if(res==0) break;
			retry--;
			usleep(2000);
		}
		if (res == 0)
		{
			struct in_addr hostip;
			hostip.s_addr = net_gethostip();
			if (hostip.s_addr)
			{
				strcpy(wiiIP, inet_ntoa(hostip));
				networkInit = true;	
				prevInit = true;
			}
		}
		if(netHalt != 2) LWP_SuspendThread(networkthread);
	}
	return NULL;
}
Пример #17
0
static void *
UpdateGUI (void *arg)
{
	int i;

	while(1)
	{
		if(guiHalt)
		{
			LWP_SuspendThread(guithread);
		}
		else
		{
			UpdatePads();
			mainWindow->Draw();

			#ifdef HW_RVL
		//	for(i=3; i >= 0; i--) // so that player 1's cursor appears on top!
		//	{
				if(userInput[0].wpad->ir.valid)
					Menu_DrawImg(userInput[0].wpad->ir.x-48, userInput[0].wpad->ir.y-48,
						96, 96, pointer->GetImage(), userInput[0].wpad->ir.angle, 1, 1, 255);
		//	}
			#endif

			Menu_Render();

		//	for(i=0; i < 4; i++)
				mainWindow->Update(&userInput[0]);

			if(ExitRequested)
			{
				for(i = 0; i < 255; i += 15)
				{
					mainWindow->Draw();
					GXColor Color = (GXColor) {0, 0, 0, i};
					Menu_DrawRectangle(0,0,screenwidth,screenheight,&Color,false,true);
					Menu_Render();
				}

				if (boothomebrew)
				{
					LoadHomebrew(Settings.forwarder_path.c_str());

					string startingAppName = Settings.forwarder_path;

					if((signed)startingAppName.rfind("/") != -1)
						startingAppName.erase(startingAppName.rfind("/"));

					startingAppName.erase(0, startingAppName.rfind("/") +1);

					if(IOS_GetVersion() != GetAppIOS(startingAppName))
						addAppIos(Settings.startingAppName, SelectedIOS());
				}
				if (!goneek2o)
					ExitApp();
			}

			// sd check
			if(Settings.device == "sd1")
				check_sd();

			// usb check
			else if(Settings.device == "usb1")
				check_usb();

			// sd und usb check
			else if(Settings.device == "sd_usb")
			{
				check_sd();
				check_usb();
			}

			else if(Settings.device == "dvd")
				check_dvd();
#ifndef VWII
			else if(Settings.device == "gca")
				check_gca();

			else if(Settings.device == "gcb")
				check_gcb();
#endif
			else if(Settings.device == "all")
			{
				check_sd();
				check_usb();
				check_dvd();
#ifndef VWII
				check_gca();
				check_gcb();
#endif
			}

			// screenshoot
			if(WPAD_ButtonsDown(0) & WPAD_BUTTON_1 && WPAD_ButtonsDown(0) & WPAD_BUTTON_2)
				Screenshot();
		}
	}
	return NULL;
}