[MAXGUIEx] Tray icon code not working?

BlitzMax Forums/BlitzMax GUI Programming/[MAXGUIEx] Tray icon code not working?

Hey guys!

I'm trying to get Ozak's code to work with MAXGUIEX:
http://www.blitzmax.com/codearcs/codearcs.php?code=1643

Example code: Sinking / Showing an app from task bar.

SuperStrict

Framework brl.D3D7Max2D 
  Import brl.GlMax2D 
'  Import brl.FreeTypeFont 
'  Import brl.Timer       
'  Import brl.Bmploader
'  Import brl.Pngloader
'  Import brl.Jpgloader
  Import brl.System
  Import brl.EventQueue 
  Import brl.Event
  Import MaxGUI.Drivers

Global window:TGadget = CreateWindow( "Window", 80,80,640,480)
Global panel:TGadget = CreatePanel( 0,0, 0,0, window,0)

Repeat
	WaitEvent()
	
	Select EventID()
		Case EVENT_MOUSEMOVE
			If EventSource() = panel Then
  	 	           Print "TEST"
				Select EventX()
'					Case WM_MOUSEMOVE		Print "mouse move"
'					Case WM_LBUTTONDOWN	Print "left down"
					Case WM_LBUTTONUP		ShowGadget(window); RemoveTrayIcon()
					Case WM_LBUTTONDBLCLK	ShowGadget(window); RemoveTrayIcon()
'					Case WM_RBUTTONDOWN	Print "right down"
'					Case WM_RBUTTONUP		Print "right up"
'					Case WM_RBUTTONDBLCLK	Print "right doucle click"
'					Case WM_MBUTTONDOWN	Print "middle down"
'					Case WM_MBUTTONUP		Print "middle up"
'					Case WM_MBUTTONDBLCLK	Print "middle double click"
					Default
'						Print "unknown " + EventX()
				EndSelect
			EndIf
		Case EVENT_WINDOWCLOSE
                 RegisterTrayIcon(panel, "Click to activate app", "prp.ico") '<- INSERT YOUR ICON HERE ;)
                 'RemoveTrayIcon()
			HideGadget(window)
	EndSelect
Forever

' unregister tray icon
RemoveTrayIcon()

End

' Tray minimize win32 application

?Win32
' tray icons 
'
Const NIM_ADD:Int			= 0
Const NIM_MODIFY:Int		= 1
Const NIM_DELETE:Int		= 2
Const NIM_SETFOCUS:Int		= 3
Const NIM_SETVERSION:Int	= 4

Const NIF_MESSAGE:Int	= $00000001
Const NIF_ICON:Int	= $00000002
Const NIF_TIP:Int		= $00000004
Const NIF_STATE:Int	= $00000008
Const NIF_INFO:Int	= $00000010
Const NIF_GUID:Int	= $00000020

Type TNotifyIconData
	Field Size:Int
	Field HWND:Int
	Field id:Int
	Field Flags:Int
	Field CallbackMessage:Int
	Field Icon:Int 				' HICON	
	Field Tip:Long				' array [0..63] of AnsiChar;
	Field Tip2:Long
	Field Tip3:Long
	Field Tip4:Long
	Field Tip5:Long
	Field Tip6:Long
	Field Tip7:Long
	Field Tip8:Long
EndType

Extern "WIN32"
	Function Shell_NotifyIcon:Int( message:Int, notifyicondata:Byte Ptr) = "Shell_NotifyIconA@8"
EndExtern

Function SetNotifyIconDataTip( nid:TNotifyIconData, s:String)
	MemClear( Varptr nid.Tip, 64)
	If s.length > 0 Then
		Local p:Byte Ptr = s.ToCString()
		If s.length < 64 Then
			MemCopy( Varptr nid.Tip, p, s.length)
		Else			
			MemCopy( Varptr nid.Tip, p, 63)			
		EndIf
		MemFree( p)
	EndIf
EndFunction

'
' window messages (also used by tray icon)
'
Const WM_MOUSEMOVE:Int        = $0200
Const WM_LBUTTONDOWN:Int      = $0201
Const WM_LBUTTONUP:Int        = $0202
Const WM_LBUTTONDBLCLK:Int    = $0203
Const WM_RBUTTONDOWN:Int      = $0204
Const WM_RBUTTONUP:Int        = $0205
Const WM_RBUTTONDBLCLK:Int    = $0206
Const WM_MBUTTONDOWN:Int      = $0207
Const WM_MBUTTONUP:Int        = $0208
Const WM_MBUTTONDBLCLK:Int    = $0209

'
' icon resources
'
Const IMAGE_BITMAP:Int      = 0
Const IMAGE_ICON:Int        = 1
Const IMAGE_CURSOR:Int      = 2
Const IMAGE_ENHMETAFILE:Int = 3

Const LR_DEFAULTSIZE:Int      = 64
Const LR_DEFAULTCOLOR:Int     = 0
Const LR_MONOCHROME:Int       = 1
Const LR_COLOR:Int            = 2
Const LR_COPYRETURNORG:Int    = 4
Const LR_COPYDELETEORG:Int    = 8
Const LR_LOADFROMFILE:Int     = 16
Const LR_LOADTRANSPARENT:Int  = 32
Const LR_LOADREALSIZE:Int     = 128
Const LR_LOADMAP3DCOLORS:Int  = 4096
Const LR_CREATEDIBSECTION:Int = 8192
Const LR_COPYFROMRESOURCE:Int = $4000 ' 0x4000
Const LR_SHARED:Int      	  = 32768           
	
Global nid:TNotifyIconData

Extern "WIN32"
	Function LoadImage_:Int( Instance:Int, Name$z, Type_:Int, DesiredX:Int, DesiredY:Int, Load:Int) = "LoadImageA@24"
EndExtern

Function LoadIcon:Int( filename:String, width:Int=16,Height:Int=16, Flags:Int=LR_SHARED)
	Return LoadImage_( 0, filename, IMAGE_ICON, width,Height, LR_LOADFROMFILE| Flags)
EndFunction
?

' Register tray icon
Function RegisterTrayIcon(window:TGadget, toolTip:String, iconFile:String)

?Win32
	nid = New TNotifyIconData
	nid.Size = SizeOf(TNotifyIconData)
	nid.hwnd = QueryGadget(window, QUERY_HWND)
	nid.id = 0
	nid.CallbackMessage = WM_MOUSEMOVE
	nid.Icon = LoadIcon( iconFile)
	nid.Flags = NIF_MESSAGE | NIF_TIP | NIF_ICON
	SetNotifyIconDataTip( nid, toolTip )
	Shell_NotifyIcon( NIM_ADD, nid)
?
End Function   

'Remove tray icon
Function RemoveTrayIcon()    
?Win32
	Shell_NotifyIcon(NIM_DELETE, nid)
?
End Function


Any ideas why this isn't working are highly appreciated.

Grisu

The reason why it isn't working is that you can't handle Windows system messages (i.e those starting with WM_**********) using the standard Blitz event system as they aren't Blitz/MaxGUI events.

I spent some time looking into this for you and the easiest (and probably most dirty) way of doing this is by registering a new WndProc that maps these events into Blitz ones.

I've just noticed your original code-archive querym, so I've modded the code slightly so that it uses the executable icon (instead of an icon from a file) for the notification icon. If you copy and paste the code 'as-is', it will use MaxIDE's object resource file but you should obviously replace this with your own.

Anyhoo, try the following:
THIS WILL ONLY WORK WITH MAXGUI.WIN32MAXGUIEX

SuperStrict

Framework MaxGUI.Win32MaxGUIEx 
Import BRL.EventQueue
Import "../src/maxide/maxicons.o"

AppTitle = "Shell_NotifyIcon Sample Program"

Global window:TGadget = CreateWindow( AppTitle, 80, 80, 640, 480, Null, WINDOW_TITLEBAR|WINDOW_RESIZABLE|WINDOW_STATUS|WINDOW_MENU|WINDOW_CLIENTCOORDS )
Global panel:TGadget = CreatePanel( 0, 0, 0, 0, window, 0 )

Repeat
	Select WaitEvent()
		
		Case EVENT_MOUSEDOWN
			
			Select EventSource()
				Case panel
					ShowGadget(window)
					RemoveTrayIcon()
			EndSelect
		
		Case EVENT_WINDOWCLOSE
		
                 RegisterTrayIcon(panel, "Click to activate app!" )
			HideGadget(window)
			
	EndSelect
	
Forever

' unregister tray icon
RemoveTrayIcon()

End


' Register tray icon
Function RegisterTrayIcon( window:TGadget, toolTip:String )

	?Win32
	nid = New TNotifyIconData
	nid.Size = SizeOf(TNotifyIconData)
	nid.hwnd = QueryGadget(window, QUERY_HWND)
	SetWindowLongW(nid.hwnd,GWL_WNDPROC,Int Byte Ptr SysTrayWndProc)
	nid.id = 0
	nid.CallbackMessage = WM_APP
	nid.Icon = LoadIconW(GetModuleHandleW(Null),Short Ptr(101))
	nid.Flags = NIF_MESSAGE | NIF_TIP | NIF_ICON
	SetNotifyIconDataTip( nid, toolTip )
	Shell_NotifyIcon( NIM_ADD, nid)
	?
	
End Function

'WndProc NotifyIcon -> Blitz Event
Function SysTrayWndProc%(hwnd%,msg%,wp%,lp%) "win32"
	?Win32
	Select msg
		Case WM_APP
			Local owner:TGadget = TWindowsGadget(TWindowsGUIDriver.GadgetMap.ValueForKey(String(hwnd)))
			If owner Then
				Select lp
					Case WM_MOUSEMOVE
						PostGuiEvent( EVENT_MOUSEMOVE, owner )
					Case WM_LBUTTONDOWN, WM_LBUTTONDBLCLK
						PostGuiEvent( EVENT_MOUSEDOWN, owner, MOUSE_LEFT )
					Case WM_LBUTTONUP
						PostGuiEvent( EVENT_MOUSEUP, owner, MOUSE_LEFT )
					Case WM_RBUTTONDOWN, WM_RBUTTONDBLCLK
						PostGuiEvent( EVENT_MOUSEDOWN, owner, MOUSE_RIGHT )
					Case WM_RBUTTONUP
						PostGuiEvent( EVENT_MOUSEDOWN, owner, MOUSE_RIGHT )
					Case WM_MBUTTONDOWN, WM_MBUTTONDBLCLK
						PostGuiEvent( EVENT_MOUSEDOWN, owner, MOUSE_MIDDLE )
					Case WM_MBUTTONUP
						PostGuiEvent( EVENT_MOUSEDOWN, owner, MOUSE_MIDDLE )
					Case WM_MOUSELEAVE
						PostGuiEvent( EVENT_MOUSELEAVE, owner )
				EndSelect
			EndIf
	EndSelect
	Return TWindowsGUIDriver.ClassWndProc(hwnd,msg,wp,lp)
	?
EndFunction

'Remove tray icon
Function RemoveTrayIcon()    
	?Win32
	Shell_NotifyIcon(NIM_DELETE, nid)
	?
End Function

Function SetNotifyIconDataTip( nid:TNotifyIconData, s:String)
	MemClear( Varptr nid.Tip, 64)
	If s.length > 0 Then
		Local p:Byte Ptr = s.ToCString()
		If s.length < 64 Then
			MemCopy( Varptr nid.Tip, p, s.length)
		Else			
			MemCopy( Varptr nid.Tip, p, 63)			
		EndIf
		MemFree( p)
	EndIf
EndFunction



?Win32
' tray icons 
'
Const NIM_ADD:Int			= 0
Const NIM_MODIFY:Int		= 1
Const NIM_DELETE:Int		= 2
Const NIM_SETFOCUS:Int		= 3
Const NIM_SETVERSION:Int	= 4

Const NIF_MESSAGE:Int		= $1
Const NIF_ICON:Int		= $2
Const NIF_TIP:Int			= $4
Const NIF_STATE:Int		= $8
Const NIF_INFO:Int		= $10
Const NIF_GUID:Int		= $20

Global nid:TNotifyIconData

Type TNotifyIconData
	Field Size:Int
	Field HWND:Int
	Field id:Int
	Field Flags:Int
	Field CallbackMessage:Int
	Field Icon:Int 				' HICON	
	Field Tip:Long				' array [0..63] of AnsiChar;
	Field Tip2:Long
	Field Tip3:Long
	Field Tip4:Long
	Field Tip5:Long
	Field Tip6:Long
	Field Tip7:Long
	Field Tip8:Long
EndType

Extern "win32"
	Function Shell_NotifyIcon:Int( message:Int, notifyicondata:Byte Ptr) = "Shell_NotifyIconA@8"
EndExtern
?


You should then be able to process the events like regular MaxGUI ones, but watchout, the events don't hold any x,y co-ordinate info. You will have to play around a bit more to get these...

Thanks a lot Seb. Works flawlessly.

Have added this to Ozak's code archive entry in case other might need it as well.