/*
 * Xailer source code:
 *
 * NotifyIcon.prg
 * Clase para manejo de los NotifyIcon
 *
 * Copyright 2003, 2007 Jose F. Gimenez
 * Copyright 2003, 2007 Jose Lalin
 * Copyright 2003, 2007 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"
#include "ShellApi.api"

STATIC nLastId := 900

//--------------------------------------------------------------------------

CLASS XNotifyIcon FROM TWinObject

PUBLISHED:
   PROPERTY oImageList     AS TImageList  EDITOR PE_ImageList
   PROPERTY oMenu          AS TPopupMenu  EDITOR PE_Component
   PROPERTY nImage         INIT 0   WRITE SetIcon EDITOR PE_ImageIndex
   PROPERTY cTooltip       INIT ""  WRITE SetTooltip
   PROPERTY lVisible       INIT .F. WRITE INLINE IIf( Value, ::Show(), ::Hide() )

   EVENT OnLButtonDown( oSender, nX, nY ) // --> Nil
   EVENT OnLButtonUp( oSender, nX, nY )   // --> Nil
   EVENT OnDblClick( oSender, nX, nY )    // --> Nil

   EVENT OnRButtonUp( oSender, nX, nY )   // --> Nil
   EVENT OnRButtonDown( oSender, nX, nY ) // --> Nil
   EVENT OnRButtonDblClk( oSender, nX, nY )  // --> Nil

   EVENT OnMouseMove( oSender, nX, nY )   // --> Nil

   EVENT OnBalloonShow( oSender )      // --> Nil
   EVENT OnBalloonHide( oSender )      // --> Nil
   EVENT OnBalloonTimeout( oSender )   // --> Nil
   EVENT OnBalloonClick( oSender )     // --> Nil

PROTECTED:
   PROPERTY nID      INIT 900
   DATA hIcon

   METHOD ShowMenu()
   METHOD DoDefault()

PUBLIC:
   PROPERTY oParent

   METHOD New( oParent ) CONSTRUCTOR
   METHOD Create( oParent ) CONSTRUCTOR
   METHOD Free()

   METHOD Show()        INLINE ::FlVisible := .T., ::Run( NIM_ADD )    // --> lSuccess
   METHOD Hide()        INLINE ::FlVisible := .F., ::Run( NIM_DELETE ) // --> lSuccess
   METHOD Refresh()     INLINE ::Run( NIM_MODIFY ) // --> lSuccess

   METHOD Run( nAction ) // --> lSuccess
   METHOD Execute( nAction )  EXTERN XNotifyIcon_Run( nAction ) // --> lSuccess

   METHOD AddIcon( cIcon )    INLINE IIf( ::oImageList != Nil, ::oImageList:AddIcon( cIcon ), -1 ) // --> nIcon
   METHOD SetIcon( nImage )   INLINE ( ::FnImage := nImage, ::Refresh() ) // --> Nil
   METHOD SetToolTip( cTip )  INLINE ( ::FcTooltip := Left( cTip, 63 ), ::Refresh() ) // --> Nil
   METHOD SetMenu( oMenu )    INLINE ::oMenu := oMenu // --> Nil

   METHOD ShowBalloon( cMessage, cTitle, nFlags, nTimeout ) // --> Nil
   METHOD HideBalloon() // --> Nil

RESERVED:
   METHOD Link()              EXTERN WndLink()
   METHOD Unlink()            EXTERN WndUnlink()

   METHOD InsertComponent()   VIRTUAL
   METHOD RemoveComponent()   VIRTUAL

   METHOD WMXailer( nWParam, nLParam )

ENDCLASS

//--------------------------------------------------------------------------

METHOD New( oParent ) CLASS XNotifyIcon

   ::FoImageList := TImageList():Create( Self, 16, 16 )

RETURN ::Super:New( oParent )

//--------------------------------------------------------------------------

METHOD Create( oParent ) CLASS XNotifyIcon

   UPDATE ::oParent  TO oParent
   UPDATE ::nID      TO ++nLastId

   ::lFree := .T.

   IF ! GetClassInfo( ::ClassName )
      RegisterClass( ::ClassName )
   ENDIF

   IF ( ::Handle := CreateWindow( ::ClassName, "",,,,,,, -3 ) ) != 0
      ::Link()
   ENDIF

   IF ::oImageList == Nil
      ::oImageList := TImageList():Create( Self, 16, 16 )
   ENDIF

   IF ::oParent != Nil
      ::oParent:InsertComponent( Self )
   ENDIF

RETURN Self

//--------------------------------------------------------------------------

METHOD Free() CLASS XNotifyIcon

   ::Hide()

   IF ! Empty( ::Handle )
      ::Unlink()
      DestroyWindow( ::Handle )
   ENDIF

   IF ::oImageList != Nil .AND. ::oImageList:oParent == Self
      ::oImageList:Destroy()
   ENDIF

RETURN ::Super:Free()

//--------------------------------------------------------------------------

METHOD WMXailer( nWParam, nLParam ) CLASS XNotifyIcon

   LOCAL nX := LOWORD( nLParam )
   LOCAL nY := HIWORD( nLParam )

   /* NOTA: El icono de notificacion siempre envia el mensaje indicado
            en NOTIFYICONDATA.uCallbackMessage (WM_XAILER) y pasa en
            nLParam el verdadero evento que se ha producido.

            nWParam es el nID del notify icon.
   */

   IF nWParam == ::nID
      DO CASE
         CASE nLParam == WM_LBUTTONDOWN
            ::OnLButtonDown( nX, nY )
         CASE nLParam == WM_LBUTTONUP
            ::OnLButtonUp( nX, nY )
         CASE nLParam == WM_LBUTTONDBLCLK
            ::DoDefault( nX, nY )
         CASE nLParam == WM_RBUTTONDOWN
            ::OnRButtonDown( nX, nY )
         CASE nLParam == WM_RBUTTONUP
            IF ::OnRButtonUp( nX, nY ) == Nil
               ::ShowMenu()
            ENDIF
         CASE nLParam == WM_RBUTTONDBLCLK
            ::OnRButtonDblClk(  nX, nY )
         CASE nLParam == WM_MOUSEMOVE
            ::OnMouseMove( nX, nY )
         CASE nLParam == NIN_BALLOONSHOW
            ::OnBalloonShow()
         CASE nLParam == NIN_BALLOONHIDE
            ::OnBalloonHide()
         CASE nLParam == NIN_BALLOONTIMEOUT
            ::OnBalloonTimeout()
         CASE nLParam == NIN_BALLOONUSERCLICK
            ::OnBalloonClick()
      ENDCASE
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD DoDefault() CLASS XNotifyIcon

   IF ::oMenu != Nil .AND. ::oMenu:GetDefault() > 0
      ::oMenu:DoDefault()
   ELSE
      ::OnDblClick()
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD ShowMenu() CLASS XNotifyIcon

   LOCAL nOption
   LOCAL aPos := GetCursorPos()

   IF ::oMenu != Nil

      SetForegroundWindow( ::oParent:Handle )
      ::oParent:oForm:oPopup := ::oMenu
      nOption := TrackPopupMenu( ::oMenu:Handle, TPM_RETURNCMD, aPos[ 1 ], aPos[ 2 ], ::oParent:Handle )
      ::oParent:oForm:oPopup := Nil

      IF nOption > 0
         ::oMenu:DoAction( nOption )
         PostMessage( ::Handle, WM_NULL, 0, 0 )
      ENDIF

   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

#pragma BEGINDUMP

#define _WIN32_IE 0x0500

#include <windows.h>
#include <commctrl.h>
#include <xailer.h>
#include <constants.ch>

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XNOTIFYICON_RUN )
{
   NOTIFYICONDATA nid;
   PHB_ITEM Self = hb_stackSelfItem();
   PHB_ITEM oImage = XA_ObjGetItemCopy( Self, "oImageList" );
   UINT iImageIndex = XA_ObjGetNL( Self, "nImage" );
   UINT uiAction = hb_parnl( 1 );
   HICON hIcon = (HICON) XA_ObjGetNL( Self, "hIcon" );

   if( hIcon )
      {
      DestroyIcon( hIcon );
      XA_ObjSendNil( Self, "_hIcon" );
      }

   nid.cbSize  = sizeof( NOTIFYICONDATA );
   nid.hWnd    = GetHandleOf( Self );
   nid.uID     = XA_ObjGetNL( Self, "nID" );
   nid.uFlags  = 0;

   switch( uiAction )
   {
      case NIM_ADD:
         {
				nid.uCallbackMessage = WM_XAILER;
            nid.uFlags |= NIF_MESSAGE;
         }
      // NOTA: No hay break para que se ejecute el bloque NIM_MODIFY [jlalin]
      /* fall through */

      case NIM_MODIFY:
         {
            char * cTooltip = XA_ObjGetC( Self, "cTooltip" );

            if( iImageIndex )
            {
               HANDLE hIL = GetHandleOf( oImage );

               nid.hIcon = ImageList_GetIcon( hIL, iImageIndex - 1, 0 );
               nid.uFlags |= NIF_ICON ;
               XA_ObjSendNL( Self, "_hIcon", (long) nid.hIcon );
            }

            if( cTooltip )
            {
               strcpy( nid.szTip, cTooltip );
               nid.uFlags |= NIF_TIP;
            }
         }
         break;

      //case NIM_DELETE:
      //   break;
   }

   hb_retl( Shell_NotifyIcon( uiAction, &nid ) );

   hb_itemRelease( oImage );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XNOTIFYICON_SHOWBALLOON )
{
   PHB_ITEM Self = hb_stackSelfItem();
   NOTIFYICONDATA nid;

   LPCSTR cTooltip;
   LPCSTR cMsg = hb_parc( 1 );
   LPCSTR cTitle = hb_parc( 2 );

   nid.cbSize     = sizeof( NOTIFYICONDATA );
   nid.hWnd       = GetHandleOf( Self );
   nid.uID        = XA_ObjGetNL( Self, "nID" );
   nid.uFlags     = NIF_INFO;
   nid.dwInfoFlags = hb_parnl( 3 );
#ifdef __GNUC__
   nid.uTimeout = hb_parni( 4 );
#else
   nid.u.uTimeout = hb_parni( 4 );
#endif

   if( ( cTooltip = XA_ObjGetC( Self, "cTooltip" ) ) != NULL )
      {
      strncpy( nid.szTip, cTooltip, sizeof( nid.szTip ) );
      nid.szTip[ sizeof( nid.szTip ) - 1 ] = 0;
      }

   if( cTitle )
      {
      strncpy( nid.szInfoTitle, cTitle, sizeof( nid.szInfoTitle ) );
      nid.szInfoTitle[ sizeof( nid.szInfoTitle ) - 1 ] = 0;
      }

   if( cMsg )
      {
      strncpy( nid.szInfo, cMsg, sizeof( nid.szInfo ) );
      nid.szInfo[ sizeof( nid.szInfo ) - 1 ] = 0;
      }

   Shell_NotifyIcon( NIM_MODIFY, &nid );
   hb_ret();
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XNOTIFYICON_HIDEBALLOON )
{
   PHB_ITEM Self = hb_stackSelfItem();
   NOTIFYICONDATA nid;

   nid.cbSize     = sizeof( NOTIFYICONDATA );
   nid.hWnd       = GetHandleOf( Self );
   nid.uID        = XA_ObjGetNL( Self, "nID" );
   nid.uFlags     = NIF_INFO;
   nid.dwInfoFlags = 0;
#ifdef __GNUC__
   nid.uTimeout = 0;
#else
   nid.u.uTimeout = 0;
#endif

   strcpy( nid.szInfo, "" );
   Shell_NotifyIcon( NIM_MODIFY, &nid );
   hb_ret();
}

#pragma ENDDUMP

//--------------------------------------------------------------------------
