mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 12:49:42 +01:00 
			
		
		
		
	- General clean up and much improved support for Qt. - Updated the example to contain a popup menu. git-svn-id: trunk@10107 -
		
			
				
	
	
		
			516 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			516 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						||
 wsgtk2trayicon.pas
 | 
						||
 | 
						||
 *****************************************************************************
 | 
						||
 *                                                                           *
 | 
						||
 *  See the file COPYING.modifiedLGPL, 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.
 | 
						||
}
 | 
						||
unit WSGtk2TrayIcon;
 | 
						||
 | 
						||
{$ifdef FPC}
 | 
						||
  {$mode delphi}{$H+}
 | 
						||
{$endif}
 | 
						||
 | 
						||
{$PACKRECORDS C}
 | 
						||
  
 | 
						||
interface
 | 
						||
 | 
						||
uses
 | 
						||
  Graphics, Classes, ExtCtrls, SysUtils, Forms, Controls, Dialogs,
 | 
						||
  Menus, WSCommonTrayIcon, x, xlib, xutil, gtk2, gdk2, gdk2x, glib2, gtkdef;
 | 
						||
 | 
						||
type
 | 
						||
 | 
						||
  { TWidgetTrayIcon }
 | 
						||
 | 
						||
  TWidgetTrayIcon = class(TCustomWidgetTrayIcon)
 | 
						||
    private
 | 
						||
      fOwner: TComponent;
 | 
						||
      fEmbedded: Boolean;
 | 
						||
      fMsgCount: Integer;
 | 
						||
      Tips: PGtkTooltips;
 | 
						||
      procedure CreateForm(id: Integer);
 | 
						||
      procedure RemoveForm(id: Integer);
 | 
						||
      function GetCanvas: TCanvas;
 | 
						||
    protected
 | 
						||
    public
 | 
						||
      function Hide: Boolean; override;
 | 
						||
      function Show: Boolean; override;
 | 
						||
      property Canvas: TCanvas read GetCanvas;
 | 
						||
      procedure InternalUpdate; override;
 | 
						||
      procedure PaintForm(Sender: TObject);
 | 
						||
      function GetPosition: TPoint; override;
 | 
						||
    published
 | 
						||
  end;
 | 
						||
 | 
						||
const
 | 
						||
  SYSTEM_TRAY_REQUEST_DOCK   = 0;
 | 
						||
  SYSTEM_TRAY_BEGIN_MESSAGE  = 1;
 | 
						||
  SYSTEM_TRAY_CANCEL_MESSAGE = 2;
 | 
						||
 | 
						||
implementation
 | 
						||
 | 
						||
uses WSTrayIcon;
 | 
						||
 | 
						||
var
 | 
						||
  fDisplay: PDisplay;
 | 
						||
  fWindow: TWindow;
 | 
						||
  fScreen: PScreen;
 | 
						||
  fScreenID: longint;
 | 
						||
  GtkForm: PGtkWidget;
 | 
						||
  fTrayParent: TWindow;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  TempX11ErrorHandler ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:    Temp ErrorHandler
 | 
						||
*
 | 
						||
*  PARAMETERS:     ?
 | 
						||
*
 | 
						||
*  RETURNS:        ?
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
function TempX11ErrorHandler(Display:PDisplay; ErrorEv:PXErrorEvent):longint;cdecl;
 | 
						||
begin
 | 
						||
  WriteLn('Error: ' + IntToStr(ErrorEv^.error_code));
 | 
						||
end;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  Send_Message ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:    Sends a message to the X client
 | 
						||
*
 | 
						||
*  PARAMETERS:     None
 | 
						||
*
 | 
						||
*  RETURNS:        Nothing
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
function SendMessage(window: TWindow; msg: Integer; data1, data2, data3: Integer): boolean;
 | 
						||
var
 | 
						||
  Ev: TXEvent;
 | 
						||
  fmt: Integer;
 | 
						||
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;
 | 
						||
 | 
						||
  XSendEvent(fDisplay, fTrayParent, False, NoEventMask, @ev);
 | 
						||
  XSync(fDisplay, False);
 | 
						||
  Result := false;//(untrap_errors() = 0);
 | 
						||
end;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  SetEmbedded ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:    Docks the GtkPlug into the system tray
 | 
						||
*
 | 
						||
*  PARAMETERS:     None
 | 
						||
*
 | 
						||
*  RETURNS:        Nothing
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
procedure SetEmbedded;
 | 
						||
var
 | 
						||
  old_error: TXErrorHandler;
 | 
						||
  buf: array [0..32] of char;
 | 
						||
  selection_atom : TAtom;
 | 
						||
begin
 | 
						||
  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
 | 
						||
    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
 | 
						||
  gdk_screen: PGdkScreen;
 | 
						||
begin
 | 
						||
  fDisplay := GDK_WINDOW_XDISPLAY(GtkForm^.window);
 | 
						||
  fWindow := GDK_WINDOW_XWINDOW(GtkForm^.window);
 | 
						||
 | 
						||
{  Doesn<73>t work
 | 
						||
 | 
						||
  gdk_screen := gtk_widget_get_screen(GtkForm);
 | 
						||
  fScreen := GDK_SCREEN_XSCREEN(gdk_screen); // get the real screen}
 | 
						||
 | 
						||
  fScreen := XDefaultScreenOfDisplay(fDisplay);
 | 
						||
  fScreenID := XScreenNumberOfScreen(fScreen); // and it's number
 | 
						||
  
 | 
						||
  SetEmbedded;
 | 
						||
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: TWSTrayIcon;
 | 
						||
begin
 | 
						||
  vwsTrayIcon := TWSTrayIcon(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: if Assigned(vwsTrayIcon.OnMouseUp) then
 | 
						||
        vwsTrayIcon.OnMouseUp(vwsTrayIcon, mbRight, [], Round(event^.X), Round(event^.Y));
 | 
						||
  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: TWSTrayIcon;
 | 
						||
begin
 | 
						||
  vwsTrayIcon := TWSTrayIcon(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.OnMouseUp) then
 | 
						||
          vwsTrayIcon.OnMouseDown(vwsTrayIcon, mbLeft, [], Round(event^.X), Round(event^.Y));
 | 
						||
 | 
						||
      2: if Assigned(vwsTrayIcon.OnMouseUp) then
 | 
						||
         vwsTrayIcon.OnMouseDown(vwsTrayIcon, mbMiddle, [], Round(event^.X), Round(event^.Y));
 | 
						||
 | 
						||
      3:
 | 
						||
      begin
 | 
						||
        if Assigned(vwsTrayIcon.OnMouseUp) then
 | 
						||
         vwsTrayIcon.OnMouseDown(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;
 | 
						||
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: TWSTrayIcon;
 | 
						||
begin
 | 
						||
  vwsTrayIcon := TWSTrayIcon(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: TWSTrayIcon;
 | 
						||
begin
 | 
						||
  vwsTrayIcon := TWSTrayIcon(user_data);
 | 
						||
 | 
						||
  Result := False;
 | 
						||
 | 
						||
  if Assigned(vwsTrayIcon.OnMouseMove) then
 | 
						||
   vwsTrayIcon.OnMouseMove(vwsTrayIcon, [], Round(event^.X), Round(event^.Y));
 | 
						||
end;
 | 
						||
 | 
						||
{ TWidgetTrayIcon }
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  TWidgetTrayIcon.CreateForm ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:
 | 
						||
*
 | 
						||
*  PARAMETERS:     None
 | 
						||
*
 | 
						||
*  RETURNS:        Nothing
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
procedure TWidgetTrayIcon.CreateForm(id: Integer);
 | 
						||
var
 | 
						||
  AImage: PGtkWidget;
 | 
						||
  GDIObject: PgdiObject;
 | 
						||
begin
 | 
						||
  {*******************************************************************
 | 
						||
  *  Creates the GtkPlug
 | 
						||
  *******************************************************************}
 | 
						||
  
 | 
						||
  fEmbedded := False;
 | 
						||
 | 
						||
  GtkForm := 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), GtkForm, PChar(Hint), '');
 | 
						||
 | 
						||
  {*******************************************************************
 | 
						||
  *  Connects the signals
 | 
						||
  *******************************************************************}
 | 
						||
  
 | 
						||
  gtk_widget_add_events(GtkForm, GDK_ALL_EVENTS_MASK);
 | 
						||
 | 
						||
  g_signal_connect(GtkForm, 'realize', TGCallback(@realize_cb), Self);
 | 
						||
 | 
						||
  g_signal_connect(GtkForm, 'popup-menu', TGCallback(@popup_cb), Self);
 | 
						||
 | 
						||
  g_signal_connect(GtkForm, 'motion-notify-event', TGCallback(@motion_cb), Self);
 | 
						||
 | 
						||
  g_signal_connect(GtkForm, 'button-press-event', TGCallback(@button_press_cb), Self);
 | 
						||
 | 
						||
  g_signal_connect(GtkForm, 'button-release-event', TGCallback(@button_release_cb), Self);
 | 
						||
 | 
						||
  {*******************************************************************
 | 
						||
  *  Draws the icon
 | 
						||
  *******************************************************************}
 | 
						||
 | 
						||
  GDIObject := PgdiObject(Icon.Handle);
 | 
						||
 | 
						||
  AImage := gtk_image_new_from_pixmap(GDIObject^.GDIPixmapObject,
 | 
						||
   GDIObject^.GDIBitmapMaskObject);
 | 
						||
 | 
						||
  gtk_widget_show(AImage);
 | 
						||
 | 
						||
  gtk_container_add(GTK_CONTAINER(GtkForm), AImage);
 | 
						||
 | 
						||
  {*******************************************************************
 | 
						||
  *  Now shows the GtkPlug
 | 
						||
  *******************************************************************}
 | 
						||
 | 
						||
  gtk_widget_show(GtkForm);
 | 
						||
end;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  TWidgetTrayIcon.RemoveForm ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:
 | 
						||
*
 | 
						||
*  PARAMETERS:     None
 | 
						||
*
 | 
						||
*  RETURNS:        Nothing
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
procedure TWidgetTrayIcon.RemoveForm(id: Integer);
 | 
						||
begin
 | 
						||
  gtk_widget_destroy(GtkForm);
 | 
						||
  
 | 
						||
  GtkForm := nil;
 | 
						||
 | 
						||
  g_object_unref(Tips);
 | 
						||
 | 
						||
  Tips := nil;
 | 
						||
end;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  TWidgetTrayIcon.GetCanvas ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:
 | 
						||
*
 | 
						||
*  PARAMETERS:     None
 | 
						||
*
 | 
						||
*  RETURNS:        Nothing
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
function TWidgetTrayIcon.GetCanvas: TCanvas;
 | 
						||
begin
 | 
						||
  Result := Icon.Canvas;
 | 
						||
end;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  TWidgetTrayIcon.Hide ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:    Hides the main tray icon of the program
 | 
						||
*
 | 
						||
*  PARAMETERS:     None
 | 
						||
*
 | 
						||
*  RETURNS:        True if sucessfull, otherwise False
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
function TWidgetTrayIcon.Hide: Boolean;
 | 
						||
begin
 | 
						||
  Result := False;
 | 
						||
 | 
						||
  if not vVisible then Exit;
 | 
						||
 | 
						||
  RemoveForm(0);
 | 
						||
 | 
						||
  vVisible := False;
 | 
						||
  
 | 
						||
  Result := True;
 | 
						||
end;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  TWidgetTrayIcon.Show ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:    Shows the main tray icon of the program
 | 
						||
*
 | 
						||
*  PARAMETERS:     None
 | 
						||
*
 | 
						||
*  RETURNS:        True if sucessfull, otherwise False
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
function TWidgetTrayIcon.Show: Boolean;
 | 
						||
begin
 | 
						||
  Result := False;
 | 
						||
 | 
						||
  if vVisible then Exit;
 | 
						||
  
 | 
						||
  CreateForm(0);
 | 
						||
 | 
						||
  fEmbedded := True;
 | 
						||
 | 
						||
  vVisible := True;
 | 
						||
 | 
						||
  Result := True;
 | 
						||
end;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  TWidgetTrayIcon.PaintForm ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:    Paint method of the Icon Window
 | 
						||
*
 | 
						||
*  PARAMETERS:     Sender of the event
 | 
						||
*
 | 
						||
*  RETURNS:        Nothing
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
procedure TWidgetTrayIcon.PaintForm(Sender: TObject);
 | 
						||
begin
 | 
						||
//  if ShowIcon then GtkForm.Canvas.Draw(0, 0, Icon);
 | 
						||
 | 
						||
  if Assigned(OnPaint) then OnPaint(Self);
 | 
						||
end;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  TWidgetTrayIcon.InternalUpdate ()
 | 
						||
*
 | 
						||
*  DESCRIPTION:    Makes modifications to the Icon while running
 | 
						||
*                  i.e. without hiding it and showing again
 | 
						||
*
 | 
						||
*  PARAMETERS:     None
 | 
						||
*
 | 
						||
*  RETURNS:        Nothing
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
procedure TWidgetTrayIcon.InternalUpdate;
 | 
						||
begin
 | 
						||
  if Assigned(Tips) then gtk_tooltips_set_tip(GTK_TOOLTIPS(Tips), GtkForm, PChar(Hint), '');
 | 
						||
end;
 | 
						||
 | 
						||
{*******************************************************************
 | 
						||
*  TWidgetTrayIcon.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
 | 
						||
*
 | 
						||
*******************************************************************}
 | 
						||
function TWidgetTrayIcon.GetPosition: TPoint;
 | 
						||
begin
 | 
						||
  Result.X := 0;
 | 
						||
  Result.Y := 0;
 | 
						||
end;
 | 
						||
 | 
						||
end.
 | 
						||
 |