Page 1 of 1

Screensaver Hell! Help! [Long Post]

Posted: Tue Apr 29, 2003 9:55 pm
by Kale
Im having trouble with this piece of code. Its basically a screen saver template, which i am trying to make as generic as possible for later re-use. The problem i have is that i can't seen to get the preview working as it should.

As you (may or may not) know screensavers just pass different command line parameters to the .exe to do different things '/s' for screensaver, '/c' for config and also '/p' for preview. Along with the '/p' there is also the handle to the preview window passed like this '/p:2165', i have no trouble parsing this and getting the handle, BUT when i try to display anything in this window i run into problems, i think its my inexperience with child windows. This is my code:

Code: Select all

;===========================================================================
;-GLOBAL FLAGS / VARIABLES / STRUCTURES / ARRAYS
;===========================================================================

Global screenWidth.l
Global screenHeight.l
Global previewFlag.l
Global parameter.s
Global prevWinHndlString.s
Global prevWinHndl.l
Global prevThreadID.l

screensaverName.s = "PureBasic ScreenSaver"
screenWidth.l = GetSystemMetrics_(#SM_CXSCREEN)
screenHeight.l = GetSystemMetrics_(#SM_CYSCREEN)

parameter = UCase(ProgramParameter())
If Len(parameter) > 2
    prevWinHndlString = RemoveString(parameter, Left(parameter, 3), 1)
    parameter = RemoveString(parameter, Left(parameter, 1), 1)
    parameter = Left(parameter, 1)
Else
    parameter = RemoveString(parameter, Left(parameter, 1), 1)
    prevWinHndlString = ProgramParameter()
    If FindString(prevWinHndlString, "-", 0) <> 0 : prevWinHndlString = RemoveString(prevWinHndlString, "-", 1) : EndIf
    If FindString(prevWinHndlString, "/", 0) <> 0 : prevWinHndlString = RemoveString(prevWinHndlString, "/", 1) : EndIf
EndIf
prevWinHndl = Val(prevWinHndlString)

;===========================================================================
;-PROCEDURES
;===========================================================================

;simple error checking
Procedure HandleError(result, text.s)
    If result = 0 : MessageRequester("Error", text, #PB_MessageRequester_Ok) : End : EndIf
EndProcedure

;start only one screensaver
Procedure OnlyOneSCRStart(screensaverName.s)
    *MutexName = @screensaverName
    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

;execute the preview in the little mini monitor in 'Display Properties'
Procedure ExecutePreview()
    previewWindowSize.RECT
    GetClientRect_(prevWinHndl, @previewWindowSize)

    CatchImage(1, ?PreviewImage)
    HandleError(CreateGadgetList(prevWinHndl), "Gadget list in preview panel could not be created!")
    ImageGadget(1, 0, 0, previewWindowSize\right, previewWindowSize\bottom, UseImage(1))
    
    Repeat
        EventID.l = WaitWindowEvent()
    Until EventID = #PB_EventCloseWindow

EndProcedure

;run the fullscreen screensaver code
Procedure ExecuteScreenSaver()
    Shared screensaverName
    SystemParametersInfo_(#SPI_SCREENSAVERRUNNING, 1, @oldval, 0)
    ShowCursor_(0)
    
    HandleError(OpenScreen(screenWidth, screenHeight, 32, screensaverName), "A fullscreen screen could not be opened!")

CatchSprite(0, ?PBLogo, 0)
XMax = (GetSystemMetrics_(#SM_CXSCREEN)/2)-(SpriteWidth(0)/2)
YMax = (GetSystemMetrics_(#SM_CYSCREEN)/2)-(SpriteHeight(0)/2)
    
    Repeat

ClearScreen(0,0,0)
DisplaySprite(0, XMax+x, YMax+x)
DisplaySprite(0, XMax-x, YMax-x)
DisplaySprite(0, XMax+x, YMax-x)
DisplaySprite(0, XMax-x, YMax+x)
DisplaySprite(0, XMax+x, YMax)
DisplaySprite(0, XMax-x, YMax)
DisplaySprite(0, XMax, YMax+x)
DisplaySprite(0, XMax, YMax-x)
If x < XMax And Pos = 0 : x+1 : Pos = 0 : EndIf
If x = XMax And Pos = 0 : x-1 : Pos = 1 : EndIf
If x < XMax And Pos = 1 : x-1 : Pos = 1 : EndIf
If x = 0 And Pos = 1 : x+1 : Pos = 0 : EndIf
FlipBuffers()

        Delay(1)
        ExamineKeyboard()
        ExamineMouse()
    Until KeyboardPushed(#PB_Key_All) Or MouseDeltaX() <> 0 Or MouseDeltaY() <> 0 Or MouseWheel() <> 0 Or MouseButton(1) <> 0 Or MouseButton(2) <> 0
    ShowCursor_(1)
    SystemParametersInfo_(#SPI_SCREENSAVERRUNNING, 0, @oldval, 0)
    End
EndProcedure

;===========================================================================
;-CONFIG GEOMETRY
;===========================================================================

;configuration window
Procedure Config()
    Shared screensaverName
    If OpenWindow(0, 0, 0, 320, 240, #PB_Window_SystemMenu | #PB_Window_WindowCentered, screensaverName)
        Repeat
            EventID.l = WaitWindowEvent()
        Until EventID = #PB_EventCloseWindow
    EndIf
    End
EndProcedure

;===========================================================================
;-MAIN
;===========================================================================

OnlyOneSCRStart(screensaverName)

;deal with the parameters passed to this program
Select parameter
    Case "" ;double clicked
        Config()
    Case "A" ;check password
        End
    Case "C" ;'Settings' button clicked in the screensaver dialog
        Config()
    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
        HandleError(InitSprite(), "DirectX v7.0 or above can not be found or initialised!")
        HandleError(InitKeyboard(), "DirectX v7.0 or above can not be found or initialised!")
        HandleError(InitMouse(), "DirectX v7.0 or above can not be found or initialised!")
        ExecuteScreenSaver()
EndSelect

OnlyOneSCRStop()
End

;===========================================================================
;-BINARY INCLUDES
;===========================================================================

PBLogo:
    IncludeBinary "PureBasic.bmp"
    
PreviewImage:
    IncludeBinary "preview.bmp"
now when the preview.bmp is displayed it is fine, the only problem is i can't seem to get the .exe to quit when i want to do something else, i.e. bring up the config dialog or watch the screensaver fullscreen. When i quit the display properties dialog the .exe is still running in the background. Any Ideas? this has been driving me nuts for weeks.

I have tried an API approach using this as a guide:
viewtopic.php?t=2658

but that piece of code confuses the hell out of me and its not very generic. I'm trying to write a screensaver template to use a PB screen using OpenScreen() for nice graphics and to be reuseable for lots of savers, etc... I'm nearly there i just need this .bmp in the preview window sorting. :cry:
Big thanks to anyone who can help.

Posted: Fri May 02, 2003 11:32 pm
by Kale
anybody any ideas? or examples? :cry:

Posted: Sat May 03, 2003 11:32 am
by Fred
Unfortunately not...

Posted: Sat May 03, 2003 5:04 pm
by Kale
he he, ok i'll figure it out. :)

Posted: Mon Dec 15, 2003 1:04 pm
by dontmailme
did you find out how to stop this happening ? It would be interesting to try this out.

Posted: Mon Dec 15, 2003 1:26 pm
by Kale
Yeah figured it out and learned a hell of alot since this old post :) I've been looking into the WinAPI in more depth since then. This is how i display a piccie in the small monitor window and behaving as a normal child should when the 'P' parameter has been passed to the saver.

Code: Select all

;preview window callback
Procedure PreviewCallback(hWnd, Message, wParam, lParam) 
    Select Message
        Case #WM_CLOSE
            UnregisterClass_("PreviewWindowClass", GetModuleHandle_(#NULL)) 
            Destroywindow_(hWnd)
            End 
    EndSelect
    Result = DefWindowProc_(hWnd, Message, wParam, lParam) 
    ProcedureReturn Result
EndProcedure

;execute the preview in the little mini monitor in 'Display Properties'
Procedure ExecutePreview()
    PreviewWindowSize.RECT
    GetClientRect_(PrevWinHndl, @PreviewWindowSize)
    PreviewWindowClass.WNDCLASS
    Classname.s = "PreviewWindowClass"
    PreviewWindowClass\style = #CS_HREDRAW | #CS_VREDRAW
    PreviewWindowClass\lpfnWndProc = @PreviewCallback()
    PreviewWindowClass\cbClsExtra = 0
    PreviewWindowClass\cbWndExtra = 0
    PreviewWindowClass\hInstance = GetModuleHandle_(#NULL)
    PreviewWindowClass\hIcon = 0
    PreviewWindowClass\hCursor = 0
    PreviewWindowClass\hbrBackground = 0
    PreviewWindowClass\lpszMenuName = 0
    PreviewWindowClass\lpszClassName = @Classname
    RegisterClass_(PreviewWindowClass)
    hWnd.l = CreateWindowEx_(0, "PreviewWindowClass", "", #WS_CHILD | #WS_VISIBLE, 0, 0, PreviewWindowSize\right, PreviewWindowSize\bottom, PrevWinHndl, 0, GetModuleHandle_(#NULL), 0) 
    If hWnd
        CatchImage(1, ?PreviewImage)
        HandleError(CreateGadgetList(hWnd), "Gadget list in preview window could not be created!")
        ImageGadget(1, 0, 0, PreviewWindowSize\right, PreviewWindowSize\bottom, UseImage(1))
        While Getmessage_(Message.MSG, 0, 0, 0)
            TranslateMessage_(Message)
            DispatchMessage_(Message)
        Wend
    EndIf
EndProcedure

screensaver preview code is perfect!

Posted: Wed Jul 06, 2005 5:50 am
by netmaestro
Thanks for this, it's just the ticket and works perfectly.

Posted: Wed Jul 06, 2005 8:41 am
by Kale
Heres the downloadable source of the above (working) screensaver.

http://www.garyw.uklinux.net/pb/Screens ... Source.zip

Posted: Fri Jul 15, 2005 7:05 pm
by netmaestro
One thing I discovered you need to make your saver act like the pros is a GetFocus_() check in your status routine. If something else has focus, die. Otherwise, you could get up in the morning and find something's started in the night and your screensaver's running on the taskbar. No place for a professional saver at all.

Posted: Sat Jul 16, 2005 1:43 am
by Kale
Handy Tip! :)