home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kolekce / d6 / rxlibsetup.exe / {app} / units / RXSHELL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-02-19  |  21.3 KB  |  790 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 2001,2002 SGB Software          }
  6. {         Copyright (c) 1997, 1998 Fedor Koshevnikov,   }
  7. {                        Igor Pavluk and Serge Korolev  }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11.  
  12. {.$DEFINE USE_TIMER}
  13. { - Use Windows timer instead thread to the animated TrayIcon }
  14.  
  15. {$IFNDEF WIN32}
  16.   {$DEFINE USE_TIMER}  { - Always use timer in 16-bit version }
  17. {$ENDIF}
  18.  
  19. unit RXShell;
  20.  
  21. {$I RX.INC}
  22. {$P+,W-,R-}
  23.  
  24. interface
  25.  
  26. uses {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF} Messages,
  27.   Classes, Graphics, SysUtils, Forms, Controls, Menus, ShellAPI,
  28.   {$IFDEF USE_TIMER} ExtCtrls, {$ENDIF} IcoList;
  29.  
  30. type
  31. {$IFNDEF WIN32}
  32.   PNotifyIconData = ^TNotifyIconData;
  33.   TNotifyIconData = record
  34.     cbSize: Longint;
  35.     Wnd: Longint;
  36.     uID: Longint;
  37.     uFlags: Longint;
  38.     uCallbackMessage: Longint;
  39.     hIcon: Longint;
  40.     szTip: array [0..63] of Char;
  41.   end;
  42. {$ENDIF}
  43.  
  44.   TMouseButtons = set of TMouseButton;
  45.  
  46. { TRxTrayIcon }
  47.  
  48.   TRxTrayIcon = class(TComponent)
  49.   private
  50.     FHandle: HWnd;
  51.     FActive: Boolean;
  52.     FAdded: Boolean;
  53.     FAnimated: Boolean;
  54.     FEnabled: Boolean;
  55.     FClicked: TMouseButtons;
  56.     FIconIndex: Integer;
  57.     FInterval: Word;
  58.     FIconData: TNotifyIconData;
  59.     FIcon: TIcon;
  60.     FIconList: TIconList;
  61. {$IFDEF USE_TIMER}
  62.     FTimer: TTimer;
  63. {$ELSE}
  64.     FTimer: TThread;
  65. {$ENDIF}
  66.     FHint: string;
  67.     FShowDesign: Boolean;
  68.     FPopupMenu: TPopupMenu;
  69.     FOnClick: TMouseEvent;
  70.     FOnDblClick: TNotifyEvent;
  71.     FOnMouseMove: TMouseMoveEvent;
  72.     FOnMouseDown: TMouseEvent;
  73.     FOnMouseUp: TMouseEvent;
  74.     procedure ChangeIcon;
  75. {$IFDEF USE_TIMER}
  76.     procedure Timer(Sender: TObject);
  77. {$ELSE}
  78.     procedure Timer;
  79. {$ENDIF}
  80.     procedure SendCancelMode;
  81.     function CheckMenuPopup(X, Y: Integer): Boolean;
  82.     function CheckDefaultMenuItem: Boolean;
  83.     procedure SetHint(const Value: string);
  84.     procedure SetIcon(Value: TIcon);
  85.     procedure SetIconList(Value: TIconList);
  86.     procedure SetPopupMenu(Value: TPopupMenu);
  87.     procedure Activate;
  88.     procedure Deactivate;
  89.     procedure SetActive(Value: Boolean);
  90.     function GetAnimated: Boolean;
  91.     procedure SetAnimated(Value: Boolean);
  92.     procedure SetShowDesign(Value: Boolean);
  93.     procedure SetInterval(Value: Word);
  94.     procedure IconChanged(Sender: TObject);
  95.     procedure WndProc(var Message: TMessage);
  96.     function GetActiveIcon: TIcon;
  97.   protected
  98.     procedure DblClick; dynamic;
  99.     procedure DoClick(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
  100.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
  101.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;
  102.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
  103.     procedure Loaded; override;
  104.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  105.     procedure UpdateNotifyData; virtual;
  106.   public
  107.     constructor Create(AOwner: TComponent); override;
  108.     destructor Destroy; override;
  109.     procedure Hide;
  110.     procedure Show;
  111.     property Handle: HWnd read FHandle;
  112.   published
  113.     property Active: Boolean read FActive write SetActive default True;
  114.     property Enabled: Boolean read FEnabled write FEnabled default True;
  115.     property Hint: string read FHint write SetHint;
  116.     property Icon: TIcon read FIcon write SetIcon;
  117.     property Icons: TIconList read FIconList write SetIconList;
  118.     { Ensure Icons is declared before Animated }
  119.     property Animated: Boolean read GetAnimated write SetAnimated default False;
  120.     property Interval: Word read FInterval write SetInterval default 150;
  121.     property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
  122.     property ShowDesign: Boolean read FShowDesign write SetShowDesign stored False;
  123.     property OnClick: TMouseEvent read FOnClick write FOnClick;
  124.     property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
  125.     property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
  126.     property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
  127.     property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
  128.   end;
  129.  
  130. function IconExtract(const FileName: string; Id: Integer): TIcon;
  131. procedure WinAbout(const AppName, Stuff: string);
  132.  
  133. type
  134.   TExecState = (esNormal, esMinimized, esMaximized, esHidden);
  135.  
  136. function FileExecute(const FileName, Params, StartDir: string;
  137.   InitialState: TExecState): THandle;
  138. function FileExecuteWait(const FileName, Params, StartDir: string;
  139.   InitialState: TExecState): Integer;
  140.  
  141. implementation
  142.  
  143. uses RxConst, RxCConst, VCLUtils, MaxMin;
  144.  
  145. {$IFNDEF WIN32}
  146. const
  147.   Shell = 'shell';
  148.  
  149. function ExtractAssociatedIcon(hInst: THandle; lpIconPath: PChar;
  150.   var lpiIcon: Word): HIcon; far; external Shell;
  151. function ShellAbout(Wnd: HWnd; App, Stuff: PChar; Icon: HIcon): Integer;
  152.   far; external Shell;
  153. {$ENDIF WIN32}
  154.  
  155. procedure WinAbout(const AppName, Stuff: string);
  156. var
  157. {$IFNDEF WIN32}
  158.   szApp, szStuff: array[0..255] of Char;
  159. {$ENDIF}
  160.   Wnd: HWnd;
  161.   Icon: HIcon;
  162. begin
  163.   if Application.MainForm <> nil then Wnd := Application.MainForm.Handle
  164.   else Wnd := 0;
  165.   Icon := Application.Icon.Handle;
  166.   if Icon = 0 then Icon := LoadIcon(0, IDI_APPLICATION);
  167. {$IFDEF WIN32}
  168.   ShellAbout(Wnd, PChar(AppName), PChar(Stuff), Icon);
  169. {$ELSE}
  170.   StrPLCopy(szApp, AppName, SizeOf(szApp) - 1);
  171.   StrPLCopy(szStuff, Stuff, SizeOf(szStuff) - 1);
  172.   ShellAbout(Wnd, szApp, szStuff, Icon);
  173. {$ENDIF}
  174. end;
  175.  
  176. function IconExtract(const FileName: string; Id: Integer): TIcon;
  177. var
  178.   S: array[0..255] of char;
  179.   IconHandle: HIcon;
  180.   Index: Word;
  181. begin
  182.   Result := TIcon.Create;
  183.   try
  184.     StrPLCopy(S, FileName, SizeOf(S) - 1);
  185.     IconHandle := ExtractIcon(hInstance, S, Id);
  186.     if IconHandle < 2 then begin
  187.       Index := Id;
  188.       IconHandle := ExtractAssociatedIcon(hInstance, S, Index);
  189.     end;
  190.     if IconHandle < 2 then begin
  191.       if IconHandle = 1 then
  192.         raise EResNotFound.Create(LoadStr(SFileNotExec))
  193.       else begin
  194.         Result.Free;
  195.         Result := nil;
  196.       end;
  197.     end else Result.Handle := IconHandle;
  198.   except
  199.     Result.Free;
  200.     raise;
  201.   end;
  202. end;
  203.  
  204. const
  205.   ShowCommands: array[TExecState] of Integer =
  206.     (SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED, SW_HIDE);
  207.  
  208. function FileExecute(const FileName, Params, StartDir: string;
  209.   InitialState: TExecState): THandle;
  210. {$IFDEF WIN32}
  211. begin
  212.   Result := ShellExecute(Application.Handle, nil, PChar(FileName),
  213.     PChar(Params), PChar(StartDir), ShowCommands[InitialState]);
  214. end;
  215. {$ELSE}
  216. var
  217.   cFileName, cParams, cPath: array [0..80] of Char;
  218. begin
  219.   Result := ShellExecute(Application.Handle, nil, StrPCopy(cFileName,
  220.     FileName), StrPCopy(cParams, Params), StrPCopy(cPath, StartDir),
  221.     ShowCommands[InitialState]);
  222. end;
  223. {$ENDIF}
  224.  
  225. function FileExecuteWait(const FileName, Params, StartDir: string;
  226.   InitialState: TExecState): Integer;
  227. {$IFDEF WIN32}
  228. var
  229.   Info: TShellExecuteInfo;
  230.   ExitCode: DWORD;
  231. begin
  232.   FillChar(Info, SizeOf(Info), 0);
  233.   Info.cbSize := SizeOf(TShellExecuteInfo);
  234.   with Info do begin
  235.     fMask := SEE_MASK_NOCLOSEPROCESS;
  236.     Wnd := Application.Handle;
  237.     lpFile := PChar(FileName);
  238.     lpParameters := PChar(Params);
  239.     lpDirectory := PChar(StartDir);
  240.     nShow := ShowCommands[InitialState];
  241.   end;
  242.   if ShellExecuteEx(@Info) then begin
  243.     repeat
  244.       Application.ProcessMessages;
  245.       GetExitCodeProcess(Info.hProcess, ExitCode);
  246.     until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
  247.     Result := ExitCode;
  248.   end
  249.   else Result := -1;
  250. end;
  251. {$ELSE}
  252. var
  253.   Task: THandle;
  254. begin
  255.   Result := 0;
  256.   Task := FileExecute(FileName, Params, StartDir, InitialState);
  257.   if Task >= HINSTANCE_ERROR then begin
  258.     repeat
  259.       Application.ProcessMessages;
  260.     until (GetModuleUsage(Task) = 0) or Application.Terminated;
  261.   end
  262.   else Result := -1;
  263. end;
  264. {$ENDIF}
  265.  
  266. {$IFNDEF USE_TIMER}
  267.  
  268. { TTimerThread }
  269.  
  270. type
  271.   TTimerThread = class(TThread)
  272.   private
  273.     FOwnerTray: TRxTrayIcon;
  274.   protected
  275.     procedure Execute; override;
  276.   public
  277.     constructor Create(TrayIcon: TRxTrayIcon; CreateSuspended: Boolean);
  278.   end;
  279.  
  280. constructor TTimerThread.Create(TrayIcon: TRxTrayIcon; CreateSuspended: Boolean);
  281. begin
  282.   FOwnerTray := TrayIcon;
  283.   inherited Create(CreateSuspended);
  284.   FreeOnTerminate := True;
  285. end;
  286.  
  287. procedure TTimerThread.Execute;
  288.  
  289.   function ThreadClosed: Boolean;
  290.   begin
  291.     Result := Terminated or Application.Terminated or (FOwnerTray = nil);
  292.   end;
  293.  
  294. begin
  295.   while not Terminated do begin
  296.     if not ThreadClosed then
  297.       if SleepEx(FOwnerTray.FInterval, False) = 0 then begin
  298.         if not ThreadClosed and FOwnerTray.Animated then
  299.           FOwnerTray.Timer;
  300.       end;
  301.   end;
  302. end;
  303.  
  304. {$ENDIF USE_TIMER}
  305.  
  306. {$IFNDEF WIN32}
  307.  
  308. type
  309.   TLoadLibrary32 = function (FileName: PChar; Handle, Special: Longint): Longint;
  310.   TFreeLibrary32 = function (Handle: Longint): Bool;
  311.   TGetAddress32 = function (Handle: Longint; ProcName: PChar): Pointer;
  312.   TCallProc32 = function (Msg: Longint; Data: PNotifyIconData; ProcHandle: Pointer;
  313.     AddressConvert, Params: Longint): Longint;
  314.  
  315. const
  316.   NIM_ADD     = $00000000;
  317.   NIM_MODIFY  = $00000001;
  318.   NIM_DELETE  = $00000002;
  319.  
  320.   NIF_MESSAGE = $00000001;
  321.   NIF_ICON    = $00000002;
  322.   NIF_TIP     = $00000004;
  323.  
  324. const
  325.   Shell32: Longint = 0;
  326.   ProcAddr: Pointer = nil;
  327.   FreeLib32: TFreeLibrary32 = nil;
  328.   CallPrc32: TCallProc32 = nil;
  329.  
  330. procedure FreeHandles; far;
  331. begin
  332.   if (ProcAddr <> nil) and Assigned(FreeLib32) then FreeLib32(Shell32);
  333. end;
  334.  
  335. procedure InitHandles;
  336. var
  337.   Kernel16: THandle;
  338.   LoadLib32: TLoadLibrary32;
  339.   GetAddr32: TGetAddress32;
  340. begin
  341.   Kernel16 := GetModuleHandle('kernel');
  342.   @LoadLib32 := GetProcAddress(Kernel16, 'LoadLibraryEx32W');
  343.   @FreeLib32 := GetProcAddress(Kernel16, 'FreeLibrary32W');
  344.   @GetAddr32 := GetProcAddress(Kernel16, 'GetProcAddress32W');
  345.   @CallPrc32 := GetProcAddress(Kernel16, 'CallProc32W');
  346.   if (@LoadLib32 <> nil) and (@FreeLib32 <> nil) and (@GetAddr32 <> nil)
  347.     and (@CallPrc32 <> nil) then
  348.   begin
  349.     Shell32 := LoadLib32('shell32', 0, 0);
  350.     if Shell32 >= HINSTANCE_ERROR then begin
  351.       ProcAddr := GetAddr32(Shell32, 'Shell_NotifyIcon');
  352.       if ProcAddr = nil then begin
  353.         FreeLib32(Shell32);
  354.         Shell32 := 1;
  355.       end
  356.       else AddExitProc(FreeHandles);
  357.     end
  358.     else Shell32 := 1;
  359.   end;
  360. end;
  361.  
  362. function Shell_NotifyIcon(dwMessage: Longint; lpData: PNotifyIconData): Bool;
  363. begin
  364.   if (ProcAddr = nil) and (Shell32 <> 1) then InitHandles;
  365.   if ProcAddr <> nil then
  366.     Result := Bool(CallPrc32(dwMessage, lpData, ProcAddr, $01, 2));
  367. end;
  368.  
  369. {$ENDIF WIN32}
  370.  
  371. { TRxTrayIcon }
  372.  
  373. constructor TRxTrayIcon.Create(AOwner: Tcomponent);
  374. begin
  375.   inherited Create(AOwner);
  376.   FHandle := Classes.AllocateHWnd(WndProc);
  377.   FIcon := TIcon.Create;
  378.   FIcon.OnChange := IconChanged;
  379.   FIconList := TIconList.Create;
  380.   FIconList.OnChange := IconChanged;
  381.   FIconIndex := -1;
  382.   FEnabled := True;
  383.   FInterval := 150;
  384.   FActive := True;
  385. end;
  386.  
  387. destructor TRxTrayIcon.Destroy;
  388. begin
  389.   Destroying;
  390.   FEnabled := False;
  391.   FIconList.OnChange := nil;
  392.   FIcon.OnChange := nil;
  393.   SetAnimated(False);
  394.   Deactivate;
  395.   Classes.DeallocateHWnd(FHandle);
  396.   FIcon.Free;
  397.   FIcon := nil;
  398.   FIconList.Free;
  399.   FIconList := nil;
  400.   inherited Destroy;
  401. end;
  402.  
  403. procedure TRxTrayIcon.Loaded;
  404. begin
  405.   inherited Loaded;
  406.   if FActive and not (csDesigning in ComponentState) then Activate;
  407. end;
  408.  
  409. procedure TRxTrayIcon.Notification(AComponent: TComponent;
  410.   Operation: TOperation);
  411. begin
  412.   inherited Notification(AComponent, Operation);
  413.   if (AComponent = PopupMenu) and (Operation = opRemove) then
  414.     PopupMenu := nil;
  415. end;
  416.  
  417. procedure TRxTrayIcon.SetPopupMenu(Value: TPopupMenu);
  418. begin
  419.   FPopupMenu := Value;
  420. {$IFDEF WIN32}
  421.   if Value <> nil then Value.FreeNotification(Self);
  422. {$ENDIF}
  423. end;
  424.  
  425. procedure TRxTrayIcon.SendCancelMode;
  426. var
  427.   F: TForm;
  428. begin
  429.   if not (csDestroying in ComponentState) then begin
  430.     F := Screen.ActiveForm;
  431.     if F = nil then F := Application.MainForm;
  432.     if F <> nil then F.SendCancelMode(nil);
  433.   end;
  434. end;
  435.  
  436. function TRxTrayIcon.CheckMenuPopup(X, Y: Integer): Boolean;
  437. begin
  438.   Result := False;
  439.   if not (csDesigning in ComponentState) and Active and
  440.     (PopupMenu <> nil) and PopupMenu.AutoPopup then
  441.   begin
  442.     PopupMenu.PopupComponent := Self;
  443.     SendCancelMode;
  444.     SwitchToWindow(FHandle, False);
  445.     Application.ProcessMessages;
  446.     try
  447.       PopupMenu.Popup(X, Y);
  448.     finally
  449. {$IFDEF WIN32}
  450.       SwitchToWindow(FHandle, False);
  451. {$ENDIF}
  452.     end;
  453.     Result := True;
  454.   end;
  455. end;
  456.  
  457. function TRxTrayIcon.CheckDefaultMenuItem: Boolean;
  458. {$IFDEF WIN32}
  459. var
  460.   Item: TMenuItem;
  461.   I: Integer;
  462. {$ENDIF}
  463. begin
  464.   Result := False;
  465. {$IFDEF WIN32}
  466.   if not (csDesigning in ComponentState) and Active and
  467.     (PopupMenu <> nil) and (PopupMenu.Items <> nil) then
  468.   begin
  469.     I := 0;
  470.     while (I < PopupMenu.Items.Count) do begin
  471.       Item := PopupMenu.Items[I];
  472.       if Item.Default and Item.Enabled then begin
  473.         Item.Click;
  474.         Result := True;
  475.         Break;
  476.       end;
  477.       Inc(I);
  478.     end;
  479.   end;
  480. {$ENDIF}
  481. end;
  482.  
  483. procedure TRxTrayIcon.SetIcon(Value: TIcon);
  484. begin
  485.   FIcon.Assign(Value);
  486. end;
  487.  
  488. procedure TRxTrayIcon.SetIconList(Value: TIconList);
  489. begin
  490.   FIconList.Assign(Value);
  491. end;
  492.  
  493. function TRxTrayIcon.GetActiveIcon: TIcon;
  494. begin
  495.   Result := FIcon;
  496.   if (FIconList <> nil) and (FIconList.Count > 0) and Animated then
  497.     Result := FIconList[Max(Min(FIconIndex, FIconList.Count - 1), 0)];
  498. end;
  499.  
  500. function TRxTrayIcon.GetAnimated: Boolean;
  501. begin
  502.   Result := FAnimated;
  503. end;
  504.  
  505. procedure TRxTrayIcon.SetAnimated(Value: Boolean);
  506. begin
  507.   Value := Value and Assigned(FIconList) and (FIconList.Count > 0);
  508.   if Value <> Animated then begin
  509.     if Value then begin
  510. {$IFDEF USE_TIMER}
  511.       FTimer := TTimer.Create(Self);
  512.       FTimer.Enabled := FAdded;
  513.       FTimer.Interval := FInterval;
  514.       FTimer.OnTimer := Timer;
  515. {$ELSE}
  516.       FTimer := TTimerThread.Create(Self, not FAdded);
  517. {$ENDIF}
  518.       FAnimated := True;
  519.     end
  520.     else begin
  521.       FAnimated := False;
  522. {$IFDEF USE_TIMER}
  523.       FTimer.Free;
  524.       FTimer := nil;
  525. {$ELSE}
  526.       TTimerThread(FTimer).FOwnerTray := nil;
  527.       while FTimer.Suspended do FTimer.Resume;
  528.       FTimer.Terminate;
  529. {$ENDIF}
  530.     end;
  531.     FIconIndex := 0;
  532.     ChangeIcon;
  533.   end;
  534. end;
  535.  
  536. procedure TRxTrayIcon.SetActive(Value: Boolean);
  537. begin
  538.   if (Value <> FActive) then begin
  539.     FActive := Value;
  540.     if not (csDesigning in ComponentState) then
  541.       if Value then Activate else Deactivate;
  542.   end;
  543. end;
  544.  
  545. procedure TRxTrayIcon.Show;
  546. begin
  547.   Active := True;
  548. end;
  549.  
  550. procedure TRxTrayIcon.Hide;
  551. begin
  552.   Active := False;
  553. end;
  554.  
  555. procedure TRxTrayIcon.SetShowDesign(Value: Boolean);
  556. begin
  557.   if (csDesigning in ComponentState) then begin
  558.     if Value then Activate else Deactivate;
  559.     FShowDesign := FAdded;
  560.   end;
  561. end;
  562.  
  563. procedure TRxTrayIcon.SetInterval(Value: Word);
  564. begin
  565.   if FInterval <> Value then begin
  566.     FInterval := Value;
  567. {$IFDEF USE_TIMER}
  568.     if Animated then FTimer.Interval := FInterval;
  569. {$ENDIF}
  570.   end;
  571. end;
  572.  
  573. {$IFDEF USE_TIMER}
  574. procedure TRxTrayIcon.Timer(Sender: TObject);
  575. {$ELSE}
  576. procedure TRxTrayIcon.Timer;
  577. {$ENDIF}
  578. begin
  579.   if not (csDestroying in ComponentState) and Animated then begin
  580.     Inc(FIconIndex);
  581.     if (FIconList = nil) or (FIconIndex >= FIconList.Count) then
  582.       FIconIndex := 0;
  583.     ChangeIcon;
  584.   end;
  585. end;
  586.  
  587. procedure TRxTrayIcon.IconChanged(Sender: TObject);
  588. begin
  589.   ChangeIcon;
  590. end;
  591.  
  592. procedure TRxTrayIcon.SetHint(const Value: string);
  593. begin
  594.   if FHint <> Value then begin
  595.     FHint := Value;
  596.     ChangeIcon;
  597.   end;
  598. end;
  599.  
  600. procedure TRxTrayIcon.UpdateNotifyData;
  601. var
  602.   Ico: TIcon;
  603. begin
  604.   with FIconData do begin
  605.     cbSize := SizeOf(TNotifyIconData);
  606.     Wnd := FHandle;
  607.     uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
  608.     Ico := GetActiveIcon;
  609.     if Ico <> nil then hIcon := Ico.Handle
  610. {$IFDEF WIN32}
  611.     else hIcon := INVALID_HANDLE_VALUE;
  612. {$ELSE}
  613.     else hIcon := 0;
  614. {$ENDIF}
  615.     StrPLCopy(szTip, GetShortHint(FHint), SizeOf(szTip) - 1);
  616.     uCallbackMessage := CM_TRAYICON;
  617.     uID := 0;
  618.   end;
  619. end;
  620.  
  621. procedure TRxTrayIcon.Activate;
  622. var
  623.   Ico: TIcon;
  624. begin
  625.   Deactivate;
  626.   Ico := GetActiveIcon;
  627.   if (Ico <> nil) and not Ico.Empty then begin
  628.     FClicked := [];
  629.     UpdateNotifyData;
  630.     FAdded := Shell_NotifyIcon(NIM_ADD, @FIconData);
  631.     if (GetShortHint(FHint) = '') and FAdded then
  632.       Shell_NotifyIcon(NIM_MODIFY, @FIconData);
  633. {$IFDEF USE_TIMER}
  634.     if Animated then FTimer.Enabled := True;
  635. {$ELSE}
  636.     if Animated then
  637.       while FTimer.Suspended do FTimer.Resume;
  638. {$ENDIF}
  639.   end;
  640. end;
  641.  
  642. procedure TRxTrayIcon.Deactivate;
  643. begin
  644.   Shell_NotifyIcon(NIM_DELETE, @FIconData);
  645.   FAdded := False;
  646.   FClicked := [];
  647. {$IFDEF USE_TIMER}
  648.   if Animated then FTimer.Enabled := False;
  649. {$ELSE}
  650.   if Animated and not FTimer.Suspended then FTimer.Suspend;
  651. {$ENDIF}
  652. end;
  653.  
  654. procedure TRxTrayIcon.ChangeIcon;
  655. var
  656.   Ico: TIcon;
  657. begin
  658.   if (FIconList = nil) or (FIconList.Count = 0) then SetAnimated(False);
  659.   if FAdded then begin
  660.     Ico := GetActiveIcon;
  661.     if (Ico <> nil) and not Ico.Empty then begin
  662.       UpdateNotifyData;
  663.       Shell_NotifyIcon(NIM_MODIFY, @FIconData);
  664.     end
  665.     else Deactivate;
  666.   end
  667.   else begin
  668.     if ((csDesigning in ComponentState) and FShowDesign) or
  669.       (not (csDesigning in ComponentState) and FActive) then Activate;
  670.   end;
  671. end;
  672.  
  673. procedure TRxTrayIcon.MouseMove(Shift: TShiftState; X, Y: Integer);
  674. begin
  675.   if Assigned(FOnMouseMove) then FOnMouseMove(Self, Shift, X, Y);
  676. end;
  677.  
  678. procedure TRxTrayIcon.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  679. begin
  680.   if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
  681. end;
  682.  
  683. procedure TRxTrayIcon.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  684. begin
  685.   if Assigned(FOnMouseUp) then FOnMouseUp(Self, Button, Shift, X, Y);
  686. end;
  687.  
  688. procedure TRxTrayIcon.DblClick;
  689. begin
  690.   if not CheckDefaultMenuItem and Assigned(FOnDblClick) then
  691.     FOnDblClick(Self);
  692. end;
  693.  
  694. procedure TRxTrayIcon.DoClick(Button: TMouseButton; Shift: TShiftState;
  695.   X, Y: Integer);
  696. begin
  697.   if (Button = mbRight) and CheckMenuPopup(X, Y) then Exit;
  698.   if Assigned(FOnClick) then FOnClick(Self, Button, Shift, X, Y);
  699. end;
  700.  
  701. procedure TRxTrayIcon.WndProc(var Message: TMessage);
  702.  
  703.   function GetShiftState: TShiftState;
  704.   begin
  705.     Result := [];
  706.     if GetKeyState(VK_SHIFT) < 0 then Include(Result, ssShift);
  707.     if GetKeyState(VK_CONTROL) < 0 then Include(Result, ssCtrl);
  708.     if GetKeyState(VK_MENU) < 0 then Include(Result, ssAlt);
  709.   end;
  710.  
  711. var
  712.   P: TPoint;
  713.   Shift: TShiftState;
  714. begin
  715.   try
  716.     with Message do
  717.       if (Msg = CM_TRAYICON) and Self.FEnabled then begin
  718.         case lParam of
  719.           WM_LBUTTONDBLCLK:
  720.             begin
  721.               DblClick;
  722.               GetCursorPos(P);
  723.               MouseDown(mbLeft, GetShiftState + [ssDouble], P.X, P.Y);
  724.             end;
  725.           WM_RBUTTONDBLCLK:
  726.             begin
  727.               GetCursorPos(P);
  728.               MouseDown(mbRight, GetShiftState + [ssDouble], P.X, P.Y);
  729.             end;
  730.           WM_MBUTTONDBLCLK:
  731.             begin
  732.               GetCursorPos(P);
  733.               MouseDown(mbMiddle, GetShiftState + [ssDouble], P.X, P.Y);
  734.             end;
  735.           WM_MOUSEMOVE:
  736.             begin
  737.               GetCursorPos(P);
  738.               MouseMove(GetShiftState, P.X, P.Y);
  739.             end;
  740.           WM_LBUTTONDOWN:
  741.             begin
  742.               GetCursorPos(P);
  743.               MouseDown(mbLeft, GetShiftState + [ssLeft], P.X, P.Y);
  744.               Include(FClicked, mbLeft);
  745.             end;
  746.           WM_LBUTTONUP:
  747.             begin
  748.               Shift := GetShiftState + [ssLeft];
  749.               GetCursorPos(P);
  750.               if mbLeft in FClicked then begin
  751.                 Exclude(FClicked, mbLeft);
  752.                 DoClick(mbLeft, Shift, P.X, P.Y);
  753.               end;
  754.               MouseUp(mbLeft, Shift, P.X, P.Y);
  755.             end;
  756.           WM_RBUTTONDOWN:
  757.             begin
  758.               GetCursorPos(P);
  759.               MouseDown(mbRight, GetShiftState + [ssRight], P.X, P.Y);
  760.               Include(FClicked, mbRight);
  761.             end;
  762.           WM_RBUTTONUP:
  763.             begin
  764.               Shift := GetShiftState + [ssRight];
  765.               GetCursorPos(P);
  766.               if mbRight in FClicked then begin
  767.                 Exclude(FClicked, mbRight);
  768.                 DoClick(mbRight, Shift, P.X, P.Y);
  769.               end;
  770.               MouseUp(mbRight, Shift, P.X, P.Y);
  771.             end;
  772.           WM_MBUTTONDOWN:
  773.             begin
  774.               GetCursorPos(P);
  775.               MouseDown(mbMiddle, GetShiftState + [ssMiddle], P.X, P.Y);
  776.             end;
  777.           WM_MBUTTONUP:
  778.             begin
  779.               GetCursorPos(P);
  780.               MouseUp(mbMiddle, GetShiftState + [ssMiddle], P.X, P.Y);
  781.             end;
  782.         end;
  783.       end
  784.       else Result := DefWindowProc(FHandle, Msg, wParam, lParam);
  785.   except
  786.     Application.HandleException(Self);
  787.   end;
  788. end;
  789.  
  790. end.