Page 1 of 1
Screensaver Preview
Posted: Sat Dec 27, 2003 6:06 am
by eddy
Code updated For 5.20+
Whenever possible, I use PB command instead of API (threre are only two API commands)
What do you think about it.
(code updated scroll down)
Code: Select all
;-------------------
;-Preview Destructor
;-------------------
Procedure DestroyPreview(hnd)
Repeat
Delay(200)
Until IsWindow_(hnd)=0
End
EndProcedure
;-------------------
;-Preview
;-------------------
Procedure Preview(previewWindow)
; ------------------------
; wait end of preview
; ------------------------
ThreadPriority(CreateThread(@DestroyPreview(),previewWindow),4)
Repeat
WaitWindowEvent()
ForEver
EndProcedure
Posted: Sat Dec 27, 2003 12:57 pm
by Seldon
I think it's the best "trick" for this kind of stuff, thank you for sharing!
Posted: Sat Dec 27, 2003 3:38 pm
by Kale
Remember that parsing the command line arg should be done a little more thoroughly, this is taken from a screensaver guide i used when writing screensavers:
When parsing command-line options, note that the letters may appear as lower-case or upper-case, and that there might be either a forward slash or a hyphen prefixing the letter, and that there may be either a space or a colon after the letter. Thus, you should respond to /p #### and -P:#### and all options in between.
I always use WinAPI for displaying stuff in the preview window, i don't think it can be done purely with native commands

anyway here is how i do it (scroll to the bottom):
viewtopic.php?t=6010
Posted: Sun Dec 28, 2003 5:45 am
by eddy
@Kale
/p #### or -P:####
Thanks for your information about commandline.
@Seldom
Ok I've updated my code.
Did you test it ?
I hope that it works for you

Posted: Sun Dec 28, 2003 11:14 am
by Seldon
I just tested (1st version) and it works well under Win98SE (I have here). I said it's the best because you add a gadget not a child window that needs to have a certain class name, etc.. Maybe the way suggested by Kale is the standard, but your method is simple and it works (if you only need a static image in the preview).
Posted: Sun Dec 28, 2003 8:44 pm
by eddy
@Kale
Hmm it's true. We can't code a screensaver preview without WinAPI.
We always need a child window to receive some CLOSE messages.
Code: Select all
#WM_CLOSE_OLD_PREVIEW = 2000
#PREVIEW_TITLE = "My Saver Preview"
;-------------------
;-Preview Destructor
;-------------------
Procedure PreviewDestructor(window, message, wParam, lParam)
Result = #PB_ProcessPureBasicEvents
Select message
Case #WM_CLOSE
DestroyWindow_(window)
End
Case #WM_CLOSE_OLD_PREVIEW
GlobalString.l = wParam
GlobalString$ = Space(1204)
GlobalGetAtomName_(GlobalString,GlobalString$,1024)
If GlobalString$=#PREVIEW_TITLE
GlobalDeleteAtom_(GlobalString)
End
EndIf
EndSelect
ProcedureReturn Result
EndProcedure
;-------------------
;-Preview
;-------------------
Procedure Preview(preview)
; ------------------------
; preview image
; ------------------------
UseGadgetList(preview)
GetClientRect_(preview,@rc.rect)
CreateImage(1,rc\right,rc\bottom)
StartDrawing(ImageOutput())
For y=0 To ImageHeight()
Line(0,y,ImageWidth(),1,RGB($FF*y/ImageHeight(),$CC*y/ImageHeight(),0))
Next
StopDrawing()
ImageGadget(1,0,0,0,0,ImageID())
CloseGadgetList()
; ------------------------
; close all old previews
; ------------------------
Sendmessage_(#HWND_BROADCAST,#WM_CLOSE_OLD_PREVIEW,GlobalAddAtom_(#PREVIEW_TITLE),0)
; ------------------------
; wait end of preview (using fake window)
; ------------------------
OpenWindow(0,0,0,0,0,#PB_WINDOW_INVISIBLE,#PREVIEW_TITLE)
SetParent_(WindowID(),preview)
SetWindowCallback(@PreviewDestructor())
Repeat
WaitWindowEvent()
ForEver
EndProcedure
;-------------------
;-Main Program
;-------------------
FirstParam.s =ProgramParameter()
command.s =LCase(Left(ReplaceString(FirstParam,"-","/"),2))
ParentWindow.l =Val(StringField(FirstParam,2,":")) | Val(ProgramParameter())
Select command
Case "/p"
Preview(ParentWindow)
Case "/c"
;Config(ParentWindow)
Default
;Saver()
EndSelect
Posted: Sun Dec 28, 2003 9:23 pm
by Kale
woah! that code is way to complicated, hidden windows??? This bit worries me:
Code: Select all
; ------------------------
; close all old previews
; ------------------------
Sendmessage_(#HWND_BROADCAST,#WM_CLOSE_OLD_PREVIEW,GlobalAddAtom_(#PREVIEW_TITLE),0)
close all old previews? no more than one instance of a config, preview or saver should ever start. use this to only start one instance to begin with:
Code: Select all
...
ScreensaverName = "PureBasic ScreenSaver v1.0"
...
;start only one screensaver
Procedure OnlyOneSCRStart(SaverName.s)
*MutexName = @SaverName
Shared OnlyOneStartMutex.l
OnlyOneStartMutex = CreateMutex_(0, 1, *MutexName)
OnlyOneStartError.l = GetLastError_()
If OnlyOneStartMutex <> 0 And OnlyOneStartError = 0
ProcedureReturn 1
Else
CloseHandle_(OnlyOneStartMutex)
End
EndIf
EndProcedure
;close the screensaver
Procedure OnlyOneSCRStop()
CloseHandle_(OnlyOneStartMutex)
EndProcedure
...
;start only one instance of the program!
OnlyOneSCRStart(ScreensaverName)
;deal with the Parameters passed to this program
Select Parameter
Case "" ;double clicked
ExecuteConfiguration()
Case "A" ;check password
End
Case "C" ;'Settings' button clicked in the screensaver dialog
ExecuteConfiguration()
Case "P" ;when the preview is requested in the screensaver dialog by selecting this screensaver
ExecutePreview()
Case "S" ;launch the main screensaver after an interval or by pressing 'Preview' in the dialog
ExecuteScreenSaver()
EndSelect
;stop monitoring to see if one instance is running
OnlyOneSCRStop()
End
Posted: Sun Dec 28, 2003 9:29 pm
by freak
just one thing for eddy:
you can't just send a userdefined message to #HWND_BROADCAST!
Some other application might interpret it as one of it's own messages , and
act very strangely because of it.
You have to use RegisterWindowMessage_() to get a message ID, that is
unique throughout the system.
Timo
Posted: Mon Dec 29, 2003 9:03 am
by eddy
you can't just send a userdefined message to #HWND_BROADCAST!
8O 8O Oups!!
Third version should be better
Thanks Freak
Code: Select all
;-------------------
;-Preview Destructor
;-------------------
Procedure PreviewAutoDestruction(window, message, wParam, lParam)
Shared WM_DestroyPreview
Result = #PB_ProcessPureBasicEvents
Select message
Case #WM_CLOSE
DestroyWindow_(window)
End
Case WM_DestroyPreview
End
EndSelect
ProcedureReturn Result
EndProcedure
;-------------------
;-Preview
;-------------------
Procedure Preview(preview)
; ------------------------
; preview image
; ------------------------
UseGadgetList(preview)
GetClientRect_(preview,@rc.rect)
CreateImage(1,rc\right,rc\bottom)
StartDrawing(ImageOutput())
For y=0 To ImageHeight()
Line(0,y,ImageWidth(),1,RGB($FF*y/ImageHeight(),$CC*y/ImageHeight(),0))
Next
StopDrawing()
ImageGadget(1,0,0,0,0,ImageID())
CloseGadgetList()
; ------------------------
; close previous previews
; ------------------------
Shared WM_DestroyPreview
WM_DestroyPreview=RegisterWindowMessage_(@"PREVIEW AUTO DESTRUCTION")
Sendmessage_(#HWND_BROADCAST,WM_DestroyPreview,0,0)
; ------------------------
; the empty child window will receive all messages
; wait end of preview...
; ------------------------
SetParent_(OpenWindow(0,0,0,0,0,#PB_WINDOW_INVISIBLE,"CHILD WINDOW"),preview)
SetWindowCallback(@PreviewAutoDestruction())
Repeat
WaitWindowEvent()
ForEver
EndProcedure
;-------------------
;-Main Program
;-------------------
FirstParam.s =ProgramParameter()
command.s =LCase(Left(ReplaceString(FirstParam,"-","/"),2))
ParentWindow.l =Val(StringField(FirstParam,2,":")) | Val(ProgramParameter())
Select command
Case "/p"
Preview(ParentWindow)
Case "/c"
;Config(ParentWindow)
Default
;Saver()
EndSelect