NB. JNotify class for Windows Taskbar Notification Area

NB. This class creates an icon in the Windows Notification
NB. Area on the taskbar.  Mouse clicks on the icon result in
NB. calls to <notify_handler> in the COCREATOR locale, with a
NB. right argument of:
NB.    WM_APP,(id used when creating icon),(event message).
NB.
NB. Eg:
NB.    notify_handler=: verb def 'verb to handle events'
NB.    n=. ('c:\myicon.ico';0;'My Tooltip';0) conew 'jnotify'
NB.    modify__n 'c:\newicon.ico';0;'New Tooltip';0
NB.    destroy__n ''
NB.
NB. Notes:
NB.  1/ The taskbar notification area is often mistakenly
NB.     called the system tray.
NB.  2/ You can explicitly add and delete the icon, but the
NB.     create and destroy methods will do this for you.
NB.     You need one instance of a jnotify object for each
NB.     icon you want to add to the notification area.
NB.  3/ If your J application ends without deleting the icon,
NB.     (eg by destroying the jnotify object), the icon will
NB.     remain in the notification area until the mouse next
NB.     moves over it.  (Then Windows will notice the app
NB.     is gone and will delete the icon).
NB.  4/ The iconfile argument names a .ico, .exe or .dll file.
NB.     In the case of a .exe or .dll, the iconresource argument
NB.     is the index of the icon to use.
NB.  5/ The icon in the notification area is 16x16, however
NB.     Windows will shrink a 32x32 icon to fit.

require 'dll winapi'
require '~system\packages\winapi\wdmsg.ijs'
require '~system\packages\winapi\menu.ijs'

coclass 'jnotify'



NB. Windows constants:

WM_APP=: 32768     NB. base of application messages

NIM_size=: 88
NIM_ADD=: 0
NIM_MODIFY=: 1
NIM_DELETE=: 2
NIF_MESSAGE=: 1
NIF_ICON=: 2
NIF_TIP=:4

WM_MOUSEMOVE=: 512   NB. event messages
WM_LBUTTONDOWN=: 513
WM_LBUTTONUP=: 514
WM_LBUTTONDBLCLK=: 515
WM_RBUTTONDOWN=: 516
WM_RBUTTONUP=: 517
WM_RBUTTONDBLCLK=: 518
WM_MBUTTONDOWN=: 519
WM_MBUTTONUP=: 520
WM_MBUTTONDBLCLK=: 521



NB. Call notify_handler when our WM_APP message is received.
verb define ''
if. _1=nc <'NOTIFYTBL' do. NOTIFYTBL=: 0 2$a: end.
)

register=: verb define
empty NOTIFYTBL_jnotify_=: (#~ ~:@:({."1)) NOTIFYTBL_jnotify_,y.;coname ''
)

unregister=: verb define
empty NOTIFYTBL_jnotify_=: NOTIFYTBL_jnotify_#~y.~:>{."1 NOTIFYTBL_jnotify_
)


msg_handler=: verb define
if. (#NOTIFYTBL)~:i=. (>{."1 NOTIFYTBL) i. 1{y. do.
	l=. ('COCREATOR_',(>1{i{NOTIFYTBL),'_')~ NB. locale
	notify_handler__l y.
end.
empty ''
)


wdmsgregister WM_APP    NB. register this locale for WM_APP messages







NB. create - create jnotify object and (optionally) icon
NB.   y - 'iconfile';iconresource;'tooltip';id
NB.    or '', meaning don't add the icon yet (see <add>)
create=:3 : 0
hicon=: uid=: 0
if. *#y. do. add y. end.
)


NB. destroy - delete icon (if exists) and destroy object 
NB.   y. - ''
destroy=: verb define
if. *hicon do. delete '';0;'' end.
codestroy ''
)


NB. add - add the icon
NB.   y - 'iconfile';iconresource;'tooltip';id
add=: verb define
notifyicon NIM_ADD;y.
register >3{y.,3#<0
)


NB. modify - modify an existing icon
NB.   y - 'iconfile';iconresource;'tooltip';id
modify=: verb define
notifyicon NIM_MODIFY;y.
)


NB. delete - delete the icon
NB.   y - ''
delete=: verb define
unregister uid
notifyicon NIM_DELETE;'';0;'';uid
)


NB. popup - Place a popup message where the mouse is.
NB. This is a cover for wdmenu (see
NB. '~system\packages\winapi\menu.ijs')
NB. We also create a hidden foreground window in
NB. order to make sure the popup goes away if the
NB. user selects elsewhere on the screen.
popup=: verb define
xy=. _1 _1
wd 'pc hidden'
'SetForegroundWindow' win32api ".wd 'qhwndp'
z=. (>1{'GetCursorPos' win32api <xy) wdmenu y.
wd 'psel hidden;pclose'
z
)




NB. Utilities

notifyicon=: verb define
'nm icon iconres tip id'=. y.,(#y.)}._1;'';0;'';0

i=. 0
if. nm~:NIM_DELETE do. i=. extract_icon icon;iconres end.

assert *nim=. mema NIM_size
NIM_size memw nim,0,1,4        NB. size
(".wd 'qhwndx') memw nim,4,1,4 NB. hWnd
id memw nim,8,1,4              NB. uID
(NIF_MESSAGE+NIF_ICON+NIF_TIP**#tip) memw nim,12,1,4 NB. flags
WM_APP memw nim,16,1,4 NB.  message
i memw nim,20,1,4 NB.  hIcon
tip memw nim,24,(#tip),2 [ tip=. tip{.~63<.#tip  NB. szTip

assert 1=rc=. >{. 'shell32 Shell_NotifyIconA i i i'&(15!:0) nm;nim

memf nim
if. *hicon do. 'DestroyIcon' win32api hicon end.
hicon=: i*nm~:NIM_DELETE
uid=: id
)



extract_icon=: verb define
'icon iconres'=. y.
assert *z=. >{. 'ExtractIcon' win32api (".wd 'qhinst');icon;<._2+2+iconres
z
)


