1{%mainunit customdrawnwsextctrls.pas} 2 3type 4 5 { TX11TrayIconHandle } 6 7 TX11TrayIconHandle = class(TObject) 8 private 9 //plug: PGtkWidget; 10 //drawingarea: PGtkWidget; 11 fDisplay: PDisplay; 12 fcanvas: TCanvas; 13 fWindow: TWindow; 14 fScreenID: longint; 15 fTrayParent: TWindow; 16 //fOwner: TComponent; 17 fEmbedded: Boolean; 18 //fMsgCount: Integer; 19 fTrayIcon: TCustomTrayIcon; 20 function GetCanvas: TCanvas; 21 procedure PaintForm(Sender: TObject); 22 function Send_Message(window: TWindow; msg: Integer;data1, data2,data3: Integer): boolean; 23 public 24 constructor create; 25 destructor Destroy; override; 26 procedure CreateForm(id: Integer); 27 function GetPosition: TPoint; 28 procedure Hide; 29 procedure SetEmbedded; 30 function TrayParent(UseCachedValue: Boolean = True): TWindow; 31 public 32 property Canvas: TCanvas read GetCanvas; 33 end; 34 35const 36 SYSTEM_TRAY_REQUEST_DOCK = 0; 37 SYSTEM_TRAY_BEGIN_MESSAGE = 1; 38 SYSTEM_TRAY_CANCEL_MESSAGE = 2; 39 40// Temp ErrorHandler 41function TempX11ErrorHandler(Display:PDisplay; ErrorEv:PXErrorEvent):longint;cdecl; 42begin 43 DebugLn('[TX11TrayIconHandle] Error: ' + IntToStr(ErrorEv^.error_code)); 44 Result:=0; 45end; 46 47function TX11TrayIconHandle.GetCanvas: TCanvas; 48begin 49 Result := nil; 50{ if Assigned(FCanvas) then Exit(FCanvas); 51 52 Result := TCanvas.Create; 53 Result.Handle:= GetDC(HWND(drawingarea)); 54 FCanvas := Result;} 55end; 56 57{function TX11TrayIconHandle.NotifyExpose(Event: PGdkEventExpose; 58 Widget: PGtkWidget): Boolean; cdecl; 59begin 60 Result := False; 61 62 PaintForm(fTrayIcon); 63end; 64 65function TGtk1TrayIconHandle.NotifyMouseMove(Event: PGdkEventMotion; 66 Widget: PGtkWidget): Boolean; cdecl; 67begin 68 Result := False; 69 70 if Assigned(fTrayIcon.OnMouseMove) then 71 fTrayIcon.OnMouseMove(fTrayIcon, [], Trunc(Event^.x), Trunc(Event^.y)); 72end; 73 74function TGtk1TrayIconHandle.NotifyMouseDown(Event: PGdkEventButton; 75 Widget: PGtkWidget): Boolean; cdecl; 76var 77 Button: TMouseButton; 78begin 79 Result := False; 80 81 case Event^.button of 82 GDK_RIGHTBUTTON: Button := mbRight; 83 GDK_MIDDLEBUTTON: Button := mbMiddle; 84 GDK_LEFTBUTTON: Button := mbLeft; 85 end; 86 87 if Assigned(fTrayIcon.OnMouseDown) then 88 fTrayIcon.OnMouseDown(fTrayIcon, Button, [], Trunc(Event^.x), Trunc(Event^.y)); 89end; 90 91function TGtk1TrayIconHandle.NotifyMouseUp(Event: PGdkEventButton; 92 Widget: PGtkWidget): Boolean; cdecl; 93var 94 Button: TMouseButton; 95begin 96 Result := False; 97 98 case Event^.button of 99 3: Button := mbRight; 100 2: Button := mbMiddle; 101 1: Button := mbLeft; 102 end; 103 104 if Button = mbLeft then 105 case gdk_event_get_type(Event) of 106 GDK_BUTTON_PRESS: 107 if Assigned(fTrayIcon.OnClick) then 108 fTrayIcon.OnClick(fTrayIcon); 109 GDK_2BUTTON_PRESS: 110 if Assigned(fTrayIcon.OnDblClick) then 111 fTrayIcon.OnDblClick(fTrayIcon); 112 end; 113 114 { Just using GetPosition to get the screen position and then add 115 Event^.x and Event^.y to it won't work. It seams that this will 116 cause a small difference with Mouse.CursorPos, and using 117 TPopupMenu.PopUp will result in a wrong position for the menu } 118 if (Button = mbRight) and (fTrayIcon.PopUpMenu <> nil) then 119 fTrayIcon.PopUpMenu.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); 120 121 if Assigned(fTrayIcon.OnMouseUp) then 122 fTrayIcon.OnMouseUp(fTrayIcon, Button, [], Trunc(Event^.x), Trunc(Event^.y)); 123end; } 124 125{******************************************************************* 126* TX11TrayIconHandle.Send_Message () 127* 128* DESCRIPTION: Sends a message to the X client 129* 130*******************************************************************} 131function TX11TrayIconHandle.Send_Message(window: TWindow; msg: Integer;data1, data2,data3: Integer): boolean; 132var 133 Ev: TXEvent; 134// fmt: Integer; 135begin 136 FillChar(Ev, SizeOf(TXEvent), $0); 137 138 ev.xclient._type := ClientMessage; 139 ev.xclient.window := window; 140 ev.xclient.message_type := XInternAtom (fDisplay, '_NET_SYSTEM_TRAY_OPCODE', False ); 141 ev.xclient.format := 32; 142 ev.xclient.data.l[0] := CurrentTime; 143 ev.xclient.data.l[1] := msg; 144 ev.xclient.data.l[2] := data1; 145 ev.xclient.data.l[3] := data2; 146 ev.xclient.data.l[4] := data3; 147 148 XSendEvent(fDisplay, fTrayParent, False, NoEventMask, @ev); 149 XSync(fDisplay, False); 150 Result := false;//(untrap_errors() = 0); 151end; 152 153constructor TX11TrayIconHandle.create; 154begin 155 inherited create; 156end; 157 158function TX11TrayIconHandle.TrayParent(UseCachedValue: Boolean = True): TWindow; 159var 160 buf: array[0..32] of char; 161 selection_atom: TAtom; 162begin 163 if (fTrayParent <> 0) and UseCachedValue then 164 Exit(fTrayParent); 165 fDisplay := CDWidgetset.FDisplay; 166 fScreenID := CDWidgetSet.FScreen; 167 168 buf := PChar('_NET_SYSTEM_TRAY_S' + IntToStr(fScreenID)); 169 selection_atom := XInternAtom(fDisplay, buf, false); 170 fTrayParent := XGetSelectionOwner(fDisplay, selection_atom); 171 172 Result := fTrayParent; 173end; 174 175destructor TX11TrayIconHandle.Destroy; 176begin 177 if Assigned(FCanvas) and FCanvas.HandleAllocated then 178 begin 179 //ReleaseDC(HWND(drawingarea), fcanvas.Handle); 180 FCanvas.Free; 181 end; 182{ if Assigned(drawingarea) then 183 begin 184 g_signal_handlers_destroy(G_OBJECT(drawingarea)); 185 gtk_widget_destroy(drawingarea); 186 end; 187 if Assigned(plug) then 188 gtk_widget_destroy(plug);} 189 190 inherited Destroy; 191end; 192 193{******************************************************************* 194* TX11TrayIconHandle.SetEmbedded () 195* 196* DESCRIPTION: 197* 198*******************************************************************} 199procedure TX11TrayIconHandle.SetEmbedded; 200var 201 old_error: TXErrorHandler; 202begin 203 fEmbedded := False; 204 if TrayParent = None then 205 Exit; 206 207{ // so we have a TWindow 208 gtk_widget_realize(plug);} 209 210 old_error := XSetErrorHandler(@TempX11ErrorHandler); 211 Sleep(80); 212 xsync(fdisplay,true); 213 214 XSelectInput(fDisplay, TrayParent, StructureNotifyMask); 215 216 //fWindow := GDK_WINDOW_XWINDOW (Pointer(PGtkWidget(plug)^.window)); 217 218 Send_Message(TrayParent, SYSTEM_TRAY_REQUEST_DOCK, fWindow, 0, 0); 219 220 //GTK_WIDGET_SET_FLAGS(plug,GTK_VISIBLE); 221 //GTK_WIDGET_SET_FLAGS(plug,GTK_MAPPED); 222 223 //gtk_widget_show_all(plug); 224 225 XSetErrorHandler(old_error); 226 fEmbedded:=True; 227end; 228 229procedure TX11TrayIconHandle.Hide; 230begin 231 //gtk_widget_hide_all(drawingarea); 232 fEmbedded := False; 233end; 234 235{******************************************************************* 236* TX11TrayIconHandle.CreateForm () 237* 238* DESCRIPTION: 239* 240*******************************************************************} 241procedure TX11TrayIconHandle.CreateForm(id: Integer); 242begin 243{ plug := gtk_plug_new(0); 244 drawingarea := gtk_event_box_new; 245 246 gtk_container_add(GTK_CONTAINER(plug), drawingarea); 247 248 //gtk_widget_add_events(drawingarea, GDK_MOTION_NOTIFY); 249 250 gtk_signal_connect_object_after(G_OBJECT(drawingarea), 'expose-event', TGtkSignalFunc(@TGtk1TrayIconHandle.NotifyExpose), G_OBJECT(Self)); 251 gtk_signal_connect_object(G_OBJECT(drawingarea), 'motion-notify-event', TGtkSignalFunc(@TGtk1TrayIconHandle.NotifyMouseMove), G_OBJECT(Self)); 252 gtk_signal_connect_object(G_OBJECT(drawingarea), 'button-press-event', TGtkSignalFunc(@TGtk1TrayIconHandle.NotifyMouseDown), G_OBJECT(Self)); 253 gtk_signal_connect_object(G_OBJECT(drawingarea), 'button-release-event', TGtkSignalFunc(@TGtk1TrayIconHandle.NotifyMouseUp), G_OBJECT(Self));} 254 255 fEmbedded := False; 256 GetCanvas; 257end; 258 259{******************************************************************* 260* TX11TrayIconHandle.GetPosition () 261* 262* DESCRIPTION: Returns the (x, y) position of the icon on the screen 263* 264*******************************************************************} 265function TX11TrayIconHandle.GetPosition: TPoint; 266{var 267 WindowHandle: PGDKWindow;} 268begin 269 Result := Point(0, 0); 270 271{ if not Assigned(plug) then Exit; 272 273 WindowHandle := plug^.window; 274 275 if not Assigned(WindowHandle) then Exit; 276 277 gdk_window_get_origin(WindowHandle, @Result.X, @Result.Y);} 278end; 279 280{******************************************************************* 281* TX11TrayIconHandle.PaintForm () 282* 283* DESCRIPTION: Paint method of the Icon Window 284* 285*******************************************************************} 286procedure TX11TrayIconHandle.PaintForm(Sender: TObject); 287begin 288 if fTrayIcon.ShowIcon then Canvas.Draw(0, 0, fTrayIcon.Icon); 289 290 if Assigned(fTrayIcon.OnPaint) then fTrayIcon.OnPaint(Self); 291end; 292 293{******************************************************************* 294* TCDWSCustomTrayIcon.Hide () 295* 296* DESCRIPTION: Hides the main tray icon of the program 297* 298* PARAMETERS: None 299* 300* RETURNS: True if sucessfull, otherwise False 301* 302*******************************************************************} 303class function TCDWSCustomTrayIcon.Hide(const ATrayIcon: TCustomTrayIcon): Boolean; 304var 305 TrayIconHandle: TX11TrayIconHandle; 306begin 307 Result := False; 308 309 TrayIconHandle := TX11TrayIconHandle(ATrayIcon.Handle); 310 TrayIconHandle.Free; 311 312 ATrayIcon.Handle := 0; 313 314 Result := True; 315end; 316 317{******************************************************************* 318* TCDWSCustomTrayIcon.Show () 319* 320* DESCRIPTION: Shows the main tray icon of the program 321* 322* PARAMETERS: None 323* 324* RETURNS: True if sucessfull, otherwise False 325* 326*******************************************************************} 327class function TCDWSCustomTrayIcon.Show(const ATrayIcon: TCustomTrayIcon): Boolean; 328var 329 TrayIconHandle: TX11TrayIconHandle; 330begin 331 Result := False; 332 333 TrayIconHandle := TX11TrayIconHandle.Create; 334 TrayIconHandle.fTrayIcon := ATrayIcon; 335 336 ATrayIcon.Handle := PtrInt(TrayIconHandle); 337 338 TrayIconHandle.CreateForm(0); 339 TrayIconHandle.SetEmbedded; 340 341 Result := True; 342end; 343 344{******************************************************************* 345* TCDWSCustomTrayIcon.InternalUpdate () 346* 347* DESCRIPTION: Makes modifications to the Icon while running 348* i.e. without hiding it and showing again 349*******************************************************************} 350class procedure TCDWSCustomTrayIcon.InternalUpdate(const ATrayIcon: TCustomTrayIcon); 351{var 352 TrayIconHandle: TGtk1TrayIconHandle;} 353begin 354{ TrayIconHandle := TGtk1TrayIconHandle(ATrayIcon.Handle); 355 356 if not Assigned(TrayIconHandle) then Exit;} 357end; 358 359class function TCDWSCustomTrayIcon.ShowBalloonHint( 360 const ATrayIcon: TCustomTrayIcon): Boolean; 361begin 362 Result := False; 363end; 364 365{******************************************************************* 366* TCDWSCustomTrayIcon.GetPosition () 367* 368* DESCRIPTION: Returns the position of the tray icon on the display. 369* This function is utilized to show message boxes near 370* the icon 371* 372*******************************************************************} 373class function TCDWSCustomTrayIcon.GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint; 374var 375 TrayIconHandle: TX11TrayIconHandle; 376begin 377 Result := Point(0, 0); 378 379 TrayIconHandle := TX11TrayIconHandle(ATrayIcon.Handle); 380 381 if not Assigned(TrayIconHandle) then Exit; 382 383 Result := TrayIconHandle.GetPosition; 384end; 385 386{class function TGtkWSCustomTrayIcon.GetCanvas(const ATrayIcon: TCustomTrayIcon): TCanvas; 387var 388 TrayIconHandle: TX11TrayIconHandle; 389begin 390 TrayIconHandle := TX11TrayIconHandle(ATrayIcon.Handle); 391 392 if not Assigned(TrayIconHandle) then Exit(ATrayIcon.Icon.Canvas); 393 394 Result := TrayIconHandle.Canvas; 395end; } 396 397