-- dynamically displays information, with it's icon in the System Tray.

include win32lib.ew
without warning

object ok

-- what follows is the 'TrayIcon' code    --
-- originally 'wrapped' by Hendrik Mundt. --

constant
  Shell_NotifyIconA__ = registerw32Function(shell32,"Shell_NotifyIconA",
                      {C_LONG,C_POINTER},C_INT),
  zNIM_ADD = 0,
  zNIM_MODIFY = 1,
  zNIM_DELETE = 2,

  zNIF_MESSAGE = 1,
  zNIF_ICON = 2,
  zNIF_TIP = 4,
  zWM_USER = #400,
  zUWM_SYSTRAY = zWM_USER + 1

-- declare memory required for NOTIFYICONDATA structure
constant
  NIDcbSize     = allot( DWord ),
  NIDhWnd       = allot( Long ),
  NIDuID        = allot( Long ),
  NIDuFlags     = allot( Long ),
  NIDuCallbackMessage = allot( Long ),
  NIDhIcon      = allot( DWord ),
  NIDszTip      = allot( 64 ),
  SIZE_OF_NOTIFYICONDATA = allotted_size()

function AddTrayIcon(atom hwnd,integer uid,atom hicon,sequence tooltip)
  atom nid

-- allocate memory for required structure
  nid = acquire_mem( 0,SIZE_OF_NOTIFYICONDATA )
-- and fill it with the required information
  store( nid, NIDcbSize, SIZE_OF_NOTIFYICONDATA )
  store( nid, NIDhWnd, hwnd )
  store( nid, NIDuID, uid )
  store( nid, NIDuFlags, or_all({ zNIF_MESSAGE,zNIF_ICON,zNIF_TIP} ))
  store( nid, NIDuCallbackMessage, zUWM_SYSTRAY )
  store( nid, NIDhIcon, hicon )
  store( nid, NIDszTip, tooltip )
    
  ok = w32Func(Shell_NotifyIconA__, {zNIM_ADD, nid} )
  release_mem( nid )
    
  return ok
end function

function DelTrayIcon(atom hwnd, integer uid)
  atom nid

  nid = acquire_mem( 0,SIZE_OF_NOTIFYICONDATA )
  store( nid, NIDcbSize, SIZE_OF_NOTIFYICONDATA )
  store( nid, NIDhWnd, hwnd )
  store( nid, NIDuID, uid )

  ok = w32Func( Shell_NotifyIconA__, {zNIM_DELETE, nid} )
  release_mem( nid )
    
  return ok
end function    
-- end of TrayIcon 'wrapper' --

sequence size

-- our main window and it's buttons.
constant
    MemWin  = create( Window, "- System Info -", 0, Default, Default, 480, 175, {WS_DLGFRAME} ),
    Button1 = create( PushButton, "Close", MemWin, 65, 123, 80, 25, 0 ),
    Button2 = create( PushButton, "Kill", MemWin, 180, 123, 80, 25, 0 ),
    Button3 = create( PushButton, "About", MemWin, 295, 123, 80, 25, 0 ),
    
-- links to procedures in kernel32.dll 
    zGlobalMemoryStatus = registerw32Procedure( kernel32, "GlobalMemoryStatus", {C_POINTER} ),
    zGetWindowsDirectory = registerw32Procedure( kernel32, "GetWindowsDirectoryA", {C_POINTER, C_INT} ),
    zGetCurrentDirectory = registerw32Function( kernel32, "GetCurrentDirectoryA", {C_INT, C_POINTER}, C_INT ),
    zGetCurrentTime = registerw32Procedure( kernel32, "GetLocalTime", {C_POINTER} )

-- lets calculate our pixmap size, based on the client
-- area left in our main window, and subtract 30 from the 'y' dimension 
-- to leave us room for the buttons.
    size = getClientRect(MemWin)

constant
  Buffer = create( Pixmap, "", 0, 0, 0, size[3]-size[1], size[4]-size[2]-30, 0 ),
  MyTimer = 1

-- easy on the eyes...
setFont(Buffer,"System",10,1)

-- some 'hints' for the buttons, in my 'pathetic' German.
setHint(Button1,"Fluoreszenzunterdrükkung ;-)")
setHint(Button2,"Stoppanweisung")
setHint(Button3,"...kann nicht in einer Stellung stehenbleiben!")

--The next four blocks of code, are all the routines which get the information to be displayed in the main window. 

sequence meminfo, windirstring, currentdirstring
atom buffer

procedure GetMemory()
  buffer = allocate(32)
  poke4(buffer,32)
  w32Proc(zGlobalMemoryStatus,{buffer})
  meminfo = peek4u({buffer,8})
  free(buffer)
end procedure

function GetWindowsDir()
  sequence WinDir
  integer i
  buffer = allocate(100)
  w32Proc(zGetWindowsDirectory, {buffer, 100})
  WinDir = ""
  i = 0
  while peek(buffer+i) != 0 do
    WinDir = WinDir & peek(buffer+i)
    i = i+1
  end while
free(buffer)
return WinDir
end function

function GetCurrentDir()
sequence CurrentDir
integer i
  buffer = allocate(4)   -- first get the length using this dummy length.
  i=w32Func(zGetCurrentDirectory, {4, buffer})
  if i=0 then
    ok = message_box( "Couldn't link to C function GetCurrentDirectoryA",
    "Win32 Error", MB_ICONHAND+MB_TASKMODAL )
    free(buffer)
    abort(1)
  end if
  free(buffer)
  buffer = allocate(i)   -- do it again, with the correct length this time!
  i=w32Func(zGetCurrentDirectory, {i, buffer})
  CurrentDir = ""
  i = 0
  while peek(buffer+i) != 0 do
    CurrentDir = CurrentDir & peek(buffer+i)
    i = i+1
  end while
  free(buffer)
  return CurrentDir
end function

function Getcurrenttime()
sequence currenttime
  buffer = allocate(16)
  w32Proc(zGetCurrentTime, {buffer})
  currenttime = ""
  for i = 0 to 15 do
    currenttime = currenttime & peek(buffer+i)
  end for
  free(buffer)
  return currenttime
end function

--The following refresh_info() routine is responsible for writing all the information into our pixmap buffer, and then writing the 
-- whole pixmap out to the program's main window every second. 

procedure refresh_info( integer self, integer event, sequence params )
  sequence s, t, string1

-- first let's clear the buffer pixmap by painting over it.
  setPenColor(Buffer,getSysColor( COLOR_BTNFACE ))
  drawRectangle(Buffer,1,0,0,size[3]-size[1],size[4]-size[2]-30)

-- then write out our time string.
  s=Getcurrenttime()
  t=sprintf("%02d",s[9..10]) & ":" & sprintf("%02d",s[11.12]) 
             & ":" & sprintf("%02d",s[13..14]) 
  setPenPos(Buffer,2,2)
  wPuts(Buffer,"current time = " & t )

-- ...then our memory info...
  GetMemory()
  setPenPos(Buffer,2,20)
  string1= "bytes of memory = " & sprintf("%d",meminfo[3])
  wPuts(Buffer,string1)
  setPenPos(Buffer,2,38)
  string1= "percent of memory in use  = " & sprintf("%d",meminfo[2]) & "%"
  wPuts(Buffer,string1 & "  - including 'virtual' memory.")
  setPenPos(Buffer,2,56)
  string1= "free memory bytes = " & sprintf("%d",meminfo[4])
  wPuts(Buffer,string1)

-- then, write out our directory info...
  setPenPos(Buffer,2,74)
  wPuts(Buffer,"Windows dir = " & windirstring)

  setPenPos(Buffer,2,92)
  wPuts(Buffer,"this program's dir = " & currentdirstring)

  copyBlt( MemWin, 0, 0, Buffer )
end procedure

--The next five procedures are all the event handlers for everything but the onTimer[] event, which is above. 

procedure onOpen_MemWin( integer self, integer event, sequence params )
-- put it's icon in the System Tray
-- note, for this simple example,
-- we're using the 'stock' IDI_QUESTION icon.
  ok = AddTrayIcon( getHandle(MemWin),1,
      w32Func( xLoadIcon, { NULL, IDI_QUESTION } ),
      "System Information" )   -- our app. name in the tooltip.
-- this is our re-fresh interval timer.
  setTimer(MemWin, MyTimer, 1000)
-- since the following is 'static', we only get it once.
  windirstring = GetWindowsDir()
  currentdirstring=GetCurrentDir()
end procedure

procedure hide_MemWin( integer self, integer event, sequence params )
  setVisible(MemWin,False)
end procedure

procedure kill_MemWin( integer self, integer event, sequence params )
-- since we're leaving, remove the program's icon.
  ok = DelTrayIcon( getHandle(MemWin), 1 )
  closeWindow(MemWin)
end procedure

procedure about( integer self, integer event, sequence params )
ok = message_box( "An application running from the SystemTray,\n" &
  "with code contributed by Hendrik Mundt.\n\n" &
  "Using Win32lib.ew,  by David Cuny and Friends.",
  "... a Win32 Tutorial",#2000)
end procedure

procedure onEvenr_MemWin( integer self, integer event, sequence params )
  integer lParam = params[1] -- maybe
  
  if lParam = WM_LBUTTONUP then
      setVisible( MemWin, True )
      ok = w32Func( xSetForegroundWindow,{getHandle(MemWin)})
  end if
  
end procedure

setHandler( MemWin, w32HOpen, routine_id("onOpen_MemWin") )
setHandler( MemWin, w32HTimer, routine_id("refresh_info") )
setHandler( Button1, w32HClick, routine_id("hide_MemWin") )
setHandler( Button2, w32HClick, routine_id("kill_MemWin") )
setHandler( Button3, w32HClick, routine_id("about") )
setHandler( MemWin, w32HEvent, routine_id("onEvent_MemWin") )

-- WinMain(MemWin,WS_MINIMIZE) -- if I do this, program vanishes into space!
WinMain(MemWin,Normal)
----
