diff --git a/lcl/interfaces/gtk2/gtk2trayicon.inc b/lcl/interfaces/gtk2/gtk2trayicon.inc index 722a4a7113..30ad51bc60 100644 --- a/lcl/interfaces/gtk2/gtk2trayicon.inc +++ b/lcl/interfaces/gtk2/gtk2trayicon.inc @@ -1,452 +1,458 @@ -{%MainUnit gtk2wsextctrls.pp} -{ - gtk2trayicon.inc - - ***************************************************************************** - * * - * See the file COPYING.modifiedLGPL.txt, included in this distribution, * - * for details about the copyright. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * * - ***************************************************************************** - - Authors: Felipe Monteiro de Carvalho and Andrew Haines - - Special thanks for: Danny Milosavljevic and the Lazarus Team - - Gtk2 specific code. -} - -{ TGtk2WSCustomTrayIcon } - -type - TGtk2TrayIconHandle = class - private - plug: PGtkWidget; - DrawingArea: PGtkWidget; - fDisplay: PDisplay; - fWindow: TWindow; - fScreen: PScreen; - fScreenID: longint; - fTrayParent: TWindow; - Tips: PGtkTooltips; - fEmbedded: Boolean; - fTrayIcon: TCustomTrayIcon; - function SendMessage(window: TWindow; msg: Integer; data1, data2, data3: Integer): Boolean; - public - constructor Create(const wsTrayIcon: TCustomTrayIcon); - destructor Destroy; override; - procedure SetEmbedded; - end; - -const - SYSTEM_TRAY_REQUEST_DOCK = 0; - SYSTEM_TRAY_BEGIN_MESSAGE = 1; - SYSTEM_TRAY_CANCEL_MESSAGE = 2; - -var - XError: Integer; -{******************************************************************* -* TempX11ErrorHandler () -* -* DESCRIPTION: Temp ErrorHandler -* -* PARAMETERS: ? -* -* RETURNS: ? -* -*******************************************************************} -function TempX11ErrorHandler(Display:PDisplay; ErrorEv:PXErrorEvent):longint;cdecl; -begin - XError := ErrorEv^.error_code; - WriteLn('Error: ' + IntToStr(XError)); - Result:=0; -end; - -{******************************************************************* -* TGtk2TrayIconHandle.Send_Message () -* -* DESCRIPTION: Sends a message to the X client -* -* PARAMETERS: None -* -* RETURNS: Nothing -* -*******************************************************************} -function TGtk2TrayIconHandle.SendMessage(window: TWindow; msg: Integer; data1, data2, data3: Integer): Boolean; -var - Ev: TXEvent; -begin - FillChar(Ev, SizeOf(TXEvent), 0); - - ev.xclient._type := ClientMessage; - ev.xclient.window := window; - ev.xclient.message_type := XInternAtom (fDisplay, '_NET_SYSTEM_TRAY_OPCODE', False); - ev.xclient.format := 32; - ev.xclient.data.l[0] := CurrentTime; - ev.xclient.data.l[1] := msg; - ev.xclient.data.l[2] := data1; - ev.xclient.data.l[3] := data2; - ev.xclient.data.l[4] := data3; - - XError := 0; - XSendEvent(fDisplay, fTrayParent, False, NoEventMask, @ev); - XSync(fDisplay, False); - Result := XError = 0; - XError := 0; -end; - -{******************************************************************* -* TGtk2TrayIconHandle.SetEmbedded () -* -* DESCRIPTION: Docks the GtkPlug into the system tray -* -* PARAMETERS: None -* -* RETURNS: Nothing -* -*******************************************************************} -procedure TGtk2TrayIconHandle.SetEmbedded; -var - old_error: TXErrorHandler; - buf: array [0..32] of char; - selection_atom : TAtom; -begin - if fEmbedded then - Exit; - old_error := XSetErrorHandler(@TempX11ErrorHandler); - - xsync(fdisplay,true); - buf := PChar('_NET_SYSTEM_TRAY_S' + IntToStr(fScreenID)); - selection_atom := XInternAtom(fDisplay, buf, false); - XGrabServer(fDisplay); - - fTrayParent := XGetSelectionOwner(fDisplay, selection_atom); - if fTrayParent <> None then - begin - XSelectInput(fDisplay, fTrayParent, StructureNotifyMask); - end; - - XUngrabServer(fDisplay); - XFlush(fDisplay); - if fTrayParent <> None then - fEmbedded := SendMessage(fTrayParent, SYSTEM_TRAY_REQUEST_DOCK, fWindow, 0, 0); - - XSetErrorHandler(old_error); -end; - -{******************************************************************* -* realize_cb () -* -* DESCRIPTION: Callback function for the realize signal -* Sets the systray icon after the widget is realized -* -* PARAMETERS: None -* -* RETURNS: Nothing -* -*******************************************************************} -procedure realize_cb(widget: PGtkWidget; user_data: gpointer); cdecl; -var - wsTrayIcon: TCustomTrayIcon absolute user_data; -begin -{$ifdef HasGdk2X} - with TGtk2TrayIconHandle(wsTrayIcon.Handle) do begin - fDisplay := GDK_WINDOW_XDISPLAY(plug^.window); - fWindow := GDK_WINDOW_XWINDOW(plug^.window); - -{ Doesn´t work - - gdk_screen := gtk_widget_get_screen(plug); - fScreen := GDK_SCREEN_XSCREEN(gdk_screen); // get the real screen} - - fScreen := XDefaultScreenOfDisplay(fDisplay); - fScreenID := XScreenNumberOfScreen(fScreen); // and it's number - SetEmbedded; - end; -{$endif} -end; - -{******************************************************************* -* button_release_cb () -* -* DESCRIPTION: Callback function for Mouse Click -* -* PARAMETERS: None -* -* RETURNS: Nothing -* -*******************************************************************} -function button_release_cb(widget: PGtkWidget; event: PGdkEventButton; - user_data: gpointer): gboolean; cdecl; -var - vwsTrayIcon: TCustomTrayIcon; -begin - vwsTrayIcon := TCustomTrayIcon(user_data); - - Result := False; - - case event^.button of - 1: - begin - if Assigned(vwsTrayIcon.OnClick) then vwsTrayIcon.OnClick(vwsTrayIcon); - if Assigned(vwsTrayIcon.OnMouseUp) then - vwsTrayIcon.OnMouseUp(vwsTrayIcon, mbLeft, [], Round(event^.X), Round(event^.Y)); - end; - - 2: if Assigned(vwsTrayIcon.OnMouseUp) then - vwsTrayIcon.OnMouseUp(vwsTrayIcon, mbMiddle, [], Round(event^.X), Round(event^.Y)); - - 3: - begin - if Assigned(vwsTrayIcon.OnMouseUp) then - vwsTrayIcon.OnMouseUp(vwsTrayIcon, mbRight, [], Round(event^.X), Round(event^.Y)); - if Assigned(vwsTrayIcon.PopUpMenu) then - vwsTrayIcon.PopUpMenu.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); - end; - end; -end; - -{******************************************************************* -* button_press_cb () -* -* DESCRIPTION: Callback function for Mouse Click -* -* PARAMETERS: None -* -* RETURNS: Nothing -* -*******************************************************************} -function button_press_cb(widget: PGtkWidget; event: PGdkEventButton; - user_data: gpointer): gboolean; cdecl; -var - vwsTrayIcon: TCustomTrayIcon; -begin - vwsTrayIcon := TCustomTrayIcon(user_data); - - Result := False; - - if (event^._type = GDK_2BUTTON_PRESS) and Assigned(vwsTrayIcon.OnDblClick) then - vwsTrayIcon.OnDblClick(vwsTrayIcon) - else - begin - case event^.button of - 1: if Assigned(vwsTrayIcon.OnMouseDown) then - vwsTrayIcon.OnMouseDown(vwsTrayIcon, mbLeft, [], Round(event^.X), Round(event^.Y)); - - 2: if Assigned(vwsTrayIcon.OnMouseDown) then - vwsTrayIcon.OnMouseDown(vwsTrayIcon, mbMiddle, [], Round(event^.X), Round(event^.Y)); - - 3: if Assigned(vwsTrayIcon.OnMouseDown) then - vwsTrayIcon.OnMouseDown(vwsTrayIcon, mbRight, [], Round(event^.X), Round(event^.Y)); - end; - end; -end; - -{******************************************************************* -* popup_cb () -* -* DESCRIPTION: Callback function for the popup menu -* -* PARAMETERS: None -* -* RETURNS: Nothing -* -*******************************************************************} -function popup_cb(widget: PGtkWidget; user_data: gpointer): Boolean; cdecl; -var - vwsTrayIcon: TCustomTrayIcon; -begin - vwsTrayIcon := TCustomTrayIcon(user_data); - - Result := True; - - if Assigned(vwsTrayIcon.PopUpMenu) then - vwsTrayIcon.PopUpMenu.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); -end; - -{******************************************************************* -* motion_cb () -* -* DESCRIPTION: Callback function for the OnMouseMove event -* -* PARAMETERS: None -* -* RETURNS: Nothing -* -*******************************************************************} -function motion_cb(widget: PGtkWidget; event: PGdkEventMotion; user_data: gpointer): Boolean; cdecl; -var - vwsTrayIcon: TCustomTrayIcon; -begin - vwsTrayIcon := TCustomTrayIcon(user_data); - - Result := False; - - if Assigned(vwsTrayIcon.OnMouseMove) then - vwsTrayIcon.OnMouseMove(vwsTrayIcon, [], Round(event^.X), Round(event^.Y)); -end; - -constructor TGtk2TrayIconHandle.Create(const wsTrayIcon: TCustomTrayIcon); -begin - fTrayIcon := wsTrayIcon; - {******************************************************************* - * Creates the GtkPlug - *******************************************************************} - - plug := gtk_plug_new(0); - - Tips := gtk_tooltips_new; - - g_object_ref(Tips); - - gtk_object_sink(GTK_OBJECT(Tips)); - - gtk_tooltips_set_tip(GTK_TOOLTIPS(Tips), plug, PChar(wsTrayIcon.Hint), ''); - - {******************************************************************* - * Connects the signals - *******************************************************************} - - gtk_widget_add_events(plug, GDK_ALL_EVENTS_MASK); - - g_signal_connect(plug, 'realize', TGCallback(@realize_cb), wsTrayIcon); - - g_signal_connect(plug, 'popup-menu', TGCallback(@popup_cb), wsTrayIcon); - - g_signal_connect(plug, 'motion-notify-event', TGCallback(@motion_cb), wsTrayIcon); - - g_signal_connect(plug, 'button-press-event', TGCallback(@button_press_cb), wsTrayIcon); - - g_signal_connect(plug, 'button-release-event', TGCallback(@button_release_cb), wsTrayIcon); - - {******************************************************************* - * Draws the icon - *******************************************************************} - - with wsTrayIcon do begin - DrawingArea := gtk_image_new_from_pixbuf(PGdkPixbuf(Icon.Handle)); - gtk_widget_show(DrawingArea); - gtk_container_add(GTK_CONTAINER(plug), DrawingArea); - end; -end; - -destructor TGtk2TrayIconHandle.Destroy; -begin - gtk_widget_destroy(plug); - - plug := nil; - - g_object_unref(Tips); - - Tips := nil; -end; - -{******************************************************************* -* TGtk2WSCustomTrayIcon.Hide () -* -* DESCRIPTION: Hides the main tray icon of the program -* -* PARAMETERS: None -* -* RETURNS: True if sucessfull, otherwise False -* -*******************************************************************} -class function TGtk2WSCustomTrayIcon.Hide(const ATrayIcon: TCustomTrayIcon): Boolean; -var - TrayIconHandle: TGtk2TrayIconHandle absolute ATrayIcon.Handle; -begin - Result := False; - - { Free and nil the handle } - TrayIconHandle.Free; - TrayIconHandle := nil; - - Result := True; -end; - -{******************************************************************* -* TGtk2WSCustomTrayIcon.Show () -* -* DESCRIPTION: Shows the main tray icon of the program -* -* PARAMETERS: None -* -* RETURNS: True if sucessfull, otherwise False -* -*******************************************************************} -class function TGtk2WSCustomTrayIcon.Show(const ATrayIcon: TCustomTrayIcon): Boolean; -var - TrayIconHandle: TGtk2TrayIconHandle absolute ATrayIcon.Handle; -begin - Result := False; - - TrayIconHandle := TGtk2TrayIconHandle.Create(ATrayIcon); - {******************************************************************* - * Now shows the GtkPlug - *******************************************************************} - with TrayIconHandle do begin - gtk_widget_show(plug); - if fEmbedded then begin - Result := True; - end else - Hide(ATrayIcon); - end; -end; - -{******************************************************************* -* TGtk2WSCustomTrayIcon.InternalUpdate () -* -* DESCRIPTION: Makes modifications to the Icon while running -* i.e. without hiding it and showing again -* -* PARAMETERS: None -* -* RETURNS: Nothing -* -*******************************************************************} -class procedure TGtk2WSCustomTrayIcon.InternalUpdate(const ATrayIcon: TCustomTrayIcon); -var - TrayIconHandle: TGtk2TrayIconHandle absolute ATrayIcon.Handle; -begin - if Assigned(TrayIconHandle) then with TrayIconHandle do begin - // Updates the tooltips - if Assigned(Tips) then - gtk_tooltips_set_tip(GTK_TOOLTIPS(Tips), plug, PChar(ATrayIcon.Hint), ''); - // Updates the icon - if Assigned(DrawingArea) then begin - gtk_image_set_from_pixbuf(GTK_IMAGE(DrawingArea), PGdkPixbuf(ATrayIcon.Icon.Handle)); - end; - end; -end; - -{******************************************************************* -* TGtk2WSCustomTrayIcon.GetPosition () -* -* DESCRIPTION: Returns the position of the tray icon on the display. -* This function is utilized to show message boxes near -* the icon -* -* PARAMETERS: None -* -* RETURNS: Nothing -* -*******************************************************************} -class function TGtk2WSCustomTrayIcon.GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint; -var - TrayIconHandle: TGtk2TrayIconHandle absolute ATrayIcon.Handle; - WindowHandle: PGDKWindow; -begin - Result := Point(0, 0); - if Assigned(TrayIconHandle) then with TrayIconHandle do begin - if not Assigned(plug) then begin - WindowHandle := plug^.window; - if Assigned(WindowHandle) then - gdk_window_get_origin(WindowHandle, @Result.X, @Result.Y); - end; - end; -end; - +{%MainUnit gtk2wsextctrls.pp} +{ + gtk2trayicon.inc + + ***************************************************************************** + * * + * See the file COPYING.modifiedLGPL.txt, included in this distribution, * + * for details about the copyright. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * * + ***************************************************************************** + + Authors: Felipe Monteiro de Carvalho and Andrew Haines + + Special thanks for: Danny Milosavljevic and the Lazarus Team + + Gtk2 specific code. +} + +{ TGtk2WSCustomTrayIcon } + +type + TGtk2TrayIconHandle = class + private + plug: PGtkWidget; + DrawingArea: PGtkWidget; +{$ifdef HasGdk2X} + fDisplay: PDisplay; + fWindow: TWindow; + fScreen: PScreen; + fScreenID: longint; + fTrayParent: TWindow; +{$endif HasGdk2X} + Tips: PGtkTooltips; + fEmbedded: Boolean; + fTrayIcon: TCustomTrayIcon; +{$ifdef HasGdk2X} + function SendMessage(window: TWindow; msg: Integer; data1, data2, data3: Integer): Boolean; + procedure SetEmbedded; +{$endif HasGdk2X} + public + constructor Create(const wsTrayIcon: TCustomTrayIcon); + destructor Destroy; override; + end; + +const + SYSTEM_TRAY_REQUEST_DOCK = 0; + SYSTEM_TRAY_BEGIN_MESSAGE = 1; + SYSTEM_TRAY_CANCEL_MESSAGE = 2; + +{$ifdef HasGdk2X} +var + XError: Integer; +{******************************************************************* +* TempX11ErrorHandler () +* +* DESCRIPTION: Temp ErrorHandler +* +* PARAMETERS: ? +* +* RETURNS: ? +* +*******************************************************************} +function TempX11ErrorHandler(Display:PDisplay; ErrorEv:PXErrorEvent):longint;cdecl; +begin + XError := ErrorEv^.error_code; + WriteLn('Error: ' + IntToStr(XError)); + Result:=0; +end; + +{******************************************************************* +* TGtk2TrayIconHandle.Send_Message () +* +* DESCRIPTION: Sends a message to the X client +* +* PARAMETERS: None +* +* RETURNS: Nothing +* +*******************************************************************} +function TGtk2TrayIconHandle.SendMessage(window: TWindow; msg: Integer; data1, data2, data3: Integer): Boolean; +var + Ev: TXEvent; +begin + FillChar(Ev, SizeOf(TXEvent), 0); + + ev.xclient._type := ClientMessage; + ev.xclient.window := window; + ev.xclient.message_type := XInternAtom (fDisplay, '_NET_SYSTEM_TRAY_OPCODE', False); + ev.xclient.format := 32; + ev.xclient.data.l[0] := CurrentTime; + ev.xclient.data.l[1] := msg; + ev.xclient.data.l[2] := data1; + ev.xclient.data.l[3] := data2; + ev.xclient.data.l[4] := data3; + + XError := 0; + XSendEvent(fDisplay, fTrayParent, False, NoEventMask, @ev); + XSync(fDisplay, False); + Result := XError = 0; + XError := 0; +end; + +{******************************************************************* +* TGtk2TrayIconHandle.SetEmbedded () +* +* DESCRIPTION: Docks the GtkPlug into the system tray +* +* PARAMETERS: None +* +* RETURNS: Nothing +* +*******************************************************************} +procedure TGtk2TrayIconHandle.SetEmbedded; +var + old_error: TXErrorHandler; + buf: array [0..32] of char; + selection_atom : TAtom; +begin + if fEmbedded then + Exit; + old_error := XSetErrorHandler(@TempX11ErrorHandler); + + xsync(fdisplay,true); + buf := PChar('_NET_SYSTEM_TRAY_S' + IntToStr(fScreenID)); + selection_atom := XInternAtom(fDisplay, buf, false); + XGrabServer(fDisplay); + + fTrayParent := XGetSelectionOwner(fDisplay, selection_atom); + if fTrayParent <> None then + begin + XSelectInput(fDisplay, fTrayParent, StructureNotifyMask); + end; + + XUngrabServer(fDisplay); + XFlush(fDisplay); + if fTrayParent <> None then + fEmbedded := SendMessage(fTrayParent, SYSTEM_TRAY_REQUEST_DOCK, fWindow, 0, 0); + + XSetErrorHandler(old_error); +end; +{$endif HasGdk2X} + +{******************************************************************* +* realize_cb () +* +* DESCRIPTION: Callback function for the realize signal +* Sets the systray icon after the widget is realized +* +* PARAMETERS: None +* +* RETURNS: Nothing +* +*******************************************************************} +procedure realize_cb(widget: PGtkWidget; user_data: gpointer); cdecl; +var + wsTrayIcon: TCustomTrayIcon absolute user_data; +begin +{$ifdef HasGdk2X} + with TGtk2TrayIconHandle(wsTrayIcon.Handle) do begin + fDisplay := GDK_WINDOW_XDISPLAY(plug^.window); + fWindow := GDK_WINDOW_XWINDOW(plug^.window); + +{ Doesn´t work + + gdk_screen := gtk_widget_get_screen(plug); + fScreen := GDK_SCREEN_XSCREEN(gdk_screen); // get the real screen} + + fScreen := XDefaultScreenOfDisplay(fDisplay); + fScreenID := XScreenNumberOfScreen(fScreen); // and it's number + SetEmbedded; + end; +{$endif} +end; + +{******************************************************************* +* button_release_cb () +* +* DESCRIPTION: Callback function for Mouse Click +* +* PARAMETERS: None +* +* RETURNS: Nothing +* +*******************************************************************} +function button_release_cb(widget: PGtkWidget; event: PGdkEventButton; + user_data: gpointer): gboolean; cdecl; +var + vwsTrayIcon: TCustomTrayIcon; +begin + vwsTrayIcon := TCustomTrayIcon(user_data); + + Result := False; + + case event^.button of + 1: + begin + if Assigned(vwsTrayIcon.OnClick) then vwsTrayIcon.OnClick(vwsTrayIcon); + if Assigned(vwsTrayIcon.OnMouseUp) then + vwsTrayIcon.OnMouseUp(vwsTrayIcon, mbLeft, [], Round(event^.X), Round(event^.Y)); + end; + + 2: if Assigned(vwsTrayIcon.OnMouseUp) then + vwsTrayIcon.OnMouseUp(vwsTrayIcon, mbMiddle, [], Round(event^.X), Round(event^.Y)); + + 3: + begin + if Assigned(vwsTrayIcon.OnMouseUp) then + vwsTrayIcon.OnMouseUp(vwsTrayIcon, mbRight, [], Round(event^.X), Round(event^.Y)); + if Assigned(vwsTrayIcon.PopUpMenu) then + vwsTrayIcon.PopUpMenu.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); + end; + end; +end; + +{******************************************************************* +* button_press_cb () +* +* DESCRIPTION: Callback function for Mouse Click +* +* PARAMETERS: None +* +* RETURNS: Nothing +* +*******************************************************************} +function button_press_cb(widget: PGtkWidget; event: PGdkEventButton; + user_data: gpointer): gboolean; cdecl; +var + vwsTrayIcon: TCustomTrayIcon; +begin + vwsTrayIcon := TCustomTrayIcon(user_data); + + Result := False; + + if (event^._type = GDK_2BUTTON_PRESS) and Assigned(vwsTrayIcon.OnDblClick) then + vwsTrayIcon.OnDblClick(vwsTrayIcon) + else + begin + case event^.button of + 1: if Assigned(vwsTrayIcon.OnMouseDown) then + vwsTrayIcon.OnMouseDown(vwsTrayIcon, mbLeft, [], Round(event^.X), Round(event^.Y)); + + 2: if Assigned(vwsTrayIcon.OnMouseDown) then + vwsTrayIcon.OnMouseDown(vwsTrayIcon, mbMiddle, [], Round(event^.X), Round(event^.Y)); + + 3: if Assigned(vwsTrayIcon.OnMouseDown) then + vwsTrayIcon.OnMouseDown(vwsTrayIcon, mbRight, [], Round(event^.X), Round(event^.Y)); + end; + end; +end; + +{******************************************************************* +* popup_cb () +* +* DESCRIPTION: Callback function for the popup menu +* +* PARAMETERS: None +* +* RETURNS: Nothing +* +*******************************************************************} +function popup_cb(widget: PGtkWidget; user_data: gpointer): Boolean; cdecl; +var + vwsTrayIcon: TCustomTrayIcon; +begin + vwsTrayIcon := TCustomTrayIcon(user_data); + + Result := True; + + if Assigned(vwsTrayIcon.PopUpMenu) then + vwsTrayIcon.PopUpMenu.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y); +end; + +{******************************************************************* +* motion_cb () +* +* DESCRIPTION: Callback function for the OnMouseMove event +* +* PARAMETERS: None +* +* RETURNS: Nothing +* +*******************************************************************} +function motion_cb(widget: PGtkWidget; event: PGdkEventMotion; user_data: gpointer): Boolean; cdecl; +var + vwsTrayIcon: TCustomTrayIcon; +begin + vwsTrayIcon := TCustomTrayIcon(user_data); + + Result := False; + + if Assigned(vwsTrayIcon.OnMouseMove) then + vwsTrayIcon.OnMouseMove(vwsTrayIcon, [], Round(event^.X), Round(event^.Y)); +end; + +constructor TGtk2TrayIconHandle.Create(const wsTrayIcon: TCustomTrayIcon); +begin + fTrayIcon := wsTrayIcon; + {******************************************************************* + * Creates the GtkPlug + *******************************************************************} + + plug := gtk_plug_new(0); + + Tips := gtk_tooltips_new; + + g_object_ref(Tips); + + gtk_object_sink(GTK_OBJECT(Tips)); + + gtk_tooltips_set_tip(GTK_TOOLTIPS(Tips), plug, PChar(wsTrayIcon.Hint), ''); + + {******************************************************************* + * Connects the signals + *******************************************************************} + + gtk_widget_add_events(plug, GDK_ALL_EVENTS_MASK); + + g_signal_connect(plug, 'realize', TGCallback(@realize_cb), wsTrayIcon); + + g_signal_connect(plug, 'popup-menu', TGCallback(@popup_cb), wsTrayIcon); + + g_signal_connect(plug, 'motion-notify-event', TGCallback(@motion_cb), wsTrayIcon); + + g_signal_connect(plug, 'button-press-event', TGCallback(@button_press_cb), wsTrayIcon); + + g_signal_connect(plug, 'button-release-event', TGCallback(@button_release_cb), wsTrayIcon); + + {******************************************************************* + * Draws the icon + *******************************************************************} + + with wsTrayIcon do begin + DrawingArea := gtk_image_new_from_pixbuf(PGdkPixbuf(Icon.Handle)); + gtk_widget_show(DrawingArea); + gtk_container_add(GTK_CONTAINER(plug), DrawingArea); + end; +end; + +destructor TGtk2TrayIconHandle.Destroy; +begin + gtk_widget_destroy(plug); + + plug := nil; + + g_object_unref(Tips); + + Tips := nil; +end; + +{******************************************************************* +* TGtk2WSCustomTrayIcon.Hide () +* +* DESCRIPTION: Hides the main tray icon of the program +* +* PARAMETERS: None +* +* RETURNS: True if sucessfull, otherwise False +* +*******************************************************************} +class function TGtk2WSCustomTrayIcon.Hide(const ATrayIcon: TCustomTrayIcon): Boolean; +var + TrayIconHandle: TGtk2TrayIconHandle absolute ATrayIcon.Handle; +begin + Result := False; + + { Free and nil the handle } + TrayIconHandle.Free; + TrayIconHandle := nil; + + Result := True; +end; + +{******************************************************************* +* TGtk2WSCustomTrayIcon.Show () +* +* DESCRIPTION: Shows the main tray icon of the program +* +* PARAMETERS: None +* +* RETURNS: True if sucessfull, otherwise False +* +*******************************************************************} +class function TGtk2WSCustomTrayIcon.Show(const ATrayIcon: TCustomTrayIcon): Boolean; +var + TrayIconHandle: TGtk2TrayIconHandle absolute ATrayIcon.Handle; +begin + Result := False; + + TrayIconHandle := TGtk2TrayIconHandle.Create(ATrayIcon); + {******************************************************************* + * Now shows the GtkPlug + *******************************************************************} + with TrayIconHandle do begin + gtk_widget_show(plug); + if fEmbedded then begin + Result := True; + end else + Hide(ATrayIcon); + end; +end; + +{******************************************************************* +* TGtk2WSCustomTrayIcon.InternalUpdate () +* +* DESCRIPTION: Makes modifications to the Icon while running +* i.e. without hiding it and showing again +* +* PARAMETERS: None +* +* RETURNS: Nothing +* +*******************************************************************} +class procedure TGtk2WSCustomTrayIcon.InternalUpdate(const ATrayIcon: TCustomTrayIcon); +var + TrayIconHandle: TGtk2TrayIconHandle absolute ATrayIcon.Handle; +begin + if Assigned(TrayIconHandle) then with TrayIconHandle do begin + // Updates the tooltips + if Assigned(Tips) then + gtk_tooltips_set_tip(GTK_TOOLTIPS(Tips), plug, PChar(ATrayIcon.Hint), ''); + // Updates the icon + if Assigned(DrawingArea) then begin + gtk_image_set_from_pixbuf(GTK_IMAGE(DrawingArea), PGdkPixbuf(ATrayIcon.Icon.Handle)); + end; + end; +end; + +{******************************************************************* +* TGtk2WSCustomTrayIcon.GetPosition () +* +* DESCRIPTION: Returns the position of the tray icon on the display. +* This function is utilized to show message boxes near +* the icon +* +* PARAMETERS: None +* +* RETURNS: Nothing +* +*******************************************************************} +class function TGtk2WSCustomTrayIcon.GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint; +var + TrayIconHandle: TGtk2TrayIconHandle absolute ATrayIcon.Handle; + WindowHandle: PGDKWindow; +begin + Result := Point(0, 0); + if Assigned(TrayIconHandle) then with TrayIconHandle do begin + if not Assigned(plug) then begin + WindowHandle := plug^.window; + if Assigned(WindowHandle) then + gdk_window_get_origin(WindowHandle, @Result.X, @Result.Y); + end; + end; +end; +