Transparent clock with source
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Please Trond, allow me to improve the source replacing the main code by my multimedia timer stuff, and improving 1 or 2 more things for CPU use saving:
Code: Select all
Declare UpdateClock(id.l,msg.l,dwUser.l,dw1.l,dw2.l)
;***** Windows Multimedia Timer *****
;***** by Psychophanta April 2006 *****
;***************************************
Global m_hWnd.l,m_timerId.l,m_timerRes.l
Procedure.l min(a.l,b.l)
If a<0
If b>0 Or a>b:ProcedureReturn b:EndIf
ElseIf b>0 And a>b:ProcedureReturn b
EndIf
ProcedureReturn a
EndProcedure
Procedure.l max(a.l,b.l)
If a<0
If b>0 Or a>b:ProcedureReturn a:EndIf
ElseIf b>0 And a>b:ProcedureReturn a
EndIf
ProcedureReturn b
EndProcedure
;/////////////////////////////////////////////////////////////////////////////////////////////
;// start mmTimer
;/////////////////////////////////////////////////////////////////////////////////////////////
Procedure.b StartTimer(period.l,oneShot.b=0,resolution.l=0)
tc.TIMECAPS
If timeGetDevCaps_(@tc,SizeOf(TIMECAPS))=#TIMERR_NOERROR
m_timerRes.l=min(max(tc\wPeriodMin,resolution),tc\wPeriodMax)
timeBeginPeriod_(m_timerRes);
Else
ProcedureReturn 0
EndIf
If oneShot:oneShot=#TIME_ONESHOT:Else:oneShot=#TIME_PERIODIC:EndIf
result.l=timeSetEvent_(period,m_timerRes,@UpdateClock(),0,oneShot);CALLBACK_EVENT_SET
If result.l
m_timerId=result.l
ProcedureReturn 1
EndIf
ProcedureReturn 0
EndProcedure
;/////////////////////////////////////////////////////////////////////////////////////////////
;// stop mmTimer
;// could be modified in XP with TIME_KILL_SYNCHRONOUS
;/////////////////////////////////////////////////////////////////////////////////////////////
Procedure.b StopTimer(bEndTime.b=0)
result.l=timeKillEvent_(m_timerId)
If result.l=#TIMERR_NOERROR
m_timerId=0
If bEndTime
For i.b=0 To 9
Sleep_(10); //TIME_KILL_SYNCHRONOUS
Next
EndIf
EndIf
If m_timerRes
timeEndPeriod_(m_timerRes)
m_timerRes=0
EndIf
If result.l=#TIMERR_NOERROR:ProcedureReturn 1:EndIf
ProcedureReturn 0
EndProcedure
;/////////////////////////////////////////////////////////////////////////////////////////////
;// Resume mmTimer
;/////////////////////////////////////////////////////////////////////////////////////////////
Procedure.b SafeStartTimer(period.l=2,oneShot.b=0,resolution.l=0)
If StartTimer(period,oneShot,resolution)=0
; PostMessage_(m_hWnd,#WM_CLOSE,0,0)
ProcedureReturn 0
EndIf
ProcedureReturn 1
EndProcedure
;END OF:
;***** Windows Multimedia Timer *****
;***** by Psychophanta April 2006 *****
;***************************************
#APPNAME = "CoolClock"
UseTIFFImageDecoder()
UsePNGImageDecoder()
Enumeration
#ImgCanvas
#ImgBack
#ImgBorder
#ImgGloss
#ImgLongPointer
#ImgMediumPointer
#ImgSmallPointer
EndEnumeration
Global Alpha = 255
OpenWindow(1, 0, 0, 0, 0, #APPNAME + " Parent", #PB_Window_Invisible)
OpenWindow(0, 0, 0, 512, 384, #APPNAME, #PB_Window_Invisible, WindowID(1))
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, GetWindowLong_(WindowID(0), #GWL_EXSTYLE) | #WS_EX_LAYERED)
CreatePopupMenu(0)
MenuItem(0, "Stick to &desktop")
MenuItem(1, "Always on &top")
MenuItem(2, "&Normal")
MenuItem(6, "Get UTC (Universal Time Coordinated)")
MenuBar()
MenuItem(3, "&Change translucency")
MenuBar()
MenuItem(4, "&Exit")
MenuItem(5, "&About")
Procedure.l CheckinetConnection()
State.l
InternetGetConnectedState_(@State,0)
ProcedureReturn State
EndProcedure
If CheckinetConnection()=0:DisableMenuItem(0,6,1):EndIf
;
CatchImage(#ImgGloss, ?ClockGloss)
CatchImage(#ImgBack, ?ClockBack)
CatchImage(#ImgBorder, ?ClockBorder)
StartDrawing(ImageOutput(#ImgBack))
DrawAlphaImage(ImageID(#ImgGloss), 0, 0)
DrawAlphaImage(ImageID(#ImgBorder), 0, 0)
StopDrawing()
CatchImage(#ImgLongPointer, ?ClockLongPointer)
CatchImage(#ImgMediumPointer, ?ClockMediumPointer)
CatchImage(#ImgSmallPointer, ?ClockSmallPointer)
Procedure RotateDC(hDC.l, x0.l, y0.l, Degrees.d)
Static XFORM.XFORM
Protected Radians.d = Degrees*(#PI/180)
With XFORM
\eM11 = Cos(Radians)
\eM12 = Sin(Radians)
\eM21 = -\eM12
\eM22 = \eM11
\ex = x0 - Cos(Radians)*x0 + Sin(Radians)*y0
\ey = y0 - Cos(Radians)*y0 - Sin(Radians)*x0
EndWith
SetGraphicsMode_(hDC, #GM_ADVANCED)
SetWorldTransform_(hDC, XFORM)
EndProcedure
Procedure UpdateClock(id.l,msg.l,dwUser.l,dw1.l,dw2.l)
Date = Date()
Static hDC
Hour = Hour(Date)
Minute = Minute(Date)
Second = Second(Date)
; Fresh copy of background to draw on
CopyImage(#ImgBack, #ImgCanvas)
; Draw on the background
hDC = StartDrawing(ImageOutput(#ImgCanvas))
; Draw the large pointer
RotateDC(hDC, 128, 128, Minute*6)
DrawAlphaImage(ImageID(#ImgLongPointer),120,35)
; Draw the medium pointer
RotateDC(hDC, 128, 128, Hour*30+Minute/2)
DrawAlphaImage(ImageID(#ImgMediumPointer),120,66)
; Draw the small pointer
RotateDC(hDC, 128, 128, Second*6)
DrawAlphaImage(ImageID(#ImgSmallPointer),121,19)
; Update the window
Static ContextOffset.POINT
Static BlendMode.BLENDFUNCTION
Static BitmapInfo.BITMAP
GetObject_(ImageID(#ImgCanvas), SizeOf(BITMAP), @BitmapInfo)
BlendMode\SourceConstantAlpha = Alpha
BlendMode\AlphaFormat = 1
UpdateLayeredWindow_(WindowID(0), 0, 0, @BitmapInfo+4, hDC, @ContextOffset, 0, @BlendMode, 2)
StopDrawing()
EndProcedure
Procedure StickToDesktop()
StickyWindow(0, 0)
SetParent_(WindowID(0), GetShellWindow_())
EndProcedure
Procedure AlwaysOnTop()
SetParent_(WindowID(0), 0)
StickyWindow(0, 1)
EndProcedure
Procedure ChangeTranslucency()
OpenWindow(2,WindowX(0),WindowY(0)+WindowHeight(0),200,30,"Translucency",#PB_Window_SystemMenu,WindowID(1))
CreateGadgetList(WindowID(2))
TrackBarGadget(0,0,0,180,40,0,255):SetGadgetState(0,Alpha)
TextGadget(1,180,0,40,18,Str(GetGadgetState(0)))
EndProcedure
Procedure Normal()
SetParent_(WindowID(0), 0)
StickyWindow(0, 0)
EndProcedure
Procedure.b GetUTCTime()
Static Networkinitialized.b=0
If Networkinitialized.b=0
If InitNetwork()=0
MessageRequester("Error", "Can't initialize the network !",0):ProcedureReturn 0
Else:Networkinitialized.b=1
EndIf
EndIf
Datebuffer.s=Space(1000)
UTCServers.l=14:Dim UTC.s(UTCServers-1):port.w=13
UTC(0)="208.184.49.9"; "nist1.ny.glassey.com", "Abovenet, New York City"
UTC(1)="129.6.15.28"; "time-a.nist.gov", "NIST, Gaithersburg, Maryland"
UTC(2)="129.6.15.29"; "time-b.nist.gov", "NIST, Gaithersburg, Maryland"
UTC(3)="132.163.4.101"; "time-a.timefreq.bldrdoc.gov", "NIST, Boulder, Colorado"
UTC(4)="132.163.4.102"; "time-b.timefreq.bldrdoc.gov", "NIST, Boulder, Colorado"
UTC(5)="132.163.4.103"; "time-c.timefreq.bldrdoc.gov", "NIST, Boulder, Colorado"
UTC(6)="128.138.140.44"; "utcnist.colorado.edu", "University of Colorado, Boulder"
UTC(7)="192.43.244.18"; "time.nist.gov", "NCAR, Boulder, Colorado"
UTC(8)="131.107.1.10"; "time-nw.nist.gov", "Microsoft, Redmond, Washington"
UTC(9)="63.149.208.50"; "nist1.datum.com", "Datum, San Jose, California"
UTC(10)="216.200.93.8"; "nist1.dc.glassey.com", "Abovenet, Virginia"
UTC(11)="207.126.103.204"; "nist1.sj.glassey.com", "Abovenet, San Jose, California"
UTC(12)="207.200.81.113"; "nist1.aol-ca.truetime.com", "TrueTime, AOL facility, Sunnyvale, California"
UTC(13)="205.188.185.33"; "nist1.aol-va.truetime.com", "TrueTime, AOL facility, Virginia"
For t=0 To UTCServers-1
ConnectionID.l=OpenNetworkConnection(UTC(t),port.w)
If ConnectionID
ReceiveNetworkData(ConnectionID,@DateBuffer,1000)
date.l=ParseDate("%yy/%mm/%dd/%hh/%ii/%ss",Mid(DateBuffer,8,2)+"/"+Mid(DateBuffer,11,2)+"/"+Mid(DateBuffer,14,2)+"/"+Mid(DateBuffer,17,2)+"/"+Mid(DateBuffer,20,2)+"/"+Mid(DateBuffer,23,2))
Debug FormatDate("%yyyy/%mm/%dd/%hh/%ii/%ss",date)
systime.SYSTEMTIME
systime\wYear=Year(date)
systime\wMonth=Month(date)
systime\wDayOfWeek=DayOfWeek(date)
systime\wDay=Day(date)
systime\wHour=Hour(date)
systime\wMinute=Minute(date)
systime\wSecond=Second(date)
systime\wMilliseconds=0
SetSystemTime_(@systime)
CloseNetworkConnection(ConnectionID)
ProcedureReturn 1
ElseIf t>=UTCServers-1
MessageRequester("Error","Can't connect to UTC Server !",0):ProcedureReturn 0
EndIf
Next
EndProcedure
Procedure About()
Protected Text.s
Text+#APPNAME + #CRLF$
Text+"Copyright 2006 Trond Gundersen"+ #CRLF$
Text+"Enhanced & timered version by Albert (Psychophanta)"
MessageRequester("About", Text)
EndProcedure
UpdateClock(0,0,0,0,0)
HideWindow(0,0)
SafeStartTimer(1000)
Repeat
Select WaitWindowEvent()
Case #WM_RBUTTONUP
DisplayPopupMenu(0, WindowID(1))
Case #WM_LBUTTONDOWN
SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
Case #PB_Event_Menu
Select EventMenu()
Case 0
StickToDesktop()
Case 1
AlwaysOnTop()
Case 2
Normal()
Case 6
GetUTCTime()
Case 3
ChangeTranslucency()
Case 4
Break
Case 5
About()
EndSelect
Case #PB_Event_Gadget
If IsWindow(2)
Alpha=GetGadgetState(0)
SetGadgetText(1,Str(Alpha))
EndIf
Case #PB_Event_CloseWindow
If IsWindow(2):CloseWindow(2)
Else:Break
EndIf
EndSelect
Delay(20)
ForEver
StopTimer()
DataSection
ClockBack:
IncludeBinary "Clock - Back.tiff"
ClockBorder:
IncludeBinary "Border.tiff"
ClockGloss:
IncludeBinary "gloss.png"
ClockLongPointer:
IncludeBinary "hour_pointer.tiff"
ClockMediumPointer:
IncludeBinary "minute_pointer.tiff"
ClockSmallPointer:
IncludeBinary "second_pointer.tiff"
EndDataSection
Last edited by Psychophanta on Sun Jul 30, 2006 9:27 pm, edited 6 times in total.
- Joakim Christiansen
- Addict
- Posts: 2452
- Joined: Wed Dec 22, 2004 4:12 pm
- Location: Norway
- Contact:
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
The very nice think about your version, Psychophanta, is that the clock continues when menus and dialogs are displayed. However, it does not look the same any more. The hands are rendered in front of the glass. Obviously faster, but not as pretty.
And it updates every second instead of when the next second starts. So it could update and move the second hand in the middle of a second.
And it updates every second instead of when the next second starts. So it could update and move the second hand in the middle of a second.
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Well, that is possible to fix making some change.Trond wrote:The very nice think about your version, Psychophanta, is that the clock continues when menus and dialogs are displayed. However, it does not look the same any more. The hands are rendered in front of the glass. Obviously faster, but not as pretty.
ahhh! come on! that's not important. Keep in mind tha a timer is the more elegant solution for these kind of apps.Trond wrote:And it updates every second instead of when the next second starts. So it could update and move the second hand in the middle of a second.
It is very ugly to poll seconds every time.
EDIT: That has also solution even using timer. Just start the 1 sec timer at the date second bound and that's all

- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
I was able to remove all visible CPU usage by means of only drawing the border and gloss once. This was achieved by putting them on their own window and drawing it above the main window, keeping them together by catching the WM_MOVING event in a callback. This way, everything is drawn in the correct order and all original timing logic is kept. (it's good, no need to change it)
[edit] The SetParent_() in the SticktoDesktop procedure is causing a zorder difficulty doing it this way, that will have to be dealt with somehow.
[edit] The SetParent_() in the SticktoDesktop procedure is causing a zorder difficulty doing it this way, that will have to be dealt with somehow.
Code: Select all
Procedure CallBack(hwnd, message, wparam, lparam)
Result = #PB_ProcessPureBasicEvents
If message=#WM_MOVING
If hwnd = WindowID(0)
ResizeWindow(2, WindowX(0),WindowY(0),#PB_Ignore,#PB_Ignore)
Else
ResizeWindow(0, WindowX(2),WindowY(2),#PB_Ignore,#PB_Ignore)
EndIf
EndIf
ProcedureReturn result
EndProcedure
#APPNAME = "CoolClock"
UseTIFFImageDecoder()
UsePNGImageDecoder()
Enumeration
#ImgCanvas
#ImgBack
#ImgBorder
#ImgGloss
#ImgLongPointer
#ImgMediumPointer
#ImgSmallPointer
#imgCover
EndEnumeration
Global Alpha = 255
OpenWindow(1, 0, 0, 0, 0, #APPNAME + " Parent", #PB_Window_Invisible)
OpenWindow(0, 0, 0, 512, 384, #APPNAME, #PB_Window_Invisible, WindowID(1))
SetWindowLong_(WindowID(0), #GWL_EXSTYLE, GetWindowLong_(WindowID(0), #GWL_EXSTYLE) | #WS_EX_LAYERED)
;//////////////////////////////////////////////////////////////////////////////////
OpenWindow(2, 0, 0, 512, 384, #APPNAME+" Cover",#PB_Window_Invisible,WindowID(0))
HideWindow(2, 0)
SetWindowCallback(@CallBack())
SetWindowLong_(WindowID(2), #GWL_EXSTYLE, GetWindowLong_(WindowID(2), #GWL_EXSTYLE) | #WS_EX_LAYERED)
;//////////////////////////////////////////////////////////////////////////////////
CreatePopupMenu(0)
MenuItem(0, "Stick to &desktop")
MenuItem(1, "Always on &top")
MenuItem(2, "&Normal")
MenuBar()
MenuItem(3, "&Change translucency")
MenuBar()
MenuItem(4, "&Exit")
MenuItem(5, "&About")
CatchImage(#ImgGloss, ?ClockGloss)
CatchImage(#ImgBack, ?ClockBack)
CatchImage(#ImgBorder, ?ClockBorder)
CatchImage(#ImgLongPointer, ?ClockLongPointer)
CatchImage(#ImgMediumPointer, ?ClockMediumPointer)
CatchImage(#ImgSmallPointer, ?ClockSmallPointer)
;//////////////////////////////////////////////////////////////////////
CreateImage(#imgCover, 512,384)
hdc=StartDrawing(ImageOutput(#imgCover))
DrawAlphaImage(ImageID(#ImgGloss), 0, 0)
DrawAlphaImage(ImageID(#ImgBorder), 0, 0)
ContextOffset.POINT
BlendMode.BLENDFUNCTION
BitmapInfo.BITMAP
GetObject_(ImageID(#Imgcover), SizeOf(BITMAP), @BitmapInfo)
BlendMode\SourceConstantAlpha = 255
BlendMode\AlphaFormat = 1
UpdateLayeredWindow_(WindowID(2), 0, 0, @BitmapInfo+4, hDC, @ContextOffset, 0, @BlendMode, 2)
StopDrawing()
;//////////////////////////////////////////////////////////////////////
Procedure RotateDC(hDC.l, x0.l, y0.l, Degrees.d)
Static XFORM.XFORM
Protected Radians.d = Degrees*(#PI/180)
With XFORM
\eM11 = Cos(Radians)
\eM12 = Sin(Radians)
\eM21 = -\eM12
\eM22 = \eM11
\ex = x0 - Cos(Radians)*x0 + Sin(Radians)*y0
\ey = y0 - Cos(Radians)*y0 - Sin(Radians)*x0
EndWith
SetGraphicsMode_(hDC, #GM_ADVANCED)
SetWorldTransform_(hDC, XFORM)
EndProcedure
Procedure UpdateClock()
Static OldDate
Protected Date = Date()
If Date = OldDate
ProcedureReturn 0
Else
OldDate = Date
EndIf
Static hDC
Protected Hour = Hour(Date)
Protected Minute = Minute(Date)
Protected Second = Second(Date)
; Fresh copy of background to draw on
CopyImage(#ImgBack, #ImgCanvas)
; Draw on the background
hDC = StartDrawing(ImageOutput(#ImgCanvas))
;SaveDC_(hDC) ; Save the state for restoring after rotation
; Draw the large pointer
RotateDC(hDC, 128, 128, Minute/60*360)
DrawAlphaImage(ImageID(#ImgLongPointer), 128-9, 35)
; Draw the medium pointer
RotateDC(hDC, 128, 128, Hour/12*360)
DrawAlphaImage(ImageID(#ImgMediumPointer), 128-7, 30+36)
; Draw the small pointer
RotateDC(hDC, 128, 128, Second/60*360)
DrawAlphaImage(ImageID(#ImgSmallPointer), 128-7, 19)
;RestoreDC_(hDC, -1)
;DrawAlphaImage(ImageID(#ImgGloss), 0, 0)
;DrawAlphaImage(ImageID(#ImgBorder), 0, 0)
; Update the window
Static ContextOffset.POINT
Static BlendMode.BLENDFUNCTION
Static BitmapInfo.BITMAP
GetObject_(ImageID(#ImgCanvas), SizeOf(BITMAP), @BitmapInfo)
BlendMode\SourceConstantAlpha = Alpha
BlendMode\AlphaFormat = 1
UpdateLayeredWindow_(WindowID(0), 0, 0, @BitmapInfo+4, hDC, @ContextOffset, 0, @BlendMode, 2)
StopDrawing()
EndProcedure
Procedure StickToDesktop()
StickyWindow(0, 0)
SetParent_(WindowID(0), GetShellWindow_())
EndProcedure
Procedure AlwaysOnTop()
SetParent_(WindowID(0), 0)
StickyWindow(0, 1)
EndProcedure
Procedure ChangeTranslucency()
Protected AStr.s
Protected VA
AStr = InputRequester(#APPNAME, "Set the translucency (1 - 255):", Str(Alpha))
VA = Val(AStr)
If VA > 0 And VA < 256
Alpha = VA
Else
MessageRequester(#APPNAME, "Invalid value: " + AStr, #MB_ICONINFORMATION)
EndIf
EndProcedure
Procedure Normal()
SetParent_(WindowID(0), 0)
StickyWindow(0, 0)
EndProcedure
Procedure About()
Protected Text.s
Text + #APPNAME + #CRLF$
Text + "Copyright 2006 Trond Gundersen"
MessageRequester("About", Text)
EndProcedure
UpdateClock()
HideWindow(0, 0)
Repeat
Select WaitWindowEvent(10)
Case #WM_RBUTTONUP
DisplayPopupMenu(0, WindowID(1))
Case #WM_LBUTTONDOWN
SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, 0)
Case #PB_Event_Menu
Select EventMenu()
Case 0
StickToDesktop()
Case 1
AlwaysOnTop()
Case 2
Normal()
Case 3
ChangeTranslucency()
Case 4
Break
Case 5
About()
EndSelect
Case #PB_Event_CloseWindow
Break
EndSelect
UpdateClock()
ForEver
End
DataSection
ClockBack:
IncludeBinary "Clock - Back.tiff"
ClockBorder:
IncludeBinary "Border.tiff"
ClockGloss:
IncludeBinary "gloss.png"
ClockLongPointer:
IncludeBinary "hour_pointer.tiff"
ClockMediumPointer:
IncludeBinary "minute_pointer.tiff"
ClockSmallPointer:
IncludeBinary "second_pointer.tiff"
EndDataSection
BERESHEIT
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact:
Could be added an option menu in which you are able to choose to automatically synchronize time with a time server?
EDIT: Done. (source code in my post above). A friend of mine wanted it, and now he has to invite me to eat to a chinese restaurant (perhaps my preferred food -sorry for ones who don't like
- ).
EDIT: Done. (source code in my post above). A friend of mine wanted it, and now he has to invite me to eat to a chinese restaurant (perhaps my preferred food -sorry for ones who don't like

- Psychophanta
- Always Here
- Posts: 5153
- Joined: Wed Jun 11, 2003 9:33 pm
- Location: Anare
- Contact: