Creating MAX Screensaver

BlitzMax Forums/BlitzMax Programming/Creating MAX Screensaver

Uncle Ho(Posted 2006) [#1]
I am trying to build a screensaver in Max. I mean a real screensaver with a config-dialog and a preview-window also. so only changing the .exe to .scr will not be sufficient ;)

i found this code which seems to have all features i need:

http://www.blitzmax.com/Community/posts.php?topic=48729#542024

But it is rather old as it still uses FlushMem.
I finally got it to compile under Max 1.20 when i:
1. changed FlushMem to GCCollect
2. put some fake arguments in the commandline (because AppArgs[2] gives me an error otherwise)

Now it shows the config dialog and the preview allright.

But it does not start the screensaver. also clicking "Preview" in the windows-screensaver-dialog runs the saver silently, gathering only lots of memory in the taskmanager.

I also tried the example beneath the topic and this one works ok. I do not have the code but i guess it was compiled with an old MAX version also.

Can someone help me converting this code to work with the latest version MAX (v. 1.20) ?


ImaginaryHuman(Posted 2006) [#2]
I wish there were code to make screensavers easily on all platforms.


Uncle Ho(Posted 2006) [#3]
Just sorted it out :D

Can a few of you check out if this works on your systems too?

it was only a bug with the AppArgs[] array:

'******************** Open Source Screensaver Program ************************
'
' Version 1.1 June 27, 2006
'
' Known issues: None at this time
'
' Contributors: netmaestro, eikon, chris c, Uncle Ho
'
'
' Use: Compile with "GUI App" CHECKED
' Rename .exe to .scr
' move .scr to c:\windows\system32 (or...)
'
'*****************************************************************************

Framework BRL.GLMax2D
Import BRL.Basic
Import BRL.System
Import BRL.Retro
Import "-lshell32"
Import "-luser32"
Import "-lkernel32"

Extern "win32"
	Function FindWindow (x:Byte Ptr, y:Byte Ptr) = "FindWindowA@8"
	Function MoveWindow (hWnd,x,y,w,h,d) = "MoveWindow@24"
	Function ShowWindow (hWnd,style) = "ShowWindow@8"
	Function GetWindowLong (hwnd, nIndex) = "GetWindowLongA@8"
	Function SetWindowLong (hWnd,x,y) = "SetWindowLongW@12"
	Function SetParent (hWnd1,hWnd2) = "SetParent@8"
	Function IsWindowVisible (hWnd) = "IsWindowVisible@4"
	Function GetDesktopWindow () = "GetDesktopWindow@0"
	Function GetWindowRect (hWnd:Int,r:Byte Ptr) = "GetWindowRect@8"
	Function CreateSemaphore (a:Byte Ptr, b:Int, c:Int, d:String) = "CreateSemaphoreW@16"
	Function GetLastError () = "GetLastError@0"
EndExtern

'**************** Get Current Desktop Resolution *******************
Global r:Int[4] 
Global p:Byte Ptr = VarPtr( r[0] ) 

' This is advisable because it is best not to switch screen
deskWnd = GetDesktopWindow( ) 		' settings when the screen saver starts.
GetWindowRect( deskWnd ,p )

Global DeskWidth :Float =r[2]
Global DeskHeight:Float =r[3] 
'**************** End Get Current Desktop Resolution ***************

Global Width: Float = 0
Global Height:Float = 0
Global startmousex:Int = 0
Global startmousey:Int = 0

Const ERROR_ALREADY_EXISTS:Int = 183
Const PREVIEW_ACTIVE:Int = 0
Const CONFIG_ACTIVE:Int = 1
Const SAVER_ACTIVE:Int = 2

Global PrevWnd:Int
If AppArgs.length = 3  
	PrevWnd:Int = Int( AppArgs[2] ) 	'Handle of the preview window
EndIf
Global pscale:Float = 1 				'scale value to apply depending on screen size
Global bmw:Int = 0 						'Handle of the BMax window
Global Status:Int = 0 					'Program status, identifies preview, regular, or config modes
Global timemark:Int = 0 				'Time marker to use for a makeshift timer

SetGraphicsDriver GLMax2DDriver( )

If AppArgs.length > 1 
	Select AppArgs[1]
		Case "/p"
			InitPreviewMode( )
		Case "/s"
			InitSaverMode( )
		Case "/c"
			InitConfigMode( )
		Default
			InitConfigMode( )
	End Select  
Else
	InitConfigMode( )
EndIf 


While not KeyHit( KEY_ESCAPE )

	'**************** TODO: Write your own presentation code ***************
	'
	' Multiply any scaling by pscale (=1 in Saver mode, .15-.25 in Preview)
	' You will scale your speeds too (nothing moving in this one)
	'
	'***********************************************************************
	Cls
	SetColor 255,255,255
	DrawOval 0,0,200,200
	SetColor 255,0,0
	DrawOval Width-(200*pscale),0,200,200
	SetColor 0,255,0
	DrawOval 0,Height-(200*pscale),200,200
	SetColor 0,0,255
	DrawOval Width-(200*pscale),Height-(200*pscale),200,200
	Flip 
	GCCollect
	
	'******* This block is boilerplate ********
	Select Status 
		Case PREVIEW_ACTIVE
			CheckVisible( )
		Case SAVER_ACTIVE
			CheckMovement( )
	End Select 
	'************* Do Not Remove **************

Wend

End

Function InitSaverMode()
	If SetProcessLock( "SaverModeLock" ) <> 0 Then End
	Status = SAVER_ACTIVE
	Width = DeskWidth
	Height = DeskHeight
	Graphics Width, Height, -1, -1
	pscale = 1
	startmousex = MouseX( )
	startmousey = MouseY( )
	Return
EndFunction

Function InitPreviewMode( )
	If SetProcessLock( "PreviewModeLock" ) <> 0 Then End
	Status = PREVIEW_ACTIVE
	Width = 152
	Height = 112
	Graphics Width, Height, 0, -1
	bmw = FindWindow( Null, "BlitzMax Application" )
	Local bmx_Style = GetWindowLong( bmw, -16 )
	bmx_Style = bmx_Style and $40000000 or $800000 and $10000000
	SetWindowLong bmw, -16, bmx_Style;
	SetParent( bmw,PrevWnd )
	MoveWindow ( bmw, 0, 0, 152, 112, True )
	pscale = 152/DeskWidth
	SetScale pscale, pscale
	timemark = MilliSecs()
	Return
EndFunction

Function InitConfigMode( )
	Status = CONFIG_ACTIVE
	Width = 320
	Height = 200
	AppTitle = "Configuration Screen"
	Graphics Width,Height, 0
	bmw = FindWindow( Null, "Configuration Screen" )
	MoveWindow ( bmw, ( DeskWidth/2-Width/2 ),( DeskHeight/2-Height/2 ), 320, 200, True )
	SetClsColor 192, 192, 192
	SetColor 0, 0, 0
	Cls
	DrawText "TODO: Write config code", 50, 80
	DrawText "Press <ANY KEY> to exit", 55, 130
	Flip
	WaitKey
	End
EndFunction

Function SetProcessLock:Int( LockStr:String )
	Global MySem = CreateSemaphore( Null, 0, 1, LockStr )
	If MySem <> 0 and GetLastError( ) = ERROR_ALREADY_EXISTS
		Return 1
	Else
		Return 0
	EndIf
EndFunction

Function CheckVisible( )
	If MilliSecs()-timemark > 2000 'Delay visibility check til window is drawn
		If not IsWindowVisible( PrevWnd )
			End
		EndIf
	EndIf
EndFunction

Function CheckMovement( )
	If MouseX( ) <> startmousex or MouseY( ) <> startmousey Then End
	If GetChar( ) <> 0 Then End
	'Probably want to put some more keyhits in here; I'm too lazy
EndFunction



H&K(Posted 2006) [#4]
If you run this for a long time does it crash? ie If you leave the computer in screen saver all night rather than closedown, will it still be running tomorrow

And two, does it hang when the computer turns on/off the monitor.

And Three, does it still appear on the task bar as a running application, after it has stopped running?


klepto2(Posted 2006) [#5]
As it is the same Framework I have used by my screensaver in BMax it should work :) .

For more details:
DOWNLOAD
SOME SCREENIES

@H&K: For me my screenie was running 5 days without interruption, with monitor turning on and off.
And it is invisible in the taskbar, but sometimes the preview mode will hang in the Taskmanager, to handle this I have simply added a delay to the mainloop of the preview code, so it will work.


ImaginaryHuman(Posted 2006) [#6]
Now we just need Mac and Linux version ;-D


Who was John Galt?(Posted 2007) [#7]
Digging up this old thread because I have a problem using the code. I can't seem to load an image in the screensaver. I know the files exist but the images all return null. This all worked before I converted to a screen saver.

Anyone know what the problem could be?


grable(Posted 2007) [#8]
It could be the Framework command, making it not import any Image loaders.

Try removing it, or adding the image loader imports manually.


Who was John Galt?(Posted 2007) [#9]
Well done Grable. You cracked it. This has held me up for ages. I don't understand why it didn't moan at compile time though.


Who was John Galt?(Posted 2007) [#10]
Well nearly there now.

I can see the screensaver fine in the small preview panel, but when I hit preview or set the screensaver to run, I don't see anything and my CPU usage shoots up.


Who was John Galt?(Posted 2007) [#11]
Can someone try the posted code with the latest Blitz? It shows previews here but nothing else.


grable(Posted 2008) [#12]
Heres a copy working in 1.26, just some minor fixes.



DREAM(Posted 2008) [#13]
is there a reason, or is it just on my machine that the preview whilst in the screen save tab on desktop preferences....it is very flickery is it actually running too fast and needs to be slown down, is it skipping and not waiting for the vertical blank......I modified it because between the two versions on this page neither worked coreectly but this hacked version seems to.....any ideas...
'******************** Open Source Screensaver Program ************************
'
' Version 1.1 June 27, 2006
'
' Known issues: None at this time
'
' Contributors: netmaestro, eikon, chris c, Uncle Ho
'
'
' Use: Compile with "GUI App" CHECKED
' Rename .exe to .scr
' move .scr to c:\windows\system32 (or...)
'
'*****************************************************************************

Framework BRL.GLMax2D
Import BRL.Basic
Import BRL.System
Import brl.Retro
Import pub.Win32
Import "-lshell32"
Import "-luser32"
Import "-lkernel32"

Extern "win32"
	Function FindWindow (x:Byte Ptr, y:Byte Ptr) = "FindWindowA@8"
	Function MoveWindow (hWnd,x,y,w,h,d) = "MoveWindow@24"
	Function ShowWindow (hWnd,style) = "ShowWindow@8"
	Function GetWindowLong (hwnd, nIndex) = "GetWindowLongA@8"
	Function SetWindowLong (hWnd,x,y) = "SetWindowLongW@12"
	Function SetParent (hWnd1,hWnd2) = "SetParent@8"
	Function IsWindowVisible (hWnd) = "IsWindowVisible@4"
	Function GetDesktopWindow () = "GetDesktopWindow@0"
	Function GetWindowRect (hWnd:Int,r:Byte Ptr) = "GetWindowRect@8"
	Function CreateSemaphore (a:Byte Ptr, b:Int, c:Int, d:String) = "CreateSemaphoreW@16"
	Function GetLastError () = "GetLastError@0"
EndExtern

'**************** Get Current Desktop Resolution *******************
Global r:Int[4] 
Global p:Byte Ptr = VarPtr( r[0] ) 

' This is advisable because it is best not to switch screen
deskWnd = GetDesktopWindow( ) 		' settings when the screen saver starts.
GetWindowRect(deskWnd, p) 

Global DeskWidth :Float =r[2]
Global DeskHeight:Float =r[3] 
'**************** End Get Current Desktop Resolution ***************

Global Width: Float = 0
Global Height:Float = 0
Global startmousex:Int = 0
Global startmousey:Int = 0

Const ERROR_ALREADY_EXISTS:Int = 183
Const PREVIEW_ACTIVE:Int = 0
Const CONFIG_ACTIVE:Int = 1
Const SAVER_ACTIVE:Int = 2

Global PrevWnd:Int
If AppArgs.length = 3  
	PrevWnd:Int = Int( AppArgs[2] ) 	'Handle of the preview window
EndIf
Global pscale:Float = 1 				'scale value to apply depending on screen size
Global bmw:Int = 0 						'Handle of the BMax window
Global Status:Int = 0 					'Program status, identifies preview, regular, or config modes
Global timemark:Int = 0 				'Time marker to use for a makeshift timer

SetGraphicsDriver GLMax2DDriver( )

If AppArgs.length > 1 
	Select AppArgs[1]
		Case "/p"
			InitPreviewMode( )
		Case "/s"
			InitSaverMode( )
		Case "/c"
			InitConfigMode( )
		Default
			InitConfigMode( )
	End Select  
Else
	InitConfigMode( )
EndIf 


While not KeyHit( KEY_ESCAPE )

	'**************** TODO: Write your own presentation code ***************
	'
	' Multiply any scaling by pscale (=1 in Saver mode, .15-.25 in Preview)
	' You will scale your speeds too (nothing moving in this one)
	'
	'***********************************************************************
	Cls
	SetColor 255,255,255
	DrawOval Rnd(1024), Rand(768), 200, 200
	SetColor 255, 0, 0
	DrawOval Rnd(1024), Rand(768), 200, 200
	SetColor 0,255,0
	DrawOval Rnd(1024), Rand(768), 200, 200
	SetColor 0,0,255
	DrawOval Rnd(1024), Rand(768), 200, 200
	Flip
	GCCollect
	
	'******* This block is boilerplate ********
	Select Status 
		Case PREVIEW_ACTIVE
			CheckVisible( )
		Case SAVER_ACTIVE
			CheckMovement( )
	End Select 
	'************* Do Not Remove **************

Wend

End

Function InitSaverMode()
	If SetProcessLock( "SaverModeLock" ) <> 0 Then End
	Status = SAVER_ACTIVE
	Width = DeskWidth
	Height = DeskHeight
	Graphics Width, Height, 32'-1, -1
	SetWindowPos(FindWindow(Null, "BlitzMax Application"), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE) 
	pscale = 1
	startmousex = MouseX( )
	startmousey = MouseY() 
	FlushMouse
	FlushKeys
	Return
EndFunction

Function InitPreviewMode( )
	If SetProcessLock("PreviewModeLock") <> 0 Then End
	Status = PREVIEW_ACTIVE
	Width = 152
	Height = 112
	Graphics Width, Height, 0, -1
	bmw = FindWindow( Null, "BlitzMax Application" )
	Local bmx_Style = GetWindowLong( bmw, -16 )
	bmx_Style = bmx_Style and $40000000 or $800000 and $10000000
	SetWindowLong bmw, -16, bmx_Style;
	SetParent( bmw,PrevWnd )
	MoveWindow ( bmw, 0, 0, 152, 112, True )
	pscale = 152/DeskWidth
	SetScale pscale, pscale
	timemark = MilliSecs()
	Return
EndFunction

Function InitConfigMode( )
	Status = CONFIG_ACTIVE
	Width = 320
	Height = 200
	AppTitle = "Configuration Screen"
	Graphics Width,Height, 0
	bmw = FindWindow( Null, "Configuration Screen" )
	MoveWindow ( bmw, ( DeskWidth/2-Width/2 ),( DeskHeight/2-Height/2 ), 320, 200, True )
	SetClsColor 192, 192, 192
	SetColor 0, 0, 0
	Cls
	DrawText "TODO: Write config code", 50, 80
	DrawText "Press <ANY KEY> to exit", 55, 130
	Flip
	WaitKey
	End
EndFunction

Function SetProcessLock:Int( LockStr:String )
	Global MySem = CreateSemaphore( Null, 0, 1, LockStr )
	If MySem <> 0 and GetLastError( ) = ERROR_ALREADY_EXISTS
		Return 1
	Else
		Return 0
	EndIf
EndFunction

Function CheckVisible( )
	If MilliSecs()-timemark > 2000 'Delay visibility check til window is drawn
		If not IsWindowVisible( PrevWnd )
			End
		EndIf
	EndIf
EndFunction

Function CheckMovement( )
	If MouseX( ) <> startmousex or MouseY( ) <> startmousey Then End
	If GetChar( ) <> 0 Then End
	'Probably want to put some more keyhits in here; I'm too lazy
EndFunction




oh and how do you do them scrolling boxes in this forum.....


grable(Posted 2008) [#14]
oh and how do you do them scrolling boxes in this forum.....

use "codebox" instead of "code" ;)


MGE(Posted 2008) [#15]
Anyone create a screensaver using this code? I'd like to download it and have a peek on my various test boxes. Thanks!


DREAM(Posted 2008) [#16]
http://www.filecrunch.com/fileDownload.php?sub=bca2128a6c04db37f0e2c272d9547850&fileId=138279

try this


MGE(Posted 2008) [#17]
Dream: "This file is a private File. So you don't have rights to download this file."

Available any place else?


DREAM(Posted 2008) [#18]
http://www.filecrunch.com/fileDownload.php?sub=bca2128a6c04db37f0e2c272d9547850&fileId=138279

sorry only just started using that site didnt realise they were private automatically try that again


MGE(Posted 2008) [#19]
Thanks Dream, I've downloaded the compiled app and I've been playing with the source. I can verify that vsync is not working in preview mode and possibly the entire internal timing seems to get thrown off inside a cls/flip loop while in preview mode. Other than that, it does seem to work, this could be interesting. The most obvious solution is simply not run anything animated in preview mode, just show a static image or something. Alot of screensavers do that anyway. In any event, this deserves alot more of my attention and it may find it's way into my development shell. Thanks! ;)


DREAM(Posted 2008) [#20]
me too found the same thing in the end i added a timing delay, but the trick is working out how fast that little window is running at seems at lest triple if not 4 times as fast, now depending on system specs its going to fly on some bigger machines.....might have to build an fps counter for it in both preview and real and compare them.

at the moment i have added a timing routine from the archives

http://www.blitzbasic.com/codearcs/codearcs.php?code=2152

thanks to Leadwerks, but it isnt very effective in the preview window seems to be based on the whole windows system rather than that little window so may need to alter it...

this is the main code now


this is the timing code from leadwerks i called it "Timimingmodule.bmx" and is an include



this is the link to the working version i have

http://www.filecrunch.com/fileDownload.php?sub=2918da1da91be977f0e05a006fff0250&fileId=138534

i just realised i forgoto to take out some of the modules for png and jpeg loading so the file is bloated...doh...works though..


MGE(Posted 2008) [#21]
I'm just going to go with a static image in preview mode and just use the windows api call sleep() to give resources back to the system during that loop. Seriously, I don't think it's too much of a show stopper to not have a real time preview. Thanks for the info, comments on this. I've been looking for some stable windows screensaver code for a while, still need to run some tests on Vista to how this is going to work. ;)