-
Notifications
You must be signed in to change notification settings - Fork 2
/
TrayIcon.pas
310 lines (281 loc) · 8.33 KB
/
TrayIcon.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
unit TrayIcon;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, AppEvnts, Forms,
ShellAPI, Graphics, Menus;
const
TI_MESSAGE = WM_USER + 1;
type
TWhatShow = (ShIcon, ShForm, ShApplication, ShTask); //Task=Form+App
TTrayIcon = class(TComponent)//TCustomApplicationEvents)
private
FWindow: HWnd;
FForm: TForm;
FIconVisible: Boolean;
FDestroying: Boolean;
FIconData: TNotifyIconData;
FNT351: Boolean;
FTip: String;
FIcon: TIcon;
FPopupMenu: TPopupMenu;
FShowIcon: Boolean;
FShowTip: Boolean;
FRespondMouse: Boolean;
FOnClick: TMouseEvent;
FOnDblClick: TNotifyEvent;
FFormVisible: Boolean;
FAppVisible: Boolean;
FMinimiseToTray: Boolean;
procedure IconChanged(Sender: TObject);
procedure SendCancelMode;
procedure SetTip(const Value: String);
procedure SetIcon(const Value: TIcon);
procedure SetFlags(const Index: Integer; const Value: Boolean);
procedure SendTrayMessage(Msg: DWORD);
procedure SetPopupMenu(const Value: TPopupMenu);//Ïðîöåäóðà óñòàíîâêè/óäàëåíèÿ/ìîäèôèêàöèè èêîíêè
function CheckMenuPopup(X, Y: Integer): Boolean;
function CheckDefaultMenuItem: Boolean;
procedure SetMinimiseToTray(const Value: Boolean);
protected
procedure WndProc(var Message: TMessage);
procedure Loaded; override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure DoClick(Button: TMouseButton); virtual;
procedure DoDblClick; virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure ShowX(const Index: TWhatShow; const Value: Boolean);
published
property Tip: String read FTip write SetTip;
property Icon: TIcon read FIcon write SetIcon;
property NIF_MESSAGE: Boolean index 0 read FRespondMouse write SetFlags default True;
property NIF_ICON: Boolean index 1 read FShowIcon write SetFlags default True;
property NIF_TIP: Boolean index 2 read FShowTip write SetFlags default True;
property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
property OnClick: TMouseEvent read FOnClick write FOnClick;
property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
property PForm: TForm read FForm;
property IconVisible: Boolean index ShIcon read FIconVisible write ShowX;
property FormVisible: Boolean index ShForm read FFormVisible write ShowX;
property AppVisible: Boolean index ShApplication read FAppVisible write ShowX;
// property MinimiseToTray: Boolean read FMinimiseToTray write SetMinimiseToTray;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TTrayIcon]);
end;
{ TTrayIcon }
function TTrayIcon.CheckDefaultMenuItem: Boolean;
Var
i: Integer;
begin
Result:=False;
If not (csDesigning in ComponentState) and IconVisible and
(PopupMenu <> nil) and (PopupMenu.Items <> nil) Then
For i:=0 to PopupMenu.Items.Count - 1 do
If PopupMenu.Items[I].Default Then
begin
PopupMenu.Items[I].Click;
Result:=True;
Break;
end;
end;
function TTrayIcon.CheckMenuPopup(X, Y: Integer): Boolean;
begin
Result:=False;
If not (csDesigning in ComponentState) and IconVisible and
(PopupMenu <> nil) and PopupMenu.AutoPopup Then
begin
PopupMenu.PopupComponent:=Self;
SendCancelMode;
SetForegroundWindow(FWindow);
Try
PopupMenu.Popup(X, Y);
Finally
SetForegroundWindow(FWindow);
end;
Result:=True;
end;
end;
constructor TTrayIcon.Create(AOwner: TComponent);
//Ðåêóðñèâíàÿ ô-èÿ ïîèñêà ôîðìû, íà êîòîðîé ëåæèò êîìïîíåíò.
function FindForm(Component: TComponent): TForm;
Var
OwnerCmpt: TComponent;
begin
OwnerCmpt:=Component.Owner;
If (OwnerCmpt <> nil) Then
begin
If OwnerCmpt.ClassParent = TForm Then
begin
(OwnerCmpt as TForm).HandleNeeded;
Result:=OwnerCmpt as TForm;
end
Else
Result:=FindForm(OwnerCmpt);
end
Else
Result:=nil;
end;
begin
Inherited;
FNT351:=(Win32MajorVersion <= 3) and (Win32Platform = VER_PLATFORM_WIN32_NT);
FIcon:=TIcon.Create;
FIcon.OnChange:=IconChanged;
FWindow:=Classes.AllocateHWnd(WndProc);
FForm:=FindForm(Self);
NIF_MESSAGE:=True;
NIF_ICON:=True;
NIF_TIP:=True;
With FIconData do
begin
cbSize:=SizeOf(FIconData);
Wnd:=FWindow;
uID:=UINT(Self);
uCallbackMessage:=TI_MESSAGE;
end;
end;
destructor TTrayIcon.Destroy;
begin
FDestroying:=True;
If IconVisible Then
SendTrayMessage(NIM_DELETE);
FIcon.Free;
Classes.DeallocateHWnd(FWindow);
Inherited;
end;
procedure TTrayIcon.DoClick(Button: TMouseButton);
var
MousePos: TPoint;
begin
GetCursorPos(MousePos);
If (Button = mbRight) and CheckMenuPopup(MousePos.X, MousePos.Y) Then
Exit;
If Assigned(FOnClick) Then
FOnClick(Self, Button, [], MousePos.X, MousePos.Y);
end;
procedure TTrayIcon.DoDblClick;
begin
if (not CheckDefaultMenuItem) and Assigned(FOnDblClick) then
FOnDblClick(Self);
end;
procedure TTrayIcon.IconChanged(Sender: TObject);
begin
FIconData.hIcon:=FIcon.Handle;
If IconVisible Then
SendTrayMessage(NIM_MODIFY);
end;
procedure TTrayIcon.Loaded;
begin
Inherited Loaded;
If FIcon.Empty then //Åñëè èêîíêà íå çàäàíà - áåðåì èêîíêó ïðèëîæåíèÿ
FIcon.Assign(Application.Icon);
FIconData.hIcon:=FIcon.Handle;
If IconVisible then
SendTrayMessage(NIM_MODIFY);
If not (csDesigning in ComponentState) and (FForm <> nil) then
begin
ShowWindow(Application.Handle, SW_SHOW*Integer(FAppVisible));
ShowWindow(FForm.Handle, SW_SHOW*Integer(FFormVisible));
Application.ShowMainForm:=FFormVisible;
FForm.Visible:=FFormVisible;
end;
end;
procedure TTrayIcon.Notification(AComponent: TComponent;
Operation: TOperation);
begin
Inherited Notification(AComponent, Operation);
If (Operation = opRemove) and (AComponent = PopupMenu) then
PopupMenu:=nil;
end;
procedure TTrayIcon.SendCancelMode;
var
F: TForm;
begin
If not ((csDestroying in ComponentState) or FDestroying) then
begin
F:=Screen.ActiveForm;
If F = nil Then
F:=Application.MainForm;
If F <> nil Then
F.SendCancelMode(nil);
end;
end;
procedure TTrayIcon.SendTrayMessage(Msg: DWORD);
begin
If not FNT351 and not (csDesigning in ComponentState) then
Shell_NotifyIcon(Msg, @FIconData);
end;
procedure TTrayIcon.SetFlags(const Index: Integer; const Value: Boolean);
begin
Case Index of
0: FRespondMouse:=Value;
1: FShowIcon:=Value;
2: FShowTip:=Value;
End;
FIconData.uFlags:=Ord(FRespondMouse) or (Ord(FShowIcon)*2) or (Ord(FShowTip)*4);
If IconVisible Then
begin //NIM_MODIFY ÍÅ ìåíÿåò ôëàãè!!! (uFlags), ò.å. íåëüçÿ óáðàòü èêîíêó èëè õèíò åñëè îíè óæå åñòü!
SendTrayMessage(NIM_DELETE);
SendTrayMessage(NIM_ADD);
end
end;
procedure TTrayIcon.SetIcon(const Value: TIcon);
begin
FIcon.Assign(Value);
end;
procedure TTrayIcon.SetMinimiseToTray(const Value: Boolean);
begin
FMinimiseToTray:=Value;
end;
procedure TTrayIcon.SetPopupMenu(const Value: TPopupMenu);
begin
FPopupMenu:=Value;
If Value <> nil Then
Value.FreeNotification(Self);
end;
procedure TTrayIcon.SetTip(const Value: String);
begin
FTip:=Value;
StrPLCopy(FIconData.szTip, GetShortHint(Value), SizeOf(FIconData.szTip) - 1);
If IconVisible Then
SendTrayMessage(NIM_MODIFY);
end;
procedure TTrayIcon.ShowX(const Index: TWhatShow; const Value: Boolean);
begin
Case Index of
ShIcon: begin
SendTrayMessage(NIM_DELETE*Integer(not Value));
FIconVisible:=Value;
end;
ShForm: FFormVisible:=Value;
ShApplication: FAppVisible:=Value;
End;
If not (csDesigning in ComponentState) and (FForm <> nil) then
begin
ShowWindow(FForm.Handle, SW_SHOW*Integer(FFormVisible));
FForm.Visible:=FFormVisible;
ShowWindow(Application.Handle, SW_SHOW*Integer(FAppVisible));
Application.ShowMainForm:=False;
end;
end;
procedure TTrayIcon.WndProc(var Message: TMessage);
begin
Try
With Message do
If Msg = TI_MESSAGE Then
Case Message.lParam of
WM_LBUTTONDBLCLK: DoDblClick;
WM_LBUTTONUP: DoClick(mbLeft);
WM_RBUTTONUP: DoClick(mbRight);
end
Else
Result:=DefWindowProc(FWindow, Msg, wParam, lParam);
except
Application.HandleException(Self);
end;
end;
end.