unit TrayIcon;<br><br>interface<br><br>uses<br> Menus,windows,Types,Forms,Messages,SysUtils, Classes ,Graphics,ExtCtrls,ShellAPI,Controls;<br><br><br>const WM_SYSTEM_TRAY_NOTIFY = WM_USER + 100;<br>type<br>TTrayIconMessage=(imClick, imDoubleClick, imMouseDown,<br> imMouseUp, imLeftClickUp, imLeftDoubleClick,<br> imRightClickUp, imRightDoubleClick, imNone);<br><br> TTrayIcon = class(TComponent)<br> private<br> FVisible:boolean;<br> FHide:boolean;<br> FIconList:TImageList;<br> FData:TNotifyIconData;<br> FIsClicked:boolean;<br> FIcon:Ticon;<br> FTimer:TTimer;<br> FAnimate:boolean;<br> FIconIndex:integer;<br> FPopupMenu:TPopupMenu;<br> FHint:String ;<br><br> FAppRestore:TTrayIconMessage;<br> FPopupMenuShow:TTrayIconMessage;<br> FApplicationHook:TWindowHook;<br><br> FOnClick:TNotifyEvent;<br> FOnMinimize:TNotifyEvent;<br> FOnRestore:TNotifyEvent;<br> FOnMouseMove:TMouseMoveEvent;<br> FOnMouseExit:TMouseMoveEvent;<br> FOnMouseEnter:TMouseMoveEvent;<br> FOnDblClick:TNotifyEvent;<br> FOnMouseDown:TMouseEvent;<br> FOnMouseUp:TMouseEvent;<br> FOnAnimate:TNotifyEvent;<br> FOnCreate:TNotifyEvent;<br> FOnDestroy:TNotifyEvent;<br> FOnActivate:TNotifyEvent;<br> FOnDeactivate:TNotifyEvent;<br><br> procedure SetHint(Hint:String);<br> procedure SetHide(Value:boolean);<br> procedure EndSession;<br> function GetAnimateInterval:integer;<br> procedure SetAnimateInterval(Value:integer);<br> function GetAnimate:boolean;<br> procedure SetAnimate(Value:boolean);<br> function ShiftState:TShiftState;<br><br> { Private declarations }<br> protected<br> procedure DoClick();<br> procedure DoDblClick();<br> procedure DoOnAnimate(Sender:TObject);virtual;<br> procedure DoMouseMove(Shift:TShiftState;X:integer;Y:integer);virtual;<br> procedure DoMouseDown(Button:TMouseButton;Shift:TShiftState;X:integer;Y:integer);<br> procedure DoMouseUp(Button:TMouseButton;Shift:TShiftState;X:integer;Y:integer);<br> procedure SetVisible(Value:boolean);virtual;<br> procedure DoMessage(var Message: TMessage);//message WM_SYSTEM_TRAY_NOTIFY;<br> function ApplicationHookProc(var Message: TMessage):boolean;<br> procedure Notification(AComponent:TComponent;Operation: TOperation);override;<br> procedure Loaded; override;<br><br> property Data:TNotifyIconData read FData;<br> { Protected declarations }<br> public<br> constructor Create(AOwner: TComponent); override;<br> destructor Destroy; override;<br> procedure Update;virtual;<br> procedure Minimize;virtual;<br> procedure Restore;virtual;<br> procedure ShowMenu;virtual;<br> procedure SetIconIndex(Value:integer);virtual;<br> procedure SetDefaultIcon;virtual;<br> function GetHandle:HWND;<br> { Public declarations }<br> published<br> property IconIndex:integer read FIconIndex write SetIconIndex default 0;<br> property Visible:boolean read FVisible write SetVisible default false;<br> property Hide:boolean read FHide write SetHide;<br> property Hint:String read FHint write SetHint;<br> property PopupMenu:TPopupMenu read FPopupMenu write FPopupMenu;<br> property RestoreOn:TTrayIconMessage read FAppRestore write FAppRestore;<br> property PopupMenuOn:TTrayIconMessage read FPopupMenuShow write FPopupMenuShow;<br> property Icons:TImageList read FIconList write FIconList;<br> property AnimateInterval:integer read GetAnimateInterval write SetAnimateInterval default 1000;<br> property Animate:boolean read GetAnimate write SetAnimate default false;<br> property Handle:HWND read GetHandle;<br><br> // Events<br> property OnMinimize:TNotifyEvent read FOnMinimize write FOnMinimize;<br> property OnRestore:TNotifyEvent read FOnRestore write FOnRestore;<br> property OnClick:TNotifyEvent read FOnClick write FOnClick;<br> property OnMouseEnter:TMouseMoveEvent read FOnMouseEnter write FOnMouseEnter;<br> property OnMouseExit:TMouseMoveEvent read FOnMouseExit write FOnMouseExit;<br> property OnMouseMove:TMouseMoveEvent read FOnMouseMove write FOnMouseMove;<br> property OnMouseUp:TMouseEvent read FOnMouseUp write FOnMouseUp;<br> property OnMouseDown:TMouseEvent read FOnMouseDown write FOnMouseDown;<br> property OnAnimate:TNotifyEvent read FOnAnimate write FOnAnimate;<br> property OnCreate:TNotifyEvent read FOnCreate write FOnCreate;<br> property OnDestroy:TNotifyEvent read FOnDestroy write FOnDestroy;<br> property OnActivate:TNotifyEvent read FOnActivate write FOnActivate;<br> property OnDeactivate:TNotifyEvent read FOnDeactivate write FOnDeactivate;<br><br> { Published declarations }<br> end;<br><br>procedure Register;<br><br>implementation<br><br>procedure Register;<br>begin<br> RegisterComponents('Samples', [TTrayIcon]);<br>end;<br><br>procedure TTrayIcon.DoOnAnimate(Sender:TObject);<br>begin<br> if (IconIndex < FIconList.Count-1) then<br> inc(FIconIndex)<br> else<br> FIconIndex := 0;<br><br> SetIconIndex(FIconIndex);<br><br> Update;<br>end;<br><br>procedure TTrayIcon.SetHide(Value:boolean);<br>begin<br> FHide := Value;<br>end;<br><br><br>procedure TTrayIcon.SetIconIndex(Value:integer);<br>begin<br> FIconIndex := Value;<br><br> if assigned(FIconList) then<br> FIconList.GetIcon(FIconIndex, FIcon);<br><br> Update;<br>end;<br><br><br>constructor TTrayIcon.Create(AOwner: TComponent);<br>begin<br> inherited;<br> FIcon := TIcon.CREATE ;<br> FTimer := TTimer.Create(nil);<br><br> FIconIndex:= 0;<br> FIcon.Assign(Application.Icon);<br> FAppRestore := imDoubleClick;<br> FOnAnimate := DoOnAnimate;<br> FPopupMenuShow := imNone;<br> FVisible := false;<br> FHide := true;<br> FTimer.Enabled := false;<br> FTimer.OnTimer := OnAnimate;<br> FTimer.Interval := 1000;<br><br> if (not (csDesigning in ComponentState)) then<br> begin<br> FData.cbSize := sizeof(TNotifyIconData);<br> FData.Wnd := AllocateHWnd(DoMessage);<br> FData.uID := integer(self);<br> FData.hIcon := FIcon.Handle;<br> FData.uFlags := NIF_ICON or NIF_MESSAGE;<br> FData.uCallbackMessage := WM_SYSTEM_TRAY_NOTIFY;<br><br> FApplicationHook := ApplicationHookProc;<br> Update;<br> end;<br>end;<br><br><br><br>destructor TTrayIcon.Destroy;<br>begin<br> if (not (csDesigning in ComponentState)) then<br> begin<br> Shell_NotifyIcon(NIM_DELETE, @FData);<br> DeallocateHWnd(FData.Wnd);<br> end;<br><br> if assigned(FIcon) then<br> FIcon.free;<br><br> if assigned(FTimer) then<br> FTimer.free;<br> inherited;<br>end;<br><br><br>procedure TTrayIcon.Update;<br>begin<br> if (not (csDesigning in ComponentState)) then<br> begin<br> FData.hIcon := FIcon.Handle;<br><br> if (Visible = true) then<br> Shell_NotifyIcon(NIM_MODIFY, @FData);<br> end;<br>end;<br><br>procedure TTrayIcon.SetVisible(Value:boolean);<br>begin<br> FVisible := Value;<br><br> if (not (csDesigning in ComponentState)) then<br> begin<br> if (FVisible) then<br> begin<br> if (not Shell_NotifyIcon(NIM_ADD, @FData)) then<br> raise EOutOfResources.Create('Cannot create!');<br><br> Hide := true;<br> Application.HookMainWindow(FApplicationHook);<br> end<br> else<br> begin<br> if (not Shell_NotifyIcon(NIM_DELETE, @FData)) then<br> raise EOutOfResources.Create('Cannot move!');;<br><br> Hide := false;<br> Application.UnhookMainWindow(FApplicationHook);<br> end;<br> end;<br>end;<br><br><br>procedure TTrayIcon.EndSession;<br>begin<br> Shell_NotifyIcon(NIM_DELETE, @FData);<br>end;<br><br><br>procedure TTrayIcon.DoMessage(var Message:TMessage);<br>var<br> point:TPoint;<br> shift:TShiftState;<br>begin<br> case Message.Msg of<br> WM_QUERYENDSESSION:<br> Message.Result := 1;<br> WM_ENDSESSION:<br> EndSession;<br> WM_SYSTEM_TRAY_NOTIFY:<br> begin<br> case Message.LParam of<br> WM_MOUSEMOVE:<br> if assigned(FOnClick) then<br> begin<br> shift := ShiftState;<br> GetCursorPos(point);<br> DoMouseMove(shift, point.x, point.y);<br> end;<br> WM_LBUTTONDOWN:<br> begin<br> shift := ShiftState;<br> shift:= shift+[ssLeft];<br> GetCursorPos(point);<br> DoMouseDown(mbLeft, shift, point.x, point.y);<br> FIsClicked := true;<br> end;<br> WM_LBUTTONUP:<br> begin<br> shift := ShiftState;<br> shift :=shift+[ssLeft];<br> GetCursorPos(point);<br><br> if assigned(FOnClick) then<br> DoClick;<br><br> DoMouseUp(mbLeft, shift, point.x, point.y);<br><br> if (FAppRestore = imLeftClickUp) then<br> Restore;<br> if (FPopupMenuShow = imLeftClickUp) then<br> ShowMenu;<br> end;<br> WM_LBUTTONDBLCLK:<br> begin<br> DoDblClick;<br><br> if (FAppRestore = imLeftDoubleClick) then<br> Restore;<br> if (FPopupMenuShow = imLeftDoubleClick) then<br> ShowMenu;<br> end;<br> WM_RBUTTONDOWN:<br> begin<br> shift := ShiftState;<br> shift:= shift+[ssRight];<br> GetCursorPos(point);<br> DoMouseDown(mbRight, shift, point.x, point.y);<br> end;<br> WM_RBUTTONUP:<br> begin<br> shift:= ShiftState;<br> shift:=shift+[ssRight];<br> GetCursorPos(point);<br><br> DoMouseUp(mbRight, shift, point.x, point.y);<br><br> if (FAppRestore = imRightClickUp) then<br> Restore;<br> if (FPopupMenuShow = imRightClickUp) then<br> ShowMenu;<br> end;<br> WM_RBUTTONDBLCLK:<br> begin<br> DoDblClick;<br><br> if (FAppRestore = imRightDoubleClick) then<br> Restore;<br> if (FPopupMenuShow = imRightDoubleClick) then<br> ShowMenu;<br> end;<br> WM_MBUTTONDOWN:<br> begin<br> shift := ShiftState;<br> shift:=shift+[ssMiddle];<br> GetCursorPos(point);<br><br> DoMouseDown(mbMiddle, shift, point.x, point.y);<br> end;<br> WM_MBUTTONUP:<br> begin<br> shift := ShiftState;<br> shift:=shift+[ssMiddle];<br> GetCursorPos(point);<br> DoMouseUp(mbMiddle, shift, point.x, point.y);<br> end;<br> WM_MBUTTONDBLCLK:<br> DoDblClick();<br> end;<br> end;<br> end;<br><br> inherited Dispatch(Message);<br>end;<br><br>procedure TTrayIcon.DoClick;<br>begin<br> if (FAppRestore = imClick) then<br> Restore;<br> if (FPopupMenuShow = imClick) then<br> ShowMenu;<br><br> if assigned(FOnClick) then<br> FOnClick(self);<br>end;<br><br>procedure TTrayIcon.DoDblClick;<br>begin<br> if (FAppRestore = imDoubleClick) then<br> Restore;<br> if (FPopupMenuShow = imDoubleClick) then<br> ShowMenu;<br><br> if assigned(FOnDblClick) then<br> FOnDblClick(self);<br>end;<br><br>procedure TTrayIcon.DoMouseMove(Shift:TShiftState;X:integer;Y:integer);<br>begin<br> if assigned(FOnMouseMove) then<br> FOnMouseMove(self, Shift, X, Y);<br>end;<br><br>procedure TTrayIcon.DoMouseDown(Button:TMouseButton;Shift:TShiftState;<br> X:integer;Y:integer);<br>begin<br> if (FAppRestore = imMouseDown) then<br> Restore;<br> if (FPopupMenuShow = imMouseDown) then<br> ShowMenu;<br><br> if assigned(FOnMouseDown) then<br> FOnMouseDown(self, Button, Shift, X, Y);<br>end;<br><br>procedure TTrayIcon.DoMouseUp(Button:TMouseButton ;Shift:TShiftState;<br> X:integer;Y:integer);<br>begin<br> if (FAppRestore = imMouseDown) then<br> Restore;<br> if (FPopupMenuShow = imMouseDown) then<br> ShowMenu;<br><br> if assigned(FOnMouseUp) then<br> FOnMouseUp(self, Button, Shift, X, Y);<br>end;<br><br>function TTrayIcon.ApplicationHookProc(var Message:TMessage):boolean;<br>begin<br> if (Message.Msg = WM_SYSCOMMAND) then<br> begin<br> if (Message.WParam = SC_MINIMIZE) then<br> Minimize;<br> if (Message.WParam = SC_RESTORE) then<br> Restore;<br> end;<br> result:= false;<br>end;<br><br>procedure TTrayIcon.Minimize;<br>begin<br> Application.Minimize;<br> ShowWindow(Application.Handle, SW_HIDE);<br><br> if assigned(FOnMinimize) then<br> FOnMinimize(self);<br>end;<br><br>procedure TTrayIcon.Restore;<br>begin<br> Application.Restore;<br> ShowWindow(Application.Handle, SW_RESTORE);<br> SetForegroundWindow(Application.Handle);<br><br> if assigned(FOnRestore) then<br> FOnRestore(self);<br>end;<br><br>procedure TTrayIcon.ShowMenu;<br>var<br>Point:Tpoint;<br>begin<br> GetCursorPos(point);<br><br> try<br> if (Screen.ActiveForm.Handle <>0) then<br> SetForegroundWindow(Screen.ActiveForm.Handle);<br> except<br> end;<br><br> FPopupMenu.Popup(point.x, point.y);<br>end;<br><br>procedure TTrayIcon.SetDefaultIcon;<br>begin<br> FIcon.Assign(Application.Icon);<br> Update;<br>end;<br><br><br>procedure TTrayIcon.Notification(AComponent:TComponent;Operation:TOperation);<br>begin<br> inherited Notification(AComponent, Operation);<br> if (Operation = opRemove) then<br> begin<br> if (AComponent = FIconList) then<br> FIconList := nil<br> else if (AComponent = FPopupMenu) then<br> FPopupMenu := nil;<br> end;<br>end;<br><br>procedure TTrayIcon.Loaded;<br>begin<br> inherited Loaded;<br><br> if not assigned( FIconList) then<br> begin<br> FAnimate := false;<br> FIcon.Assign(Application.Icon);<br> end<br> else<br> begin<br> FTimer.Enabled := FAnimate;<br> FIconList.GetIcon(FIconIndex, FIcon);<br> end;<br><br> Update;<br>end;<br><br><br>procedure TTrayIcon.SetHint(Hint:String);<br>begin<br> // The new hint must be different than the previous hint and less than<br> // 64 characters to be modified. 64 is an operating system limit.<br> if ((FHint <> Hint) and (length(Hint) < 64)) then<br> begin<br> FHint := Hint;<br> StrPLCopy(FData.szTip, Hint, sizeof(FData.szTip) - 1);<br><br> // If there is no hint then there is no tool tip.<br> if Length(Hint)>0 then<br> FData.uFlags := FData.uFlags or NIF_TIP<br> else<br> FData.uFlags := FData.uFlags and (not NIF_TIP);<br><br> Update;<br> end;<br>end;<br><br>function TTrayIcon.GetAnimateInterval:integer;<br>begin<br> result:= FTimer.Interval;<br>end;<br><br>procedure TTrayIcon.SetAnimateInterval(Value:integer);<br>begin<br> FTimer.Interval := Value;<br>end;<br><br>function TTrayIcon.GetAnimate:boolean;<br>begin<br> result:=FAnimate;<br>end;<br><br>procedure TTrayIcon.SetAnimate(Value:boolean);<br>begin<br> if (assigned(FIconList) or (csLoading in ComponentState)) then<br> FAnimate := Value;<br><br> if (assigned(FIconList) and (not (csDesigning in ComponentState))) then<br> FTimer.Enabled := Value;<br>end;<br><br><br>function TTrayIcon.ShiftState:TShiftState;<br>begin<br> if (GetKeyState(VK_SHIFT) < 0) then<br> result:=result+[ssShift];<br> if (GetKeyState(VK_CONTROL) < 0) then<br> result:=result+[ssCtrl];<br> if (GetKeyState(VK_MENU) < 0) then<br> result:=result+[ssAlt];<br>end;<br><br><br>function TTrayIcon.GetHandle:HWND;<br>begin<br> result:= FData.Wnd;<br>end;<br><br><br><br>end.