View Issue Details

IDProjectCategoryView StatusLast Update
0023217LazarusIDEpublic2014-09-14 15:04
ReporterzmeyAssigned ToZeljan Rikalo 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version1.0.2Product Build 
Target Version1.2.6Fixed in Version1.3 (SVN) 
Summary0023217: OnMouseMove don't work with TTrayIcon
DescriptionNo problem in Lazarus 0.9.30, but problem is in Lazarus>=1.0.1.
Additional Informationunit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    TrayIcon1: TTrayIcon;
    procedure FormCreate(Sender: TObject);
    procedure TrayIcon1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.TrayIcon1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
   halt;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  TrayIcon1.Visible:=true;
end;

end.
TagsNo tags attached.
Fixed in Revision46221,46222,46223
LazTarget1.2.6
WidgetsetGTK 2, QT
Attached Files
  • lazarus_trayicon_onmousemove_mga.patch (6,196 bytes)
    diff -ur lazarus.orig/lcl/interfaces/gtk2/gtk2trayicon.inc lazarus/lcl/interfaces/gtk2/gtk2trayicon.inc
    --- lazarus.orig/lcl/interfaces/gtk2/gtk2trayicon.inc	2012-04-17 11:55:52.000000000 +0400
    +++ lazarus/lcl/interfaces/gtk2/gtk2trayicon.inc	2014-04-09 15:19:52.000000000 +0400
    @@ -365,6 +365,16 @@
       end;
     end;
     
    +function query_tooltip_cb_statusicon({%H-}status_icon: PGtkStatusIcon;
    +  x: guint; y: guint; {%H-}keyboard_mode: gboolean; {%H-}tooltip: gpointer{PGtkTooltip}; user_data: gpointer): gboolean; cdecl;
    +var
    +  vwsTrayIcon: TCustomTrayIcon absolute user_data;
    +begin
    +  Result := FALSE;
    +
    +  if Assigned(vwsTrayIcon.OnMouseMove) then
    +   vwsTrayIcon.OnMouseMove(vwsTrayIcon, [], x, y);
    +end;
     {$endif}
     
     constructor TGtk2TrayIconHandle.Create(const wsTrayIcon: TCustomTrayIcon);
    @@ -378,12 +388,14 @@
         FStatusIcon := gtk_status_icon_new();
         gtk_status_icon_set_from_pixbuf(FStatusIcon, {%H-}PGdkPixbuf(FTrayIcon.Icon.Handle));
         gtk_status_icon_set_tooltip(FStatusIcon, PChar(FTrayIcon.Hint));
    +    g_object_set(PGObject(FStatusIcon), 'has-tooltip', TRUE);
         fEmbedded := gtk_status_icon_is_embedded(FStatusIcon);
     
         g_signal_connect(FStatusIcon, 'activate', TGCallback(@activate_cb_statusicon), fTrayIcon);
         g_signal_connect(FStatusIcon, 'popup-menu', TGCallback(@popup_cb_statusicon), fTrayIcon);
         g_signal_connect(FStatusIcon, 'button-press-event', TGCallback(@button_press_cb_statusicon), fTrayIcon);
         g_signal_connect(FStatusIcon, 'button-release-event', TGCallback(@button_release_cb_statusicon), fTrayIcon);
    +    g_signal_connect(FStatusIcon, 'query-tooltip', TGCallback(@query_tooltip_cb_statusicon), fTrayIcon);
       end
       else
     {$endif}
    @@ -407,8 +419,8 @@
         with wsTrayIcon do
         begin
           DrawingArea := gtk_image_new_from_pixbuf({%H-}PGdkPixbuf(Icon.Handle));
    -      gtk_widget_show(DrawingArea);
           gtk_container_add(GTK_CONTAINER(plug), DrawingArea);
    +      gtk_widget_show(DrawingArea);
         end;
       end;
     end;
    @@ -478,6 +490,7 @@
       begin
         gtk_status_icon_set_from_pixbuf(FStatusIcon, NewPixBuf);
         gtk_status_icon_set_tooltip(FStatusIcon, PChar(NewHint));
    +    g_object_set(PGObject(FStatusIcon), 'has-tooltip', TRUE);
       end
       else
     {$endif}
    Только в lazarus/lcl/interfaces/gtk2: gtk2trayicon.inc.orig
    diff -ur lazarus.orig/lcl/interfaces/qt/qtobjects.pas lazarus/lcl/interfaces/qt/qtobjects.pas
    --- lazarus.orig/lcl/interfaces/qt/qtobjects.pas	2013-06-10 01:42:51.000000000 +0400
    +++ lazarus/lcl/interfaces/qt/qtobjects.pas	2014-04-09 15:22:06.000000000 +0400
    @@ -527,15 +527,17 @@
       
       { TQtSystemTrayIcon }
     
    -  TQtSystemTrayIcon = class(TObject)
    +  TQtSystemTrayIcon = class(TQtObject)
       private
         FHook: QSystemTrayIcon_hookH;
       public
    -    Handle: QSystemTrayIconH;
         FTrayIcon: TCustomTrayIcon;
       public
         constructor Create(vIcon: QIconH); virtual;
         destructor Destroy; override;
    +    procedure AttachEvents; override;
    +    procedure DetachEvents; override;
    +    function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; override;
       public
         procedure setContextMenu(menu: QMenuH);
         procedure setIcon(icon: QIconH);
    @@ -3658,34 +3660,78 @@
       inherited Create;
     
       if vIcon <> nil then
    -    Handle := QSystemTrayIcon_create(vicon, nil)
    +    TheObject := QObjectH(QSystemTrayIcon_create(vicon, nil))
       else
    -    Handle := QSystemTrayIcon_create();
    -  FHook := QSystemTrayIcon_hook_create(Handle);
    -  QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
    +    TheObject := QObjectH(QSystemTrayIcon_create());
    +  AttachEvents;
     end;
     
     destructor TQtSystemTrayIcon.Destroy;
     begin
    -  QSystemTrayIcon_hook_destroy(FHook);
    -  QSystemTrayIcon_destroy(Handle);
    -  
       inherited Destroy;
     end;
     
    +procedure TQtSystemTrayIcon.AttachEvents;
    +begin
    +  FHook := QSystemTrayIcon_hook_create(QSystemTrayIconH(TheObject));
    +  QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
    +  inherited AttachEvents;
    +end;
    +
    +procedure TQtSystemTrayIcon.DetachEvents;
    +begin
    +  if FHook <> nil then
    +    QSystemTrayIcon_hook_destroy(FHook);
    +  inherited DetachEvents;
    +end;
    +
    +function TQtSystemTrayIcon.EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl;
    +var
    +  x, y: integer;
    +  MousePos: TQtPoint;
    +  IconGeometry: TRect;
    +begin
    +  Result := False;
    +  
    +  if Assigned(FTrayIcon) then begin
    +	case QEvent_type(Event) of
    +		QEventMouseMove:
    +		begin
    +			x := QMouseEvent_x(QMouseEventH(Event));
    +			y := QMouseEvent_y(QMouseEventH(Event));
    +			
    +			if Assigned(FTrayIcon.OnMouseMove) then
    +				FTrayIcon.OnMouseMove(FTrayIcon, [], x, y);
    +		end;
    +		QEventToolTip, QEventWheel:
    +		begin
    +			QCursor_pos(@MousePos);
    +			QSystemTrayIcon_geometry(QSystemTrayIconH(Sender), @IconGeometry);
    +			x := MousePos.x - IconGeometry.Left;
    +			y := MousePos.y - IconGeometry.Top;
    +			
    +			if Assigned(FTrayIcon.OnMouseMove) then
    +				FTrayIcon.OnMouseMove(FTrayIcon, [], x, y);
    +		end;
    +	end;
    +  end;
    +  
    +  QEvent_accept(Event);
    +end;
    +
     procedure TQtSystemTrayIcon.setContextMenu(menu: QMenuH);
     begin
    -  QSystemTrayIcon_setContextMenu(handle, menu);
    +  QSystemTrayIcon_setContextMenu(QSystemTrayIconH(TheObject), menu);
     end;
     
     procedure TQtSystemTrayIcon.setIcon(icon: QIconH);
     begin
    -  QSystemTrayIcon_setIcon(handle, icon);
    +  QSystemTrayIcon_setIcon(QSystemTrayIconH(TheObject), icon);
     end;
     
     procedure TQtSystemTrayIcon.setToolTip(tip: WideString);
     begin
    -  QSystemTrayIcon_setToolTip(handle, @tip)
    +  QSystemTrayIcon_setToolTip(QSystemTrayIconH(TheObject), @tip);
     end;
     
     procedure TQtSystemTrayIcon.signalActivated(
    @@ -3751,17 +3797,17 @@
     begin
       WHint := GetUTF8String(AHint);
       WTitle := GetUTF8String(ATitle);
    -  QSystemTrayIcon_showMessage(Handle, @WTitle, @WHint, AFlag, ATimeOut);
    +  QSystemTrayIcon_showMessage(QSystemTrayIconH(TheObject), @WTitle, @WHint, AFlag, ATimeOut);
     end;
     
     procedure TQtSystemTrayIcon.Show;
     begin
    -  QSystemTrayIcon_show(handle);
    +  QSystemTrayIcon_show(QSystemTrayIconH(TheObject));
     end;
     
     procedure TQtSystemTrayIcon.Hide;
     begin
    -  QSystemTrayIcon_hide(handle);
    +  QSystemTrayIcon_hide(QSystemTrayIconH(TheObject));
     end;
     
     { TQtButtonGroup }
    Только в lazarus/lcl/interfaces/qt: qtobjects.pas.orig
    
  • qtsystemtrayicon.pas (9,392 bytes)
    unit qtsystemtrayicon;
    {$mode objfpc}{$H+}
    
    interface
    {$i qtdefines.inc}
    
    uses Classes, Controls, ExtCtrls, Graphics, Forms, LCLType, qtobjects, qt4,
      qtproc;
    
    type
      TSysTrayIconPaintData = record
        PaintWidget: QWidgetH;
        ClipRect: Prect;
        ClipRegion: QRegionH;
        Context: TQtDeviceContext;
      end;
    
      { TQtSystemTrayIcon }
    
      TQtSystemTrayIcon = class(TQtObject)
      private
        FSysTrayHook: QObject_hookH;
        FHook: QSystemTrayIcon_hookH;
        FSysTrayWidget: QWidgetH;
        FCanvas: TCanvas;
        function BeginPaintInternal(var APaintData: TSysTrayIconPaintData): hdc;
        procedure EndPaintInternal(var APaintData: TSysTrayIconPaintData);
      public
        FTrayIcon: TCustomTrayIcon;
      public
        constructor Create(vIcon: QIconH); virtual;
        destructor Destroy; override;
      public
        procedure AttachEvents; override;
        procedure DetachEvents; override;
        procedure AttachSysTrayWidget(AWidget: QWidgetH);
        procedure DetachSysTrayWidget;
        function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; override;
        procedure setContextMenu(menu: QMenuH);
        procedure setIcon(icon: QIconH);
        procedure setToolTip(tip: WideString);
        procedure signalActivated(AReason: QSystemTrayIconActivationReason); cdecl;
        procedure showBaloonHint(const ATitle, AHint: String;
          const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
        function GetGeometry: TRect;
        function GetPosition: TPoint;
        procedure Show;
        procedure Hide;
        procedure UpdateSystemTrayWidget;
        property Canvas: TCanvas read FCanvas write FCanvas;
        property SysTrayWidget: QWidgetH read FSysTrayWidget;
      end;
    
    implementation
    uses qtint, LCLProc;
    
    { TQtSystemTrayIcon }
    
    constructor TQtSystemTrayIcon.Create(vIcon: QIconH);
    begin
      inherited Create;
      FSysTrayWidget := nil;
      FSysTrayHook := nil;
      if vIcon <> nil then
        TheObject := QSystemTrayIcon_create(vicon, nil)
      else
        TheObject := QSystemTrayIcon_create();
      FCanvas := nil;
      QtWidgetSet.RegisterSysTrayIcon(Self);
      AttachEvents;
    end;
    
    destructor TQtSystemTrayIcon.Destroy;
    begin
      QtWidgetSet.UnRegisterSysTrayIcon(Self);
      inherited Destroy;
    end;
    
    procedure TQtSystemTrayIcon.AttachEvents;
    begin
      inherited AttachEvents;
      FHook := QSystemTrayIcon_hook_create(QSystemTrayIconH(TheObject));
      QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
    end;
    
    procedure TQtSystemTrayIcon.DetachEvents;
    begin
      DetachSysTrayWidget;
      if Assigned(FHook) then
      begin
        QSystemTrayIcon_hook_destroy(FHook);
        FHook := nil;
      end;
      inherited DetachEvents;
    end;
    
    procedure TQtSystemTrayIcon.AttachSysTrayWidget(AWidget: QWidgetH);
    begin
      if (AWidget = nil) and (FSysTrayWidget <> nil) then
        DetachSysTrayWidget;
      FSysTrayWidget := AWidget;
      if FSysTrayWidget <> nil then
      begin
        FSysTrayHook := QObject_hook_create(FSysTrayWidget);
        QObject_hook_hook_events(FSysTrayHook, @EventFilter);
      end;
    end;
    
    procedure TQtSystemTrayIcon.DetachSysTrayWidget;
    begin
      if FSysTrayWidget <> nil then
      begin
        if FSysTrayHook <> nil then
          QObject_hook_destroy(FSysTrayHook);
        FSysTrayHook := nil;
        FSysTrayWidget := niL;
      end;
    end;
    
    function TQtSystemTrayIcon.BeginPaintInternal(var APaintData: TSysTrayIconPaintData): hdc;
    var
      DC: TQtDeviceContext;
    begin
      DC := TQtDeviceContext.Create(FSysTrayWidget, True);
      Result := HDC(DC);
      if Result <> 0 then
      begin
        if (QtVersionMajor = 4) and (QtVersionMinor > 6) then
          QPainter_setLayoutDirection(DC.Widget, QtLayoutDirectionAuto);
        if APaintData.ClipRegion <> nil then
        begin
          DC.setClipRegion(APaintData.ClipRegion);
          DC.setClipping(True);
        end;
        if APaintData.ClipRect <> nil then
        begin
          New(DC.vClipRect);
          DC.vClipRect^ := APaintData.ClipRect^;
        end;
        APaintData.Context := DC;
      end;
    end;
    
    procedure TQtSystemTrayIcon.EndPaintInternal(var APaintData: TSysTrayIconPaintData);
    begin
      if APaintData.ClipRect <> nil then
        Dispose(APaintData.ClipRect);
      if APaintData.Context <> nil then
        APaintData.Context.Free;
      APaintData.Context := nil;
    end;
    
    function TQtSystemTrayIcon.EventFilter(Sender: QObjectH; Event: QEventH
      ): Boolean; cdecl;
    var
      X, Y: Integer;
      R: TRect;
      P: TQtPoint;
      AHint: WideString;
      PaintData: TSysTrayIconPaintData;
    begin
      Result := False;
      if Sender <> FSysTrayWidget then
        exit;
    
      case QEvent_type(Event) of
        QEventPaint:
        begin
          if Assigned(FTrayIcon.OnPaint) then
          begin
            // qt kernel sets QtWA_PaintOnScreen and QtWA_NoSystemBackground
            // also OnPaint won't fire until we enter widget with mouse.
            // Thats so now until I find out howto find systrayicon private QWidget
            // without searching in QtWidgetSet.EventFilter.
            {$IFDEF HASX11}
            FillChar(PaintData, SizeOf(PaintData), 0);
            with PaintData do
            begin
              PaintWidget := FSysTrayWidget;
              ClipRegion := QPaintEvent_Region(QPaintEventH(Event));
              if ClipRect = nil then
                New(ClipRect);
              QPaintEvent_Rect(QPaintEventH(Event), ClipRect);
            end;
            FCanvas := TCanvas.Create;
            try
              FCanvas.Handle := BeginPaintInternal(PaintData);
              if Assigned(FTrayIcon.OnPaint) then
                FTrayIcon.OnPaint(FTrayIcon);
              EndPaintInternal(PaintData);
            finally
              FreeThenNil(FCanvas);
            end;
            Result := True;
            {$ELSE}
            DebugLn('TQtSystemTrayIcon: Paint event is not supported.');
            {$ENDIF}
          end;
        end;
        QEventToolTip:
        begin
          if Assigned(FTrayIcon) and (FTrayIcon.Hint <> '') then
          begin
            R := GetGeometry;
            QtPoint(R.Left, R.Top);
            AHint := UTF8ToUTF16(FTrayIcon.Hint);
            QToolTip_showText(@P, @AHint);
          end;
        end;
        QEventMouseMove:
        begin
          if Assigned(FTrayIcon) and Assigned(FTrayIcon.OnMouseMove) then
          begin
            X := QMouseEvent_pos(QMouseEventH(Event))^.x;
            Y := QMouseEvent_pos(QMouseEventH(Event))^.Y;
            FTrayIcon.OnMouseMove(FTrayIcon, [], X, Y);
            if Assigned(FTrayIcon.OnPaint) and (FSysTrayWidget <> nil) then
              QWidget_update(FSysTrayWidget);
          end;
        end;
      end;
    end;
    
    procedure TQtSystemTrayIcon.setContextMenu(menu: QMenuH);
    begin
      QSystemTrayIcon_setContextMenu(QSystemTrayIconH(TheObject), menu);
    end;
    
    procedure TQtSystemTrayIcon.setIcon(icon: QIconH);
    begin
      QSystemTrayIcon_setIcon(QSystemTrayIconH(TheObject), icon);
    end;
    
    procedure TQtSystemTrayIcon.setToolTip(tip: WideString);
    begin
      QSystemTrayIcon_setToolTip(QSystemTrayIconH(TheObject), @tip)
    end;
    
    procedure TQtSystemTrayIcon.signalActivated(
      AReason: QSystemTrayIconActivationReason); cdecl;
    var
      MousePos: TQtPoint;
    begin
      if not Assigned(FTrayIcon) then
        exit;
      QCursor_pos(@MousePos);
    
      if Assigned(FTrayIcon.OnPaint) and (FSysTrayWidget <> nil) then
        QWidget_update(FSysTrayWidget); // trigger paint event.
    
      case AReason of
        QSystemTrayIconTrigger:
          begin
            if Assigned(FTrayIcon.OnMouseDown) then
              FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
            if Assigned(FTrayIcon.OnClick) then
              FTrayIcon.OnClick(FTrayIcon);
            if Assigned(FTrayIcon.OnMouseUp) then
              FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
          end;
        QSystemTrayIconDoubleClick:
          begin
            if Assigned(FTrayIcon.OnMouseDown) then
              FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
    
            if Assigned(FTrayIcon.OnDblClick) then
              FTrayIcon.OnDblClick(FTrayIcon);
    
            if Assigned(FTrayIcon.OnMouseUp) then
              FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
          end;
        QSystemTrayIconMiddleClick:
          begin
            if Assigned(FTrayIcon.OnMouseDown) then
              FTrayIcon.OnMouseDown(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
            if Assigned(FTrayIcon.OnMouseUp) then
              FTrayIcon.OnMouseUp(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
          end;
        QSystemTrayIconContext:
          begin
            if Assigned(FTrayIcon.OnMouseDown) then
              FTrayIcon.OnMouseDown(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
    
            if Assigned(FTrayIcon.OnMouseUp) then
              FTrayIcon.OnMouseUp(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
          end;
      end;
    end;
    
    procedure TQtSystemTrayIcon.showBaloonHint(const ATitle, AHint: String;
      const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
    var
      WHint: WideString;
      WTitle: WideString;
    begin
      WHint := GetUTF8String(AHint);
      WTitle := GetUTF8String(ATitle);
      QSystemTrayIcon_showMessage(QSystemTrayIconH(TheObject), @WTitle, @WHint, AFlag, ATimeOut);
    end;
    
    function TQtSystemTrayIcon.GetGeometry: TRect;
    begin
      Result := Rect(0, 0, 0, 0);
      if Assigned(TheObject) then
        QSystemTrayIcon_geometry(QSystemTrayIconH(TheObject), @Result);
    end;
    
    function TQtSystemTrayIcon.GetPosition: TPoint;
    var
      R: TRect;
    begin
      R := GetGeometry;
      Result := Point(R.Left, R.Top);
    end;
    
    procedure TQtSystemTrayIcon.Show;
    begin
      QSystemTrayIcon_show(QSystemTrayIconH(TheObject));
    end;
    
    procedure TQtSystemTrayIcon.Hide;
    begin
      QSystemTrayIcon_hide(QSystemTrayIconH(TheObject));
    end;
    
    procedure TQtSystemTrayIcon.UpdateSystemTrayWidget;
    begin
      if Assigned(FSysTrayWidget) then
        QWidget_update(FSysTrayWidget);
    end;
    
    end.
    
    qtsystemtrayicon.pas (9,392 bytes)
  • qtsystemtrayicon_events.diff (13,881 bytes)
    Index: lcl/interfaces/qt/qtobjects.pas
    ===================================================================
    --- lcl/interfaces/qt/qtobjects.pas	(revision 44672)
    +++ lcl/interfaces/qt/qtobjects.pas	(working copy)
    @@ -520,28 +520,6 @@
         property Handle: QCursorH read FHandle;
       end;
       
    -  { TQtSystemTrayIcon }
    -
    -  TQtSystemTrayIcon = class(TObject)
    -  private
    -    FHook: QSystemTrayIcon_hookH;
    -  public
    -    Handle: QSystemTrayIconH;
    -    FTrayIcon: TCustomTrayIcon;
    -  public
    -    constructor Create(vIcon: QIconH); virtual;
    -    destructor Destroy; override;
    -  public
    -    procedure setContextMenu(menu: QMenuH);
    -    procedure setIcon(icon: QIconH);
    -    procedure setToolTip(tip: WideString);
    -    procedure signalActivated(AReason: QSystemTrayIconActivationReason); cdecl;
    -    procedure showBaloonHint(const ATitle, AHint: String;
    -      const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
    -    procedure Show;
    -    procedure Hide;
    -  end;
    -  
       { TQtButtonGroup }
       
       TQtButtonGroup = class(TObject)
    @@ -3690,119 +3668,6 @@
       QPixmap_fromImage(retval, image, flags);
     end;
     
    -{ TQtSystemTrayIcon }
    -
    -constructor TQtSystemTrayIcon.Create(vIcon: QIconH);
    -begin
    -  inherited Create;
    -
    -  if vIcon <> nil then
    -    Handle := QSystemTrayIcon_create(vicon, nil)
    -  else
    -    Handle := QSystemTrayIcon_create();
    -  FHook := QSystemTrayIcon_hook_create(Handle);
    -  QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
    -end;
    -
    -destructor TQtSystemTrayIcon.Destroy;
    -begin
    -  QSystemTrayIcon_hook_destroy(FHook);
    -  QSystemTrayIcon_destroy(Handle);
    -  
    -  inherited Destroy;
    -end;
    -
    -procedure TQtSystemTrayIcon.setContextMenu(menu: QMenuH);
    -begin
    -  QSystemTrayIcon_setContextMenu(handle, menu);
    -end;
    -
    -procedure TQtSystemTrayIcon.setIcon(icon: QIconH);
    -begin
    -  QSystemTrayIcon_setIcon(handle, icon);
    -end;
    -
    -procedure TQtSystemTrayIcon.setToolTip(tip: WideString);
    -begin
    -  QSystemTrayIcon_setToolTip(handle, @tip)
    -end;
    -
    -procedure TQtSystemTrayIcon.signalActivated(
    -  AReason: QSystemTrayIconActivationReason); cdecl;
    -var
    -  MousePos: TQtPoint;
    -begin
    -  if not Assigned(FTrayIcon) then
    -    exit;
    -
    -  QCursor_pos(@MousePos);
    -  {$note: TODO: Mouse events of trayicon can be catched
    -   in QApplication event filter (TQtWidgetSet.EventFilter),
    -   so OnMouseDown and OnMouseUp can be properly sent.
    -   Check if it works ok on qtwin32 and qtmac and
    -   then replace this blind calls to mouse events.
    -   To get systryicon object handle in application event filter
    -   add property "lclsystrayicon" to this handle.}
    -  case AReason of
    -    QSystemTrayIconTrigger:
    -      begin
    -        if Assigned(FTrayIcon.OnMouseDown) then
    -          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
    -        if Assigned(FTrayIcon.OnClick) then
    -          FTrayIcon.OnClick(FTrayIcon);
    -        if Assigned(FTrayIcon.OnMouseUp) then
    -          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
    -      end;
    -    QSystemTrayIconDoubleClick:
    -      begin
    -        if Assigned(FTrayIcon.OnMouseDown) then
    -          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
    -
    -        if Assigned(FTrayIcon.OnDblClick) then
    -          FTrayIcon.OnDblClick(FTrayIcon);
    -
    -        if Assigned(FTrayIcon.OnMouseUp) then
    -          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
    -      end;
    -    QSystemTrayIconMiddleClick:
    -      begin
    -        if Assigned(FTrayIcon.OnMouseDown) then
    -          FTrayIcon.OnMouseDown(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
    -        if Assigned(FTrayIcon.OnMouseUp) then
    -          FTrayIcon.OnMouseUp(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
    -      end;
    -    QSystemTrayIconContext:
    -      begin
    -        if Assigned(FTrayIcon.OnMouseDown) then
    -          FTrayIcon.OnMouseDown(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
    -
    -        if Assigned(FTrayIcon.OnMouseUp) then
    -          FTrayIcon.OnMouseUp(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
    -      end;
    -  end;
    -end;
    -
    -procedure TQtSystemTrayIcon.showBaloonHint(const ATitle, AHint: String;
    -  const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
    -var
    -  WHint: WideString;
    -  WTitle: WideString;
    -begin
    -  WHint := GetUTF8String(AHint);
    -  WTitle := GetUTF8String(ATitle);
    -  QSystemTrayIcon_showMessage(Handle, @WTitle, @WHint, AFlag, ATimeOut);
    -end;
    -
    -procedure TQtSystemTrayIcon.Show;
    -begin
    -  QSystemTrayIcon_show(handle);
    -end;
    -
    -procedure TQtSystemTrayIcon.Hide;
    -begin
    -  QSystemTrayIcon_hide(handle);
    -end;
    -
     { TQtButtonGroup }
     
     constructor TQtButtonGroup.Create(AParent: QObjectH);
    Index: lcl/interfaces/qt/qtobject.inc
    ===================================================================
    --- lcl/interfaces/qt/qtobject.inc	(revision 44672)
    +++ lcl/interfaces/qt/qtobject.inc	(working copy)
    @@ -91,6 +91,7 @@
       System.InitCriticalSection(CriticalSection);
       SavedHandlesList := TMap.Create(TMapIdType(ituPtrSize), SizeOf(TObject));
       FSocketEventMap := TMap.Create(TMapIdType(its4), SizeOf(Pointer));
    +  SysTrayIconsList := TFPList.Create;
       StayOnTopList := nil;
       FAppActive := False;
       {$IFDEF HASX11}
    @@ -158,6 +159,13 @@
         SavedHintHandlesList := nil;
       end;
       {$ENDIF}
    +
    +  if SysTrayIconsList <> nil then
    +  begin
    +    SysTrayIconsList.Free;
    +    SysTrayIconsList := nil;
    +  end;
    +
       FSocketEventMap.Free;
       FGlobalActions.Free;
     
    @@ -547,6 +555,7 @@
       ASequence: QKeySequenceH;
       AKey: WideString;
       AParent: QWidgetH;
    +  R: TRect;
     
       function IsAnyWindowActive: Boolean;
       begin
    @@ -555,10 +564,102 @@
           (QApplication_activePopupWidget() <> nil);
       end;
     
    +  function IsSystemTrayWidget(AEventType: Cardinal): boolean;
    +  var
    +    AName: WideString;
    +    AWidget: QWidgetH;
    +    RGeom: TRect;
    +    AFlags: QtWindowFlags;
    +    i: Integer;
    +  begin
    +    Result := False;
    +    if QObject_isWidgetType(Sender) then
    +    begin
    +      AWidget := QWidgetH(Sender);
    +      QObject_objectName(Sender, @AName);
    +      if UTF8Copy(AName, 1, 16) = 'qtlclsystrayicon' then
    +      begin
    +        for i := 0 to SysTrayIconsList.Count - 1 do
    +        begin
    +          RGeom := TQtSystemTrayIcon(SysTrayIconsList.Items[i]).GetGeometry;
    +          if TQtSystemTrayIcon(SysTrayIconsList.Items[i]).SysTrayWidget = nil then
    +          begin
    +            if QApplication_widgetAt(RGeom.Left, RGeom.Top) = AWidget then
    +              TQtSystemTrayIcon(SysTrayIconsList.Items[i]).AttachSysTrayWidget(AWidget);
    +          end;
    +        end;
    +        exit(True);
    +      end;
    +      if QWidget_isWindow(AWidget) and (QWidget_parentWidget(AWidget) = nil) then
    +      begin
    +        AFlags := QWidget_windowFlags(AWidget);
    +        if QWidget_testAttribute(AWidget, QtWA_AlwaysShowToolTips) and
    +          QWidget_testAttribute(AWidget, QtWA_PaintOnScreen) and
    +          QWidget_testAttribute(AWidget, QtWA_NoSystemBackground) and
    +          not QWidget_testAttribute(AWidget, QtWA_QuitOnClose) and
    +          (AFlags and QtFramelessWindowHint = QtFramelessWindowHint) and
    +          (AFlags and QtX11BypassWindowManagerHint = QtX11BypassWindowManagerHint) then
    +        begin
    +          if HwndFromWidgetH(AWidget) = 0 then
    +          begin
    +            // we must find it by geometry, but it's innacurate since
    +            // qt systrayicon widget returns -1,-1 for left & top, so we
    +            // use QApplication_widgetAt().
    +            // Another problem is that QSystemTrayIcon geometry is updated
    +            // too late, much after QEventShow/QEventShowToParent
    +            // so no way to catch private QWidget until we enter
    +            // it by mouse.
    +            for i := 0 to SysTrayIconsList.Count - 1 do
    +            begin
    +              RGeom := TQtSystemTrayIcon(SysTrayIconsList.Items[i]).GetGeometry;
    +              if QApplication_widgetAt(RGeom.Left, RGeom.Top) = AWidget then
    +              begin
    +                AName := 'qtlclsystrayicon_' + dbgHex(PtrUInt(AWidget));
    +                QObject_setObjectName(Sender, @AName);
    +                TQtSystemTrayIcon(SysTrayIconsList.Items[i]).AttachSysTrayWidget(AWidget);
    +                {$IFDEF DEBUGSYSTRAYICON}
    +                DebugLn('Attached systemtrayicon[',dbgs(I),'] with geometry ',dbgs(RGeom),' dbg=',
    +                  dbgsName(TQtSystemTrayIcon(SysTrayIconsList.Items[i]).FTrayIcon));
    +                {$ENDIF}
    +                TQtSystemTrayIcon(SysTrayIconsList.Items[i]).UpdateSystemTrayWidget;
    +                Result := True;
    +                break;
    +              end;
    +            end;
    +          end;
    +        end;
    +      end;
    +    end;
    +  end;
    +
     begin
       Result := False;
    +
    +  // find QSystemTrayIcon
    +  if QObject_isWidgetType(Sender) and (QObject_parent(Sender) = nil) and
    +    QWidget_isWindow(QWidgetH(Sender)) and
    +    (QWidget_focusPolicy(QWidgetH(Sender)) = QtNoFocus) then
    +  begin
    +    AParent := QWidgetH(Sender);
    +    QWidget_frameGeometry(AParent, @R);
    +    if (R.Left = -1) and (R.Top = -1) and (R.Right > 0) and (R.Bottom > 0) then
    +    begin
    +      {$IFDEF DEBUGSYSTRAYICON}
    +      DebugLn('EVENT: ',dbgs(QEvent_type(Event)),' Sender 0x',dbgHex(PtrUInt(Sender)),' geometry ',dbgs(R));
    +      {$ENDIF}
    +      if (QEvent_type(Event) = QEventShowToParent) or (QEvent_type(Event) = QEventEnter) then
    +      begin
    +        if IsSystemTrayWidget(QEvent_type(Event)) then
    +        begin
    +          {$IFDEF DEBUGSYSTRAYICON}
    +          DebugLn('Found SystemTrayIcon via event ',dbgs(QEvent_type(Event)),' SYSTRAYICON 0x',dbgHex(PtrUInt(Sender)));
    +          {$ENDIF}
    +        end;
    +      end;
    +    end;
    +  end;
    +
       case QEvent_type(Event) of
    -
         QEventShortcutOverride: // issue #22827
         begin
           QKeyEvent_text(QKeyEventH(Event), @AKey);
    @@ -1142,6 +1243,21 @@
       System.LeaveCriticalsection(CriticalSection);
     end;
     
    +procedure TQtWidgetSet.RegisterSysTrayIcon(AHandle: TObject);
    +begin
    +  SysTrayIconsList.Add(AHandle);
    +end;
    +
    +procedure TQtWidgetSet.UnRegisterSysTrayIcon(AHandle: TObject);
    +begin
    +  SysTrayIconsList.Remove(AHandle);
    +end;
    +
    +function TQtWidgetSet.IsValidSysTrayIcon(AHandle: HWND): Boolean;
    +begin
    +  Result := SysTrayIconsList.IndexOf(TObject(AHandle)) >= 0;
    +end;
    +
     {$IFDEF HASX11}
     procedure TQtWidgetSet.AddHintHandle(AHandle: TObject);
     begin
    Index: lcl/interfaces/qt/qtwsextctrls.pp
    ===================================================================
    --- lcl/interfaces/qt/qtwsextctrls.pp	(revision 44672)
    +++ lcl/interfaces/qt/qtwsextctrls.pp	(working copy)
    @@ -25,7 +25,7 @@
     uses
       // Bindings
       qt4,
    -  qtwidgets, qtobjects, qtproc, QtWSControls,
    +  qtwidgets, qtobjects, qtsystemtrayicon, qtproc, QtWSControls,
       // LCL
       LCLProc,
       SysUtils, Classes, Controls, Graphics, Forms, ExtCtrls, LCLType,
    @@ -152,6 +152,7 @@
         class procedure InternalUpdate(const ATrayIcon: TCustomTrayIcon); override;
         class function ShowBalloonHint(const ATrayIcon: TCustomTrayIcon): Boolean; override;
         class function GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint; override;
    +    class function GetCanvas(const ATrayIcon: TCustomTrayIcon): TCanvas; override;
       end;
     
     implementation
    @@ -334,6 +335,9 @@
       if Assigned(ATrayIcon.PopUpMenu) then
         if TQtMenu(ATrayIcon.PopUpMenu.Handle).Widget <> nil then
           SystemTrayIcon.setContextMenu(QMenuH(TQtMenu(ATrayIcon.PopUpMenu.Handle).Widget));
    +
    +  SystemTrayIcon.UpdateSystemTrayWidget;
    +
     end;
     
     class function TQtWSCustomTrayIcon.ShowBalloonHint(
    @@ -355,6 +359,17 @@
     class function TQtWSCustomTrayIcon.GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint;
     begin
       Result := Point(0, 0);
    +  if (ATrayIcon.Handle = 0) then
    +    exit;
    +  Result := TQtSystemTrayIcon(ATrayIcon.Handle).GetPosition;
     end;
     
    +class function TQtWSCustomTrayIcon.GetCanvas(const ATrayIcon: TCustomTrayIcon
    +  ): TCanvas;
    +begin
    +  Result := nil;
    +  if (ATrayIcon.Handle <> 0) then
    +    Result := TQtSystemTrayIcon(ATrayIcon.Handle).Canvas;
    +end;
    +
     end.
    Index: lcl/interfaces/qt/qtint.pp
    ===================================================================
    --- lcl/interfaces/qt/qtint.pp	(revision 44672)
    +++ lcl/interfaces/qt/qtint.pp	(working copy)
    @@ -65,6 +65,7 @@
         SavedHandlesList: TMap;
         FSocketEventMap: TMap;
         StayOnTopList: TMap;
    +    SysTrayIconsList: TFPList;
         // global hooks
         FAppEvenFilterHook: QObject_hookH;
         FAppFocusChangedHook: QApplication_hookH;
    @@ -157,6 +158,11 @@
         procedure RemoveHandle(AHandle: TObject);
         function IsValidHandle(AHandle: HWND): Boolean;
     
    +    // qt systray icons map
    +    procedure RegisterSysTrayIcon(AHandle: TObject);
    +    procedure UnRegisterSysTrayIcon(AHandle: TObject);
    +    function IsValidSysTrayIcon(AHandle: HWND): Boolean;
    +
         {$IFDEF HASX11}
         // qt hints handles map (needed on X11 only)
         procedure AddHintHandle(AHandle: TObject);
    @@ -307,7 +313,7 @@
     ////////////////////////////////////////////////////
       Graphics, buttons, Menus,
       // Bindings
    -  qtprivate, qtwidgets, qtobjects;
    +  qtprivate, qtwidgets, qtobjects, qtsystemtrayicon;
     
     function DTFlagsToQtFlags(const Flags: Cardinal): Integer;
     begin
    Index: lcl/interfaces/lcl.lpk
    ===================================================================
    --- lcl/interfaces/lcl.lpk	(revision 44672)
    +++ lcl/interfaces/lcl.lpk	(working copy)
    @@ -129,7 +129,7 @@
         <License Value="modified LGPL-2
     "/>
         <Version Major="1" Minor="3"/>
    -    <Files Count="429">
    +    <Files Count="430">
           <Item1>
             <Filename Value="carbon/agl.pp"/>
             <AddToUsesPkgSection Value="False"/>
    @@ -2135,6 +2135,11 @@
             <AddToUsesPkgSection Value="False"/>
             <UnitName Value="LazPangoCairo1"/>
           </Item429>
    +      <Item430>
    +        <Filename Value="qt/qtsystemtrayicon.pas"/>
    +        <AddToUsesPkgSection Value="False"/>
    +        <UnitName Value="qtsystemtrayicon"/>
    +      </Item430>
         </Files>
         <LazDoc Paths="../../docs/xml/lcl"/>
         <i18n>
    
  • lazarus-1.2.4-mga-qtsystemtrayicon-events.patch (14,042 bytes)
    diff -ur lazarus.orig/lcl/interfaces/lcl.lpk lazarus/lcl/interfaces/lcl.lpk
    --- lazarus.orig/lcl/interfaces/lcl.lpk	2014-06-14 09:36:52.000000000 +0400
    +++ lazarus/lcl/interfaces/lcl.lpk	2014-09-02 17:58:51.000000000 +0400
    @@ -129,7 +129,7 @@
         <License Value="modified LGPL-2
     "/>
         <Version Major="1" Minor="2" Release="4"/>
    -    <Files Count="429">
    +    <Files Count="430">
           <Item1>
             <Filename Value="carbon/agl.pp"/>
             <AddToUsesPkgSection Value="False"/>
    @@ -2134,6 +2134,11 @@
             <AddToUsesPkgSection Value="False"/>
             <UnitName Value="LazPangoCairo1"/>
           </Item429>
    +      <Item430>
    +        <Filename Value="qt/qtsystemtrayicon.pas"/>
    +        <AddToUsesPkgSection Value="False"/>
    +        <UnitName Value="qtsystemtrayicon"/>
    +      </Item430>
         </Files>
         <LazDoc Paths="../../docs/xml/lcl"/>
         <i18n>
    diff -ur lazarus.orig/lcl/interfaces/qt/qtint.pp lazarus/lcl/interfaces/qt/qtint.pp
    --- lazarus.orig/lcl/interfaces/qt/qtint.pp	2014-05-09 18:33:04.000000000 +0400
    +++ lazarus/lcl/interfaces/qt/qtint.pp	2014-09-02 17:57:54.000000000 +0400
    @@ -65,6 +65,7 @@
         SavedHandlesList: TMap;
         FSocketEventMap: TMap;
         StayOnTopList: TMap;
    +    SysTrayIconsList: TFPList;
         // global hooks
         FAppEvenFilterHook: QObject_hookH;
         FAppFocusChangedHook: QApplication_hookH;
    @@ -156,6 +157,11 @@
         procedure AddHandle(AHandle: TObject);
         procedure RemoveHandle(AHandle: TObject);
         function IsValidHandle(AHandle: HWND): Boolean;
    +    
    +    // qt systray icons map
    +    procedure RegisterSysTrayIcon(AHandle: TObject);
    +    procedure UnRegisterSysTrayIcon(AHandle: TObject);
    +    function IsValidSysTrayIcon(AHandle: HWND): Boolean;
     
         {$IFDEF HASX11}
         // qt hints handles map (needed on X11 only)
    @@ -311,7 +317,7 @@
     ////////////////////////////////////////////////////
       Graphics, buttons, Menus,
       // Bindings
    -  qtprivate, qtwidgets, qtobjects;
    +  qtprivate, qtwidgets, qtobjects, qtsystemtrayicon;
     
     function DTFlagsToQtFlags(const Flags: Cardinal): Integer;
     begin
    diff -ur lazarus.orig/lcl/interfaces/qt/qtobject.inc lazarus/lcl/interfaces/qt/qtobject.inc
    --- lazarus.orig/lcl/interfaces/qt/qtobject.inc	2014-05-07 19:56:22.000000000 +0400
    +++ lazarus/lcl/interfaces/qt/qtobject.inc	2014-09-02 17:54:19.000000000 +0400
    @@ -91,6 +91,7 @@
       System.InitCriticalSection(CriticalSection);
       SavedHandlesList := TMap.Create(TMapIdType(ituPtrSize), SizeOf(TObject));
       FSocketEventMap := TMap.Create(TMapIdType(its4), SizeOf(Pointer));
    +  SysTrayIconsList := TFPList.Create;
       StayOnTopList := nil;
       FAppActive := False;
       {$IFDEF HASX11}
    @@ -158,6 +159,13 @@
         SavedHintHandlesList := nil;
       end;
       {$ENDIF}
    +
    +  if SysTrayIconsList <> nil then
    +  begin
    +    SysTrayIconsList.Free;
    +    SysTrayIconsList := nil;
    +  end;
    +
       FSocketEventMap.Free;
       FGlobalActions.Free;
     
    @@ -547,6 +555,7 @@
       ASequence: QKeySequenceH;
       AKey: WideString;
       AParent: QWidgetH;
    +  R: TRect;
     
       function IsAnyWindowActive: Boolean;
       begin
    @@ -555,8 +564,101 @@
           (QApplication_activePopupWidget() <> nil);
       end;
     
    +  function IsSystemTrayWidget(AEventType: Cardinal): boolean;
    +  var
    +    AName: WideString;
    +    AWidget: QWidgetH;
    +    RGeom: TRect;
    +    AFlags: QtWindowFlags;
    +    i: Integer;
    +  begin
    +    Result := False;
    +    if QObject_isWidgetType(Sender) then
    +    begin
    +      AWidget := QWidgetH(Sender);
    +      QObject_objectName(Sender, @AName);
    +      if UTF8Copy(AName, 1, 16) = 'qtlclsystrayicon' then
    +      begin
    +        for i := 0 to SysTrayIconsList.Count - 1 do
    +        begin
    +          RGeom := TQtSystemTrayIcon(SysTrayIconsList.Items[i]).GetGeometry;
    +          if TQtSystemTrayIcon(SysTrayIconsList.Items[i]).SysTrayWidget = nil then
    +          begin
    +            if QApplication_widgetAt(RGeom.Left, RGeom.Top) = AWidget then
    +              TQtSystemTrayIcon(SysTrayIconsList.Items[i]).AttachSysTrayWidget(AWidget);
    +          end;
    +        end;
    +        exit(True);
    +      end;
    +      if QWidget_isWindow(AWidget) and (QWidget_parentWidget(AWidget) = nil) then
    +      begin
    +        AFlags := QWidget_windowFlags(AWidget);
    +        if QWidget_testAttribute(AWidget, QtWA_AlwaysShowToolTips) and
    +          QWidget_testAttribute(AWidget, QtWA_PaintOnScreen) and
    +          QWidget_testAttribute(AWidget, QtWA_NoSystemBackground) and
    +          not QWidget_testAttribute(AWidget, QtWA_QuitOnClose) and
    +          (AFlags and QtFramelessWindowHint = QtFramelessWindowHint) and
    +          (AFlags and QtX11BypassWindowManagerHint = QtX11BypassWindowManagerHint) then
    +        begin
    +          if HwndFromWidgetH(AWidget) = 0 then
    +          begin
    +            // we must find it by geometry, but it's innacurate since
    +            // qt systrayicon widget returns -1,-1 for left & top, so we
    +            // use QApplication_widgetAt().
    +            // Another problem is that QSystemTrayIcon geometry is updated
    +            // too late, much after QEventShow/QEventShowToParent
    +            // so no way to catch private QWidget until we enter
    +            // it by mouse.
    +            for i := 0 to SysTrayIconsList.Count - 1 do
    +            begin
    +              RGeom := TQtSystemTrayIcon(SysTrayIconsList.Items[i]).GetGeometry;
    +              if QApplication_widgetAt(RGeom.Left, RGeom.Top) = AWidget then
    +              begin
    +                AName := 'qtlclsystrayicon_' + dbgHex(PtrUInt(AWidget));
    +                QObject_setObjectName(Sender, @AName);
    +                TQtSystemTrayIcon(SysTrayIconsList.Items[i]).AttachSysTrayWidget(AWidget);
    +                {$IFDEF DEBUGSYSTRAYICON}
    +                DebugLn('Attached systemtrayicon[',dbgs(I),'] with geometry ',dbgs(RGeom),' dbg=',
    +                  dbgsName(TQtSystemTrayIcon(SysTrayIconsList.Items[i]).FTrayIcon));
    +                {$ENDIF}
    +                TQtSystemTrayIcon(SysTrayIconsList.Items[i]).UpdateSystemTrayWidget;
    +                Result := True;
    +                break;
    +              end;
    +            end;
    +          end;
    +        end;
    +      end;
    +    end;
    +  end;
    +
     begin
       Result := False;
    +
    +  // find QSystemTrayIcon
    +  if QObject_isWidgetType(Sender) and (QObject_parent(Sender) = nil) and
    +    QWidget_isWindow(QWidgetH(Sender)) and
    +    (QWidget_focusPolicy(QWidgetH(Sender)) = QtNoFocus) then
    +  begin
    +    AParent := QWidgetH(Sender);
    +    QWidget_frameGeometry(AParent, @R);
    +    if (R.Left = -1) and (R.Top = -1) and (R.Right > 0) and (R.Bottom > 0) then
    +    begin
    +      {$IFDEF DEBUGSYSTRAYICON}
    +      DebugLn('EVENT: ',dbgs(QEvent_type(Event)),' Sender 0x',dbgHex(PtrUInt(Sender)),' geometry ',dbgs(R));
    +      {$ENDIF}
    +      if (QEvent_type(Event) = QEventShowToParent) or (QEvent_type(Event) = QEventEnter) then
    +      begin
    +        if IsSystemTrayWidget(QEvent_type(Event)) then
    +        begin
    +          {$IFDEF DEBUGSYSTRAYICON}
    +          DebugLn('Found SystemTrayIcon via event ',dbgs(QEvent_type(Event)),' SYSTRAYICON 0x',dbgHex(PtrUInt(Sender)));
    +          {$ENDIF}
    +        end;
    +      end;
    +    end;
    +  end;
    +
       case QEvent_type(Event) of
         QEventShortcutOverride: // issue #22827
         begin
    @@ -1140,6 +1242,21 @@
       System.LeaveCriticalsection(CriticalSection);
     end;
     
    +procedure TQtWidgetSet.RegisterSysTrayIcon(AHandle: TObject);
    +begin
    +  SysTrayIconsList.Add(AHandle);
    +end;
    +
    +procedure TQtWidgetSet.UnRegisterSysTrayIcon(AHandle: TObject);
    +begin
    +  SysTrayIconsList.Remove(AHandle);
    +end;
    +
    +function TQtWidgetSet.IsValidSysTrayIcon(AHandle: HWND): Boolean;
    +begin
    +  Result := SysTrayIconsList.IndexOf(TObject(AHandle)) >= 0;
    +end;
    +
     procedure TQtWidgetSet.RemoveHandle(AHandle: TObject);
     begin
       System.EnterCriticalsection(CriticalSection);
    diff -ur lazarus.orig/lcl/interfaces/qt/qtobjects.pas lazarus/lcl/interfaces/qt/qtobjects.pas
    --- lazarus.orig/lcl/interfaces/qt/qtobjects.pas	2014-05-13 01:17:16.000000000 +0400
    +++ lazarus/lcl/interfaces/qt/qtobjects.pas	2014-09-02 17:50:35.000000000 +0400
    @@ -520,28 +520,6 @@
         property Handle: QCursorH read FHandle;
       end;
       
    -  { TQtSystemTrayIcon }
    -
    -  TQtSystemTrayIcon = class(TObject)
    -  private
    -    FHook: QSystemTrayIcon_hookH;
    -  public
    -    Handle: QSystemTrayIconH;
    -    FTrayIcon: TCustomTrayIcon;
    -  public
    -    constructor Create(vIcon: QIconH); virtual;
    -    destructor Destroy; override;
    -  public
    -    procedure setContextMenu(menu: QMenuH);
    -    procedure setIcon(icon: QIconH);
    -    procedure setToolTip(tip: WideString);
    -    procedure signalActivated(AReason: QSystemTrayIconActivationReason); cdecl;
    -    procedure showBaloonHint(const ATitle, AHint: String;
    -      const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
    -    procedure Show;
    -    procedure Hide;
    -  end;
    -  
       { TQtButtonGroup }
       
       TQtButtonGroup = class(TObject)
    @@ -3690,119 +3668,6 @@
       QPixmap_fromImage(retval, image, flags);
     end;
     
    -{ TQtSystemTrayIcon }
    -
    -constructor TQtSystemTrayIcon.Create(vIcon: QIconH);
    -begin
    -  inherited Create;
    -
    -  if vIcon <> nil then
    -    Handle := QSystemTrayIcon_create(vicon, nil)
    -  else
    -    Handle := QSystemTrayIcon_create();
    -  FHook := QSystemTrayIcon_hook_create(Handle);
    -  QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
    -end;
    -
    -destructor TQtSystemTrayIcon.Destroy;
    -begin
    -  QSystemTrayIcon_hook_destroy(FHook);
    -  QSystemTrayIcon_destroy(Handle);
    -  
    -  inherited Destroy;
    -end;
    -
    -procedure TQtSystemTrayIcon.setContextMenu(menu: QMenuH);
    -begin
    -  QSystemTrayIcon_setContextMenu(handle, menu);
    -end;
    -
    -procedure TQtSystemTrayIcon.setIcon(icon: QIconH);
    -begin
    -  QSystemTrayIcon_setIcon(handle, icon);
    -end;
    -
    -procedure TQtSystemTrayIcon.setToolTip(tip: WideString);
    -begin
    -  QSystemTrayIcon_setToolTip(handle, @tip)
    -end;
    -
    -procedure TQtSystemTrayIcon.signalActivated(
    -  AReason: QSystemTrayIconActivationReason); cdecl;
    -var
    -  MousePos: TQtPoint;
    -begin
    -  if not Assigned(FTrayIcon) then
    -    exit;
    -
    -  QCursor_pos(@MousePos);
    -  {$note: TODO: Mouse events of trayicon can be catched
    -   in QApplication event filter (TQtWidgetSet.EventFilter),
    -   so OnMouseDown and OnMouseUp can be properly sent.
    -   Check if it works ok on qtwin32 and qtmac and
    -   then replace this blind calls to mouse events.
    -   To get systryicon object handle in application event filter
    -   add property "lclsystrayicon" to this handle.}
    -  case AReason of
    -    QSystemTrayIconTrigger:
    -      begin
    -        if Assigned(FTrayIcon.OnMouseDown) then
    -          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
    -        if Assigned(FTrayIcon.OnClick) then
    -          FTrayIcon.OnClick(FTrayIcon);
    -        if Assigned(FTrayIcon.OnMouseUp) then
    -          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
    -      end;
    -    QSystemTrayIconDoubleClick:
    -      begin
    -        if Assigned(FTrayIcon.OnMouseDown) then
    -          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
    -
    -        if Assigned(FTrayIcon.OnDblClick) then
    -          FTrayIcon.OnDblClick(FTrayIcon);
    -
    -        if Assigned(FTrayIcon.OnMouseUp) then
    -          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
    -      end;
    -    QSystemTrayIconMiddleClick:
    -      begin
    -        if Assigned(FTrayIcon.OnMouseDown) then
    -          FTrayIcon.OnMouseDown(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
    -        if Assigned(FTrayIcon.OnMouseUp) then
    -          FTrayIcon.OnMouseUp(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
    -      end;
    -    QSystemTrayIconContext:
    -      begin
    -        if Assigned(FTrayIcon.OnMouseDown) then
    -          FTrayIcon.OnMouseDown(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
    -
    -        if Assigned(FTrayIcon.OnMouseUp) then
    -          FTrayIcon.OnMouseUp(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
    -      end;
    -  end;
    -end;
    -
    -procedure TQtSystemTrayIcon.showBaloonHint(const ATitle, AHint: String;
    -  const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
    -var
    -  WHint: WideString;
    -  WTitle: WideString;
    -begin
    -  WHint := GetUTF8String(AHint);
    -  WTitle := GetUTF8String(ATitle);
    -  QSystemTrayIcon_showMessage(Handle, @WTitle, @WHint, AFlag, ATimeOut);
    -end;
    -
    -procedure TQtSystemTrayIcon.Show;
    -begin
    -  QSystemTrayIcon_show(handle);
    -end;
    -
    -procedure TQtSystemTrayIcon.Hide;
    -begin
    -  QSystemTrayIcon_hide(handle);
    -end;
    -
     { TQtButtonGroup }
     
     constructor TQtButtonGroup.Create(AParent: QObjectH);
    diff -ur lazarus.orig/lcl/interfaces/qt/qtwsextctrls.pp lazarus/lcl/interfaces/qt/qtwsextctrls.pp
    --- lazarus.orig/lcl/interfaces/qt/qtwsextctrls.pp	2013-09-06 10:16:53.000000000 +0400
    +++ lazarus/lcl/interfaces/qt/qtwsextctrls.pp	2014-09-02 17:56:37.000000000 +0400
    @@ -25,7 +25,7 @@
     uses
       // Bindings
       qt4,
    -  qtwidgets, qtobjects, qtproc, QtWSControls,
    +  qtwidgets, qtobjects, qtsystemtrayicon, qtproc, QtWSControls,
       // LCL
       LCLProc,
       SysUtils, Classes, Controls, Graphics, Forms, ExtCtrls, LCLType,
    @@ -152,6 +152,7 @@
         class procedure InternalUpdate(const ATrayIcon: TCustomTrayIcon); override;
         class function ShowBalloonHint(const ATrayIcon: TCustomTrayIcon): Boolean; override;
         class function GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint; override;
    +    class function GetCanvas(const ATrayIcon: TCustomTrayIcon): TCanvas; override;
       end;
     
     implementation
    @@ -288,6 +289,8 @@
         if TQtMenu(ATrayIcon.PopUpMenu.Handle).Widget <> nil then
           SystemTrayIcon.setContextMenu(QMenuH(TQtMenu(ATrayIcon.PopUpMenu.Handle).Widget));
     
    +  SystemTrayIcon.UpdateSystemTrayWidget;
    +
       SystemTrayIcon.show;
     
       Result := True;
    @@ -355,6 +358,17 @@
     class function TQtWSCustomTrayIcon.GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint;
     begin
       Result := Point(0, 0);
    +  if (ATrayIcon.Handle = 0) then
    +    exit;
    +  Result := TQtSystemTrayIcon(ATrayIcon.Handle).GetPosition;
    +end;
    +
    +class function TQtWSCustomTrayIcon.GetCanvas(const ATrayIcon: TCustomTrayIcon
    +  ): TCanvas;
    +begin
    +  Result := nil;
    +  if (ATrayIcon.Handle <> 0) then
    +    Result := TQtSystemTrayIcon(ATrayIcon.Handle).Canvas;
     end;
     
     end.
    

Activities

Zeljan Rikalo

2012-10-26 20:36

developer   ~0063479

What widgetset ?

zmey

2012-10-26 20:51

reporter   ~0063481

gtk2

Stas

2012-10-26 22:03

reporter   ~0063484

Yes bug present in Lazarus 1.0.2 Linux Gtk2

zmey

2012-10-27 06:10

reporter   ~0063490

qt4 don't work also.

zmey

2013-05-14 17:06

reporter   ~0067697

When will be fix?

word

2013-10-27 09:17

reporter   ~0070989

Why is one year ago bug not assigned and closed?

Zeljan Rikalo

2013-10-27 13:26

developer   ~0070993

Because nobody have time for this ? Feel free to create patch and attach, so it will be fixed then.

word

2013-11-12 19:33

reporter   ~0071285

No problem with lazarus-0.9.30.4
Please, cancel your changes with TTrayIcon.

AlexL

2014-04-09 16:11

reporter  

lazarus_trayicon_onmousemove_mga.patch (6,196 bytes)
diff -ur lazarus.orig/lcl/interfaces/gtk2/gtk2trayicon.inc lazarus/lcl/interfaces/gtk2/gtk2trayicon.inc
--- lazarus.orig/lcl/interfaces/gtk2/gtk2trayicon.inc	2012-04-17 11:55:52.000000000 +0400
+++ lazarus/lcl/interfaces/gtk2/gtk2trayicon.inc	2014-04-09 15:19:52.000000000 +0400
@@ -365,6 +365,16 @@
   end;
 end;
 
+function query_tooltip_cb_statusicon({%H-}status_icon: PGtkStatusIcon;
+  x: guint; y: guint; {%H-}keyboard_mode: gboolean; {%H-}tooltip: gpointer{PGtkTooltip}; user_data: gpointer): gboolean; cdecl;
+var
+  vwsTrayIcon: TCustomTrayIcon absolute user_data;
+begin
+  Result := FALSE;
+
+  if Assigned(vwsTrayIcon.OnMouseMove) then
+   vwsTrayIcon.OnMouseMove(vwsTrayIcon, [], x, y);
+end;
 {$endif}
 
 constructor TGtk2TrayIconHandle.Create(const wsTrayIcon: TCustomTrayIcon);
@@ -378,12 +388,14 @@
     FStatusIcon := gtk_status_icon_new();
     gtk_status_icon_set_from_pixbuf(FStatusIcon, {%H-}PGdkPixbuf(FTrayIcon.Icon.Handle));
     gtk_status_icon_set_tooltip(FStatusIcon, PChar(FTrayIcon.Hint));
+    g_object_set(PGObject(FStatusIcon), 'has-tooltip', TRUE);
     fEmbedded := gtk_status_icon_is_embedded(FStatusIcon);
 
     g_signal_connect(FStatusIcon, 'activate', TGCallback(@activate_cb_statusicon), fTrayIcon);
     g_signal_connect(FStatusIcon, 'popup-menu', TGCallback(@popup_cb_statusicon), fTrayIcon);
     g_signal_connect(FStatusIcon, 'button-press-event', TGCallback(@button_press_cb_statusicon), fTrayIcon);
     g_signal_connect(FStatusIcon, 'button-release-event', TGCallback(@button_release_cb_statusicon), fTrayIcon);
+    g_signal_connect(FStatusIcon, 'query-tooltip', TGCallback(@query_tooltip_cb_statusicon), fTrayIcon);
   end
   else
 {$endif}
@@ -407,8 +419,8 @@
     with wsTrayIcon do
     begin
       DrawingArea := gtk_image_new_from_pixbuf({%H-}PGdkPixbuf(Icon.Handle));
-      gtk_widget_show(DrawingArea);
       gtk_container_add(GTK_CONTAINER(plug), DrawingArea);
+      gtk_widget_show(DrawingArea);
     end;
   end;
 end;
@@ -478,6 +490,7 @@
   begin
     gtk_status_icon_set_from_pixbuf(FStatusIcon, NewPixBuf);
     gtk_status_icon_set_tooltip(FStatusIcon, PChar(NewHint));
+    g_object_set(PGObject(FStatusIcon), 'has-tooltip', TRUE);
   end
   else
 {$endif}
Только в lazarus/lcl/interfaces/gtk2: gtk2trayicon.inc.orig
diff -ur lazarus.orig/lcl/interfaces/qt/qtobjects.pas lazarus/lcl/interfaces/qt/qtobjects.pas
--- lazarus.orig/lcl/interfaces/qt/qtobjects.pas	2013-06-10 01:42:51.000000000 +0400
+++ lazarus/lcl/interfaces/qt/qtobjects.pas	2014-04-09 15:22:06.000000000 +0400
@@ -527,15 +527,17 @@
   
   { TQtSystemTrayIcon }
 
-  TQtSystemTrayIcon = class(TObject)
+  TQtSystemTrayIcon = class(TQtObject)
   private
     FHook: QSystemTrayIcon_hookH;
   public
-    Handle: QSystemTrayIconH;
     FTrayIcon: TCustomTrayIcon;
   public
     constructor Create(vIcon: QIconH); virtual;
     destructor Destroy; override;
+    procedure AttachEvents; override;
+    procedure DetachEvents; override;
+    function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; override;
   public
     procedure setContextMenu(menu: QMenuH);
     procedure setIcon(icon: QIconH);
@@ -3658,34 +3660,78 @@
   inherited Create;
 
   if vIcon <> nil then
-    Handle := QSystemTrayIcon_create(vicon, nil)
+    TheObject := QObjectH(QSystemTrayIcon_create(vicon, nil))
   else
-    Handle := QSystemTrayIcon_create();
-  FHook := QSystemTrayIcon_hook_create(Handle);
-  QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
+    TheObject := QObjectH(QSystemTrayIcon_create());
+  AttachEvents;
 end;
 
 destructor TQtSystemTrayIcon.Destroy;
 begin
-  QSystemTrayIcon_hook_destroy(FHook);
-  QSystemTrayIcon_destroy(Handle);
-  
   inherited Destroy;
 end;
 
+procedure TQtSystemTrayIcon.AttachEvents;
+begin
+  FHook := QSystemTrayIcon_hook_create(QSystemTrayIconH(TheObject));
+  QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
+  inherited AttachEvents;
+end;
+
+procedure TQtSystemTrayIcon.DetachEvents;
+begin
+  if FHook <> nil then
+    QSystemTrayIcon_hook_destroy(FHook);
+  inherited DetachEvents;
+end;
+
+function TQtSystemTrayIcon.EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl;
+var
+  x, y: integer;
+  MousePos: TQtPoint;
+  IconGeometry: TRect;
+begin
+  Result := False;
+  
+  if Assigned(FTrayIcon) then begin
+	case QEvent_type(Event) of
+		QEventMouseMove:
+		begin
+			x := QMouseEvent_x(QMouseEventH(Event));
+			y := QMouseEvent_y(QMouseEventH(Event));
+			
+			if Assigned(FTrayIcon.OnMouseMove) then
+				FTrayIcon.OnMouseMove(FTrayIcon, [], x, y);
+		end;
+		QEventToolTip, QEventWheel:
+		begin
+			QCursor_pos(@MousePos);
+			QSystemTrayIcon_geometry(QSystemTrayIconH(Sender), @IconGeometry);
+			x := MousePos.x - IconGeometry.Left;
+			y := MousePos.y - IconGeometry.Top;
+			
+			if Assigned(FTrayIcon.OnMouseMove) then
+				FTrayIcon.OnMouseMove(FTrayIcon, [], x, y);
+		end;
+	end;
+  end;
+  
+  QEvent_accept(Event);
+end;
+
 procedure TQtSystemTrayIcon.setContextMenu(menu: QMenuH);
 begin
-  QSystemTrayIcon_setContextMenu(handle, menu);
+  QSystemTrayIcon_setContextMenu(QSystemTrayIconH(TheObject), menu);
 end;
 
 procedure TQtSystemTrayIcon.setIcon(icon: QIconH);
 begin
-  QSystemTrayIcon_setIcon(handle, icon);
+  QSystemTrayIcon_setIcon(QSystemTrayIconH(TheObject), icon);
 end;
 
 procedure TQtSystemTrayIcon.setToolTip(tip: WideString);
 begin
-  QSystemTrayIcon_setToolTip(handle, @tip)
+  QSystemTrayIcon_setToolTip(QSystemTrayIconH(TheObject), @tip);
 end;
 
 procedure TQtSystemTrayIcon.signalActivated(
@@ -3751,17 +3797,17 @@
 begin
   WHint := GetUTF8String(AHint);
   WTitle := GetUTF8String(ATitle);
-  QSystemTrayIcon_showMessage(Handle, @WTitle, @WHint, AFlag, ATimeOut);
+  QSystemTrayIcon_showMessage(QSystemTrayIconH(TheObject), @WTitle, @WHint, AFlag, ATimeOut);
 end;
 
 procedure TQtSystemTrayIcon.Show;
 begin
-  QSystemTrayIcon_show(handle);
+  QSystemTrayIcon_show(QSystemTrayIconH(TheObject));
 end;
 
 procedure TQtSystemTrayIcon.Hide;
 begin
-  QSystemTrayIcon_hide(handle);
+  QSystemTrayIcon_hide(QSystemTrayIconH(TheObject));
 end;
 
 { TQtButtonGroup }
Только в lazarus/lcl/interfaces/qt: qtobjects.pas.orig

AlexL

2014-04-09 16:12

reporter   ~0074232

Patch with fix OnMouseMove for tTrayIcon for qt4 and gtk2 is in attachment (for lazarus 1.0.12).
There is 1 sec. delay for qt4, but I can not fix, please look. Good for gtk2.

Zeljan Rikalo

2014-04-10 17:03

developer   ~0074273

@AlexL
Qt4 patch isn't good. You have delay because it passes only QEventTooltip to the event filter and that's ONLY on X11 platforms.No other events are passed through event filter.

See what QSysTrayIcon docs says:
Only on X11, when a tooltip is requested, the QSystemTrayIcon receives a QHelpEvent of type QEvent::ToolTip. Additionally, the QSystemTrayIcon receives wheel events of type QEvent::Wheel. These are not supported on any other platform.

http://qt-project.org/doc/qt-4.8/qsystemtrayicon.html#details

Sorry, but your patch is unacceptable for qt part. Didn't test gtk2 one yet.

Zeljan Rikalo

2014-04-10 17:41

developer   ~0074276

Forgot to say that some object IS delivering events via QApplication eventFilter (I can see clear MouseMove etc.. over systrayicon) but dunno who can it be.
Definitelly it's not QSysTrayIconH object by itself.
It's thing to investigate. Just put QEventMouseMove in qtobject.inc in main app eventfilter and one writeln there and you'll see mouse move messages when moving mouse over systrayicon (at least it is so on X11, don't know for win and mac).

Zeljan Rikalo

2014-04-10 22:18

developer   ~0074285

Finally investigated:
https://qt.gitorious.org/qt/ducklink-qt/source/3040e55a8d4fd4418ae4e76269ebbe0a25406adf:src/gui/util/qsystemtrayicon_win.cpp
https://qt.gitorious.org/qt/ducklink-qt/source/3040e55a8d4fd4418ae4e76269ebbe0a25406adf:src/gui/util/qsystemtrayicon_x11.cpp

MouseMove will be pretty tricky to implement for qt widgetset (so that it works on linux, win and mac).

AlexL

2014-04-11 07:43

reporter   ~0074291

Only you can implement cross-platform solution. It's linux patch, and with patch is OK for linux now. It's better, than nothing within 1,5 years.
Now you know problem looking patch and can fix.

Zeljan Rikalo

2014-04-11 08:35

developer   ~0074292

Didn't I say that your patch IS NOT GOOD in case of qt ? There's nothing to look into your patch since it does not change anything, and QEventToolTip isn't good to provide mouse move event.
Maybe I'll fix it when I can be 100% sure that I've catched QSystemTrayIcon private QWidget in application eventfilter (maybe via direct x11 hook).

AlexL

2014-04-11 08:59

reporter   ~0074295

In any case I have no win or mac, only linux. Maybe gtk2 is OK?

Zeljan Rikalo

2014-04-11 09:12

developer   ~0074296

I'll test gtk2 part and commit if it's ok.

Zeljan Rikalo

2014-04-11 14:23

developer  

qtsystemtrayicon.pas (9,392 bytes)
unit qtsystemtrayicon;
{$mode objfpc}{$H+}

interface
{$i qtdefines.inc}

uses Classes, Controls, ExtCtrls, Graphics, Forms, LCLType, qtobjects, qt4,
  qtproc;

type
  TSysTrayIconPaintData = record
    PaintWidget: QWidgetH;
    ClipRect: Prect;
    ClipRegion: QRegionH;
    Context: TQtDeviceContext;
  end;

  { TQtSystemTrayIcon }

  TQtSystemTrayIcon = class(TQtObject)
  private
    FSysTrayHook: QObject_hookH;
    FHook: QSystemTrayIcon_hookH;
    FSysTrayWidget: QWidgetH;
    FCanvas: TCanvas;
    function BeginPaintInternal(var APaintData: TSysTrayIconPaintData): hdc;
    procedure EndPaintInternal(var APaintData: TSysTrayIconPaintData);
  public
    FTrayIcon: TCustomTrayIcon;
  public
    constructor Create(vIcon: QIconH); virtual;
    destructor Destroy; override;
  public
    procedure AttachEvents; override;
    procedure DetachEvents; override;
    procedure AttachSysTrayWidget(AWidget: QWidgetH);
    procedure DetachSysTrayWidget;
    function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; override;
    procedure setContextMenu(menu: QMenuH);
    procedure setIcon(icon: QIconH);
    procedure setToolTip(tip: WideString);
    procedure signalActivated(AReason: QSystemTrayIconActivationReason); cdecl;
    procedure showBaloonHint(const ATitle, AHint: String;
      const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
    function GetGeometry: TRect;
    function GetPosition: TPoint;
    procedure Show;
    procedure Hide;
    procedure UpdateSystemTrayWidget;
    property Canvas: TCanvas read FCanvas write FCanvas;
    property SysTrayWidget: QWidgetH read FSysTrayWidget;
  end;

implementation
uses qtint, LCLProc;

{ TQtSystemTrayIcon }

constructor TQtSystemTrayIcon.Create(vIcon: QIconH);
begin
  inherited Create;
  FSysTrayWidget := nil;
  FSysTrayHook := nil;
  if vIcon <> nil then
    TheObject := QSystemTrayIcon_create(vicon, nil)
  else
    TheObject := QSystemTrayIcon_create();
  FCanvas := nil;
  QtWidgetSet.RegisterSysTrayIcon(Self);
  AttachEvents;
end;

destructor TQtSystemTrayIcon.Destroy;
begin
  QtWidgetSet.UnRegisterSysTrayIcon(Self);
  inherited Destroy;
end;

procedure TQtSystemTrayIcon.AttachEvents;
begin
  inherited AttachEvents;
  FHook := QSystemTrayIcon_hook_create(QSystemTrayIconH(TheObject));
  QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
end;

procedure TQtSystemTrayIcon.DetachEvents;
begin
  DetachSysTrayWidget;
  if Assigned(FHook) then
  begin
    QSystemTrayIcon_hook_destroy(FHook);
    FHook := nil;
  end;
  inherited DetachEvents;
end;

procedure TQtSystemTrayIcon.AttachSysTrayWidget(AWidget: QWidgetH);
begin
  if (AWidget = nil) and (FSysTrayWidget <> nil) then
    DetachSysTrayWidget;
  FSysTrayWidget := AWidget;
  if FSysTrayWidget <> nil then
  begin
    FSysTrayHook := QObject_hook_create(FSysTrayWidget);
    QObject_hook_hook_events(FSysTrayHook, @EventFilter);
  end;
end;

procedure TQtSystemTrayIcon.DetachSysTrayWidget;
begin
  if FSysTrayWidget <> nil then
  begin
    if FSysTrayHook <> nil then
      QObject_hook_destroy(FSysTrayHook);
    FSysTrayHook := nil;
    FSysTrayWidget := niL;
  end;
end;

function TQtSystemTrayIcon.BeginPaintInternal(var APaintData: TSysTrayIconPaintData): hdc;
var
  DC: TQtDeviceContext;
begin
  DC := TQtDeviceContext.Create(FSysTrayWidget, True);
  Result := HDC(DC);
  if Result <> 0 then
  begin
    if (QtVersionMajor = 4) and (QtVersionMinor > 6) then
      QPainter_setLayoutDirection(DC.Widget, QtLayoutDirectionAuto);
    if APaintData.ClipRegion <> nil then
    begin
      DC.setClipRegion(APaintData.ClipRegion);
      DC.setClipping(True);
    end;
    if APaintData.ClipRect <> nil then
    begin
      New(DC.vClipRect);
      DC.vClipRect^ := APaintData.ClipRect^;
    end;
    APaintData.Context := DC;
  end;
end;

procedure TQtSystemTrayIcon.EndPaintInternal(var APaintData: TSysTrayIconPaintData);
begin
  if APaintData.ClipRect <> nil then
    Dispose(APaintData.ClipRect);
  if APaintData.Context <> nil then
    APaintData.Context.Free;
  APaintData.Context := nil;
end;

function TQtSystemTrayIcon.EventFilter(Sender: QObjectH; Event: QEventH
  ): Boolean; cdecl;
var
  X, Y: Integer;
  R: TRect;
  P: TQtPoint;
  AHint: WideString;
  PaintData: TSysTrayIconPaintData;
begin
  Result := False;
  if Sender <> FSysTrayWidget then
    exit;

  case QEvent_type(Event) of
    QEventPaint:
    begin
      if Assigned(FTrayIcon.OnPaint) then
      begin
        // qt kernel sets QtWA_PaintOnScreen and QtWA_NoSystemBackground
        // also OnPaint won't fire until we enter widget with mouse.
        // Thats so now until I find out howto find systrayicon private QWidget
        // without searching in QtWidgetSet.EventFilter.
        {$IFDEF HASX11}
        FillChar(PaintData, SizeOf(PaintData), 0);
        with PaintData do
        begin
          PaintWidget := FSysTrayWidget;
          ClipRegion := QPaintEvent_Region(QPaintEventH(Event));
          if ClipRect = nil then
            New(ClipRect);
          QPaintEvent_Rect(QPaintEventH(Event), ClipRect);
        end;
        FCanvas := TCanvas.Create;
        try
          FCanvas.Handle := BeginPaintInternal(PaintData);
          if Assigned(FTrayIcon.OnPaint) then
            FTrayIcon.OnPaint(FTrayIcon);
          EndPaintInternal(PaintData);
        finally
          FreeThenNil(FCanvas);
        end;
        Result := True;
        {$ELSE}
        DebugLn('TQtSystemTrayIcon: Paint event is not supported.');
        {$ENDIF}
      end;
    end;
    QEventToolTip:
    begin
      if Assigned(FTrayIcon) and (FTrayIcon.Hint <> '') then
      begin
        R := GetGeometry;
        QtPoint(R.Left, R.Top);
        AHint := UTF8ToUTF16(FTrayIcon.Hint);
        QToolTip_showText(@P, @AHint);
      end;
    end;
    QEventMouseMove:
    begin
      if Assigned(FTrayIcon) and Assigned(FTrayIcon.OnMouseMove) then
      begin
        X := QMouseEvent_pos(QMouseEventH(Event))^.x;
        Y := QMouseEvent_pos(QMouseEventH(Event))^.Y;
        FTrayIcon.OnMouseMove(FTrayIcon, [], X, Y);
        if Assigned(FTrayIcon.OnPaint) and (FSysTrayWidget <> nil) then
          QWidget_update(FSysTrayWidget);
      end;
    end;
  end;
end;

procedure TQtSystemTrayIcon.setContextMenu(menu: QMenuH);
begin
  QSystemTrayIcon_setContextMenu(QSystemTrayIconH(TheObject), menu);
end;

procedure TQtSystemTrayIcon.setIcon(icon: QIconH);
begin
  QSystemTrayIcon_setIcon(QSystemTrayIconH(TheObject), icon);
end;

procedure TQtSystemTrayIcon.setToolTip(tip: WideString);
begin
  QSystemTrayIcon_setToolTip(QSystemTrayIconH(TheObject), @tip)
end;

procedure TQtSystemTrayIcon.signalActivated(
  AReason: QSystemTrayIconActivationReason); cdecl;
var
  MousePos: TQtPoint;
begin
  if not Assigned(FTrayIcon) then
    exit;
  QCursor_pos(@MousePos);

  if Assigned(FTrayIcon.OnPaint) and (FSysTrayWidget <> nil) then
    QWidget_update(FSysTrayWidget); // trigger paint event.

  case AReason of
    QSystemTrayIconTrigger:
      begin
        if Assigned(FTrayIcon.OnMouseDown) then
          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
        if Assigned(FTrayIcon.OnClick) then
          FTrayIcon.OnClick(FTrayIcon);
        if Assigned(FTrayIcon.OnMouseUp) then
          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
      end;
    QSystemTrayIconDoubleClick:
      begin
        if Assigned(FTrayIcon.OnMouseDown) then
          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);

        if Assigned(FTrayIcon.OnDblClick) then
          FTrayIcon.OnDblClick(FTrayIcon);

        if Assigned(FTrayIcon.OnMouseUp) then
          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
      end;
    QSystemTrayIconMiddleClick:
      begin
        if Assigned(FTrayIcon.OnMouseDown) then
          FTrayIcon.OnMouseDown(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
        if Assigned(FTrayIcon.OnMouseUp) then
          FTrayIcon.OnMouseUp(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
      end;
    QSystemTrayIconContext:
      begin
        if Assigned(FTrayIcon.OnMouseDown) then
          FTrayIcon.OnMouseDown(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);

        if Assigned(FTrayIcon.OnMouseUp) then
          FTrayIcon.OnMouseUp(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
      end;
  end;
end;

procedure TQtSystemTrayIcon.showBaloonHint(const ATitle, AHint: String;
  const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
var
  WHint: WideString;
  WTitle: WideString;
begin
  WHint := GetUTF8String(AHint);
  WTitle := GetUTF8String(ATitle);
  QSystemTrayIcon_showMessage(QSystemTrayIconH(TheObject), @WTitle, @WHint, AFlag, ATimeOut);
end;

function TQtSystemTrayIcon.GetGeometry: TRect;
begin
  Result := Rect(0, 0, 0, 0);
  if Assigned(TheObject) then
    QSystemTrayIcon_geometry(QSystemTrayIconH(TheObject), @Result);
end;

function TQtSystemTrayIcon.GetPosition: TPoint;
var
  R: TRect;
begin
  R := GetGeometry;
  Result := Point(R.Left, R.Top);
end;

procedure TQtSystemTrayIcon.Show;
begin
  QSystemTrayIcon_show(QSystemTrayIconH(TheObject));
end;

procedure TQtSystemTrayIcon.Hide;
begin
  QSystemTrayIcon_hide(QSystemTrayIconH(TheObject));
end;

procedure TQtSystemTrayIcon.UpdateSystemTrayWidget;
begin
  if Assigned(FSysTrayWidget) then
    QWidget_update(FSysTrayWidget);
end;

end.
qtsystemtrayicon.pas (9,392 bytes)

Zeljan Rikalo

2014-04-11 14:23

developer  

qtsystemtrayicon_events.diff (13,881 bytes)
Index: lcl/interfaces/qt/qtobjects.pas
===================================================================
--- lcl/interfaces/qt/qtobjects.pas	(revision 44672)
+++ lcl/interfaces/qt/qtobjects.pas	(working copy)
@@ -520,28 +520,6 @@
     property Handle: QCursorH read FHandle;
   end;
   
-  { TQtSystemTrayIcon }
-
-  TQtSystemTrayIcon = class(TObject)
-  private
-    FHook: QSystemTrayIcon_hookH;
-  public
-    Handle: QSystemTrayIconH;
-    FTrayIcon: TCustomTrayIcon;
-  public
-    constructor Create(vIcon: QIconH); virtual;
-    destructor Destroy; override;
-  public
-    procedure setContextMenu(menu: QMenuH);
-    procedure setIcon(icon: QIconH);
-    procedure setToolTip(tip: WideString);
-    procedure signalActivated(AReason: QSystemTrayIconActivationReason); cdecl;
-    procedure showBaloonHint(const ATitle, AHint: String;
-      const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
-    procedure Show;
-    procedure Hide;
-  end;
-  
   { TQtButtonGroup }
   
   TQtButtonGroup = class(TObject)
@@ -3690,119 +3668,6 @@
   QPixmap_fromImage(retval, image, flags);
 end;
 
-{ TQtSystemTrayIcon }
-
-constructor TQtSystemTrayIcon.Create(vIcon: QIconH);
-begin
-  inherited Create;
-
-  if vIcon <> nil then
-    Handle := QSystemTrayIcon_create(vicon, nil)
-  else
-    Handle := QSystemTrayIcon_create();
-  FHook := QSystemTrayIcon_hook_create(Handle);
-  QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
-end;
-
-destructor TQtSystemTrayIcon.Destroy;
-begin
-  QSystemTrayIcon_hook_destroy(FHook);
-  QSystemTrayIcon_destroy(Handle);
-  
-  inherited Destroy;
-end;
-
-procedure TQtSystemTrayIcon.setContextMenu(menu: QMenuH);
-begin
-  QSystemTrayIcon_setContextMenu(handle, menu);
-end;
-
-procedure TQtSystemTrayIcon.setIcon(icon: QIconH);
-begin
-  QSystemTrayIcon_setIcon(handle, icon);
-end;
-
-procedure TQtSystemTrayIcon.setToolTip(tip: WideString);
-begin
-  QSystemTrayIcon_setToolTip(handle, @tip)
-end;
-
-procedure TQtSystemTrayIcon.signalActivated(
-  AReason: QSystemTrayIconActivationReason); cdecl;
-var
-  MousePos: TQtPoint;
-begin
-  if not Assigned(FTrayIcon) then
-    exit;
-
-  QCursor_pos(@MousePos);
-  {$note: TODO: Mouse events of trayicon can be catched
-   in QApplication event filter (TQtWidgetSet.EventFilter),
-   so OnMouseDown and OnMouseUp can be properly sent.
-   Check if it works ok on qtwin32 and qtmac and
-   then replace this blind calls to mouse events.
-   To get systryicon object handle in application event filter
-   add property "lclsystrayicon" to this handle.}
-  case AReason of
-    QSystemTrayIconTrigger:
-      begin
-        if Assigned(FTrayIcon.OnMouseDown) then
-          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
-        if Assigned(FTrayIcon.OnClick) then
-          FTrayIcon.OnClick(FTrayIcon);
-        if Assigned(FTrayIcon.OnMouseUp) then
-          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
-      end;
-    QSystemTrayIconDoubleClick:
-      begin
-        if Assigned(FTrayIcon.OnMouseDown) then
-          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
-
-        if Assigned(FTrayIcon.OnDblClick) then
-          FTrayIcon.OnDblClick(FTrayIcon);
-
-        if Assigned(FTrayIcon.OnMouseUp) then
-          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
-      end;
-    QSystemTrayIconMiddleClick:
-      begin
-        if Assigned(FTrayIcon.OnMouseDown) then
-          FTrayIcon.OnMouseDown(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
-        if Assigned(FTrayIcon.OnMouseUp) then
-          FTrayIcon.OnMouseUp(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
-      end;
-    QSystemTrayIconContext:
-      begin
-        if Assigned(FTrayIcon.OnMouseDown) then
-          FTrayIcon.OnMouseDown(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
-
-        if Assigned(FTrayIcon.OnMouseUp) then
-          FTrayIcon.OnMouseUp(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
-      end;
-  end;
-end;
-
-procedure TQtSystemTrayIcon.showBaloonHint(const ATitle, AHint: String;
-  const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
-var
-  WHint: WideString;
-  WTitle: WideString;
-begin
-  WHint := GetUTF8String(AHint);
-  WTitle := GetUTF8String(ATitle);
-  QSystemTrayIcon_showMessage(Handle, @WTitle, @WHint, AFlag, ATimeOut);
-end;
-
-procedure TQtSystemTrayIcon.Show;
-begin
-  QSystemTrayIcon_show(handle);
-end;
-
-procedure TQtSystemTrayIcon.Hide;
-begin
-  QSystemTrayIcon_hide(handle);
-end;
-
 { TQtButtonGroup }
 
 constructor TQtButtonGroup.Create(AParent: QObjectH);
Index: lcl/interfaces/qt/qtobject.inc
===================================================================
--- lcl/interfaces/qt/qtobject.inc	(revision 44672)
+++ lcl/interfaces/qt/qtobject.inc	(working copy)
@@ -91,6 +91,7 @@
   System.InitCriticalSection(CriticalSection);
   SavedHandlesList := TMap.Create(TMapIdType(ituPtrSize), SizeOf(TObject));
   FSocketEventMap := TMap.Create(TMapIdType(its4), SizeOf(Pointer));
+  SysTrayIconsList := TFPList.Create;
   StayOnTopList := nil;
   FAppActive := False;
   {$IFDEF HASX11}
@@ -158,6 +159,13 @@
     SavedHintHandlesList := nil;
   end;
   {$ENDIF}
+
+  if SysTrayIconsList <> nil then
+  begin
+    SysTrayIconsList.Free;
+    SysTrayIconsList := nil;
+  end;
+
   FSocketEventMap.Free;
   FGlobalActions.Free;
 
@@ -547,6 +555,7 @@
   ASequence: QKeySequenceH;
   AKey: WideString;
   AParent: QWidgetH;
+  R: TRect;
 
   function IsAnyWindowActive: Boolean;
   begin
@@ -555,10 +564,102 @@
       (QApplication_activePopupWidget() <> nil);
   end;
 
+  function IsSystemTrayWidget(AEventType: Cardinal): boolean;
+  var
+    AName: WideString;
+    AWidget: QWidgetH;
+    RGeom: TRect;
+    AFlags: QtWindowFlags;
+    i: Integer;
+  begin
+    Result := False;
+    if QObject_isWidgetType(Sender) then
+    begin
+      AWidget := QWidgetH(Sender);
+      QObject_objectName(Sender, @AName);
+      if UTF8Copy(AName, 1, 16) = 'qtlclsystrayicon' then
+      begin
+        for i := 0 to SysTrayIconsList.Count - 1 do
+        begin
+          RGeom := TQtSystemTrayIcon(SysTrayIconsList.Items[i]).GetGeometry;
+          if TQtSystemTrayIcon(SysTrayIconsList.Items[i]).SysTrayWidget = nil then
+          begin
+            if QApplication_widgetAt(RGeom.Left, RGeom.Top) = AWidget then
+              TQtSystemTrayIcon(SysTrayIconsList.Items[i]).AttachSysTrayWidget(AWidget);
+          end;
+        end;
+        exit(True);
+      end;
+      if QWidget_isWindow(AWidget) and (QWidget_parentWidget(AWidget) = nil) then
+      begin
+        AFlags := QWidget_windowFlags(AWidget);
+        if QWidget_testAttribute(AWidget, QtWA_AlwaysShowToolTips) and
+          QWidget_testAttribute(AWidget, QtWA_PaintOnScreen) and
+          QWidget_testAttribute(AWidget, QtWA_NoSystemBackground) and
+          not QWidget_testAttribute(AWidget, QtWA_QuitOnClose) and
+          (AFlags and QtFramelessWindowHint = QtFramelessWindowHint) and
+          (AFlags and QtX11BypassWindowManagerHint = QtX11BypassWindowManagerHint) then
+        begin
+          if HwndFromWidgetH(AWidget) = 0 then
+          begin
+            // we must find it by geometry, but it's innacurate since
+            // qt systrayicon widget returns -1,-1 for left & top, so we
+            // use QApplication_widgetAt().
+            // Another problem is that QSystemTrayIcon geometry is updated
+            // too late, much after QEventShow/QEventShowToParent
+            // so no way to catch private QWidget until we enter
+            // it by mouse.
+            for i := 0 to SysTrayIconsList.Count - 1 do
+            begin
+              RGeom := TQtSystemTrayIcon(SysTrayIconsList.Items[i]).GetGeometry;
+              if QApplication_widgetAt(RGeom.Left, RGeom.Top) = AWidget then
+              begin
+                AName := 'qtlclsystrayicon_' + dbgHex(PtrUInt(AWidget));
+                QObject_setObjectName(Sender, @AName);
+                TQtSystemTrayIcon(SysTrayIconsList.Items[i]).AttachSysTrayWidget(AWidget);
+                {$IFDEF DEBUGSYSTRAYICON}
+                DebugLn('Attached systemtrayicon[',dbgs(I),'] with geometry ',dbgs(RGeom),' dbg=',
+                  dbgsName(TQtSystemTrayIcon(SysTrayIconsList.Items[i]).FTrayIcon));
+                {$ENDIF}
+                TQtSystemTrayIcon(SysTrayIconsList.Items[i]).UpdateSystemTrayWidget;
+                Result := True;
+                break;
+              end;
+            end;
+          end;
+        end;
+      end;
+    end;
+  end;
+
 begin
   Result := False;
+
+  // find QSystemTrayIcon
+  if QObject_isWidgetType(Sender) and (QObject_parent(Sender) = nil) and
+    QWidget_isWindow(QWidgetH(Sender)) and
+    (QWidget_focusPolicy(QWidgetH(Sender)) = QtNoFocus) then
+  begin
+    AParent := QWidgetH(Sender);
+    QWidget_frameGeometry(AParent, @R);
+    if (R.Left = -1) and (R.Top = -1) and (R.Right > 0) and (R.Bottom > 0) then
+    begin
+      {$IFDEF DEBUGSYSTRAYICON}
+      DebugLn('EVENT: ',dbgs(QEvent_type(Event)),' Sender 0x',dbgHex(PtrUInt(Sender)),' geometry ',dbgs(R));
+      {$ENDIF}
+      if (QEvent_type(Event) = QEventShowToParent) or (QEvent_type(Event) = QEventEnter) then
+      begin
+        if IsSystemTrayWidget(QEvent_type(Event)) then
+        begin
+          {$IFDEF DEBUGSYSTRAYICON}
+          DebugLn('Found SystemTrayIcon via event ',dbgs(QEvent_type(Event)),' SYSTRAYICON 0x',dbgHex(PtrUInt(Sender)));
+          {$ENDIF}
+        end;
+      end;
+    end;
+  end;
+
   case QEvent_type(Event) of
-
     QEventShortcutOverride: // issue #22827
     begin
       QKeyEvent_text(QKeyEventH(Event), @AKey);
@@ -1142,6 +1243,21 @@
   System.LeaveCriticalsection(CriticalSection);
 end;
 
+procedure TQtWidgetSet.RegisterSysTrayIcon(AHandle: TObject);
+begin
+  SysTrayIconsList.Add(AHandle);
+end;
+
+procedure TQtWidgetSet.UnRegisterSysTrayIcon(AHandle: TObject);
+begin
+  SysTrayIconsList.Remove(AHandle);
+end;
+
+function TQtWidgetSet.IsValidSysTrayIcon(AHandle: HWND): Boolean;
+begin
+  Result := SysTrayIconsList.IndexOf(TObject(AHandle)) >= 0;
+end;
+
 {$IFDEF HASX11}
 procedure TQtWidgetSet.AddHintHandle(AHandle: TObject);
 begin
Index: lcl/interfaces/qt/qtwsextctrls.pp
===================================================================
--- lcl/interfaces/qt/qtwsextctrls.pp	(revision 44672)
+++ lcl/interfaces/qt/qtwsextctrls.pp	(working copy)
@@ -25,7 +25,7 @@
 uses
   // Bindings
   qt4,
-  qtwidgets, qtobjects, qtproc, QtWSControls,
+  qtwidgets, qtobjects, qtsystemtrayicon, qtproc, QtWSControls,
   // LCL
   LCLProc,
   SysUtils, Classes, Controls, Graphics, Forms, ExtCtrls, LCLType,
@@ -152,6 +152,7 @@
     class procedure InternalUpdate(const ATrayIcon: TCustomTrayIcon); override;
     class function ShowBalloonHint(const ATrayIcon: TCustomTrayIcon): Boolean; override;
     class function GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint; override;
+    class function GetCanvas(const ATrayIcon: TCustomTrayIcon): TCanvas; override;
   end;
 
 implementation
@@ -334,6 +335,9 @@
   if Assigned(ATrayIcon.PopUpMenu) then
     if TQtMenu(ATrayIcon.PopUpMenu.Handle).Widget <> nil then
       SystemTrayIcon.setContextMenu(QMenuH(TQtMenu(ATrayIcon.PopUpMenu.Handle).Widget));
+
+  SystemTrayIcon.UpdateSystemTrayWidget;
+
 end;
 
 class function TQtWSCustomTrayIcon.ShowBalloonHint(
@@ -355,6 +359,17 @@
 class function TQtWSCustomTrayIcon.GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint;
 begin
   Result := Point(0, 0);
+  if (ATrayIcon.Handle = 0) then
+    exit;
+  Result := TQtSystemTrayIcon(ATrayIcon.Handle).GetPosition;
 end;
 
+class function TQtWSCustomTrayIcon.GetCanvas(const ATrayIcon: TCustomTrayIcon
+  ): TCanvas;
+begin
+  Result := nil;
+  if (ATrayIcon.Handle <> 0) then
+    Result := TQtSystemTrayIcon(ATrayIcon.Handle).Canvas;
+end;
+
 end.
Index: lcl/interfaces/qt/qtint.pp
===================================================================
--- lcl/interfaces/qt/qtint.pp	(revision 44672)
+++ lcl/interfaces/qt/qtint.pp	(working copy)
@@ -65,6 +65,7 @@
     SavedHandlesList: TMap;
     FSocketEventMap: TMap;
     StayOnTopList: TMap;
+    SysTrayIconsList: TFPList;
     // global hooks
     FAppEvenFilterHook: QObject_hookH;
     FAppFocusChangedHook: QApplication_hookH;
@@ -157,6 +158,11 @@
     procedure RemoveHandle(AHandle: TObject);
     function IsValidHandle(AHandle: HWND): Boolean;
 
+    // qt systray icons map
+    procedure RegisterSysTrayIcon(AHandle: TObject);
+    procedure UnRegisterSysTrayIcon(AHandle: TObject);
+    function IsValidSysTrayIcon(AHandle: HWND): Boolean;
+
     {$IFDEF HASX11}
     // qt hints handles map (needed on X11 only)
     procedure AddHintHandle(AHandle: TObject);
@@ -307,7 +313,7 @@
 ////////////////////////////////////////////////////
   Graphics, buttons, Menus,
   // Bindings
-  qtprivate, qtwidgets, qtobjects;
+  qtprivate, qtwidgets, qtobjects, qtsystemtrayicon;
 
 function DTFlagsToQtFlags(const Flags: Cardinal): Integer;
 begin
Index: lcl/interfaces/lcl.lpk
===================================================================
--- lcl/interfaces/lcl.lpk	(revision 44672)
+++ lcl/interfaces/lcl.lpk	(working copy)
@@ -129,7 +129,7 @@
     <License Value="modified LGPL-2
 "/>
     <Version Major="1" Minor="3"/>
-    <Files Count="429">
+    <Files Count="430">
       <Item1>
         <Filename Value="carbon/agl.pp"/>
         <AddToUsesPkgSection Value="False"/>
@@ -2135,6 +2135,11 @@
         <AddToUsesPkgSection Value="False"/>
         <UnitName Value="LazPangoCairo1"/>
       </Item429>
+      <Item430>
+        <Filename Value="qt/qtsystemtrayicon.pas"/>
+        <AddToUsesPkgSection Value="False"/>
+        <UnitName Value="qtsystemtrayicon"/>
+      </Item430>
     </Files>
     <LazDoc Paths="../../docs/xml/lcl"/>
     <i18n>

Zeljan Rikalo

2014-04-11 14:26

developer   ~0074306

I've attached possible patch + qtsystemtray.pas unit which should be added with patch to lcl/interfaces/qt since TQtSystemTrayIcon is moved from qtobjects.pas to that unit. Everything is fine except that under X11 qt does not provide correct geometry to QSystemTrayIcon when private QWidget is shown so we cannot catch anything without hw interaction (mouse enter into private QWidget of QSystemTrayIcon). Besides that OnMouseMove, and OnPaint works when private QWidget is catched in main TQtWidgetSet.EventFilter().

AlexL

2014-05-11 11:05

reporter   ~0074900

Zeljan, hello,
Did you look gtk2 part of patch? It will be good to fix this bug before new lazarus's version.

AlexL

2014-09-02 16:42

reporter  

lazarus-1.2.4-mga-qtsystemtrayicon-events.patch (14,042 bytes)
diff -ur lazarus.orig/lcl/interfaces/lcl.lpk lazarus/lcl/interfaces/lcl.lpk
--- lazarus.orig/lcl/interfaces/lcl.lpk	2014-06-14 09:36:52.000000000 +0400
+++ lazarus/lcl/interfaces/lcl.lpk	2014-09-02 17:58:51.000000000 +0400
@@ -129,7 +129,7 @@
     <License Value="modified LGPL-2
 "/>
     <Version Major="1" Minor="2" Release="4"/>
-    <Files Count="429">
+    <Files Count="430">
       <Item1>
         <Filename Value="carbon/agl.pp"/>
         <AddToUsesPkgSection Value="False"/>
@@ -2134,6 +2134,11 @@
         <AddToUsesPkgSection Value="False"/>
         <UnitName Value="LazPangoCairo1"/>
       </Item429>
+      <Item430>
+        <Filename Value="qt/qtsystemtrayicon.pas"/>
+        <AddToUsesPkgSection Value="False"/>
+        <UnitName Value="qtsystemtrayicon"/>
+      </Item430>
     </Files>
     <LazDoc Paths="../../docs/xml/lcl"/>
     <i18n>
diff -ur lazarus.orig/lcl/interfaces/qt/qtint.pp lazarus/lcl/interfaces/qt/qtint.pp
--- lazarus.orig/lcl/interfaces/qt/qtint.pp	2014-05-09 18:33:04.000000000 +0400
+++ lazarus/lcl/interfaces/qt/qtint.pp	2014-09-02 17:57:54.000000000 +0400
@@ -65,6 +65,7 @@
     SavedHandlesList: TMap;
     FSocketEventMap: TMap;
     StayOnTopList: TMap;
+    SysTrayIconsList: TFPList;
     // global hooks
     FAppEvenFilterHook: QObject_hookH;
     FAppFocusChangedHook: QApplication_hookH;
@@ -156,6 +157,11 @@
     procedure AddHandle(AHandle: TObject);
     procedure RemoveHandle(AHandle: TObject);
     function IsValidHandle(AHandle: HWND): Boolean;
+    
+    // qt systray icons map
+    procedure RegisterSysTrayIcon(AHandle: TObject);
+    procedure UnRegisterSysTrayIcon(AHandle: TObject);
+    function IsValidSysTrayIcon(AHandle: HWND): Boolean;
 
     {$IFDEF HASX11}
     // qt hints handles map (needed on X11 only)
@@ -311,7 +317,7 @@
 ////////////////////////////////////////////////////
   Graphics, buttons, Menus,
   // Bindings
-  qtprivate, qtwidgets, qtobjects;
+  qtprivate, qtwidgets, qtobjects, qtsystemtrayicon;
 
 function DTFlagsToQtFlags(const Flags: Cardinal): Integer;
 begin
diff -ur lazarus.orig/lcl/interfaces/qt/qtobject.inc lazarus/lcl/interfaces/qt/qtobject.inc
--- lazarus.orig/lcl/interfaces/qt/qtobject.inc	2014-05-07 19:56:22.000000000 +0400
+++ lazarus/lcl/interfaces/qt/qtobject.inc	2014-09-02 17:54:19.000000000 +0400
@@ -91,6 +91,7 @@
   System.InitCriticalSection(CriticalSection);
   SavedHandlesList := TMap.Create(TMapIdType(ituPtrSize), SizeOf(TObject));
   FSocketEventMap := TMap.Create(TMapIdType(its4), SizeOf(Pointer));
+  SysTrayIconsList := TFPList.Create;
   StayOnTopList := nil;
   FAppActive := False;
   {$IFDEF HASX11}
@@ -158,6 +159,13 @@
     SavedHintHandlesList := nil;
   end;
   {$ENDIF}
+
+  if SysTrayIconsList <> nil then
+  begin
+    SysTrayIconsList.Free;
+    SysTrayIconsList := nil;
+  end;
+
   FSocketEventMap.Free;
   FGlobalActions.Free;
 
@@ -547,6 +555,7 @@
   ASequence: QKeySequenceH;
   AKey: WideString;
   AParent: QWidgetH;
+  R: TRect;
 
   function IsAnyWindowActive: Boolean;
   begin
@@ -555,8 +564,101 @@
       (QApplication_activePopupWidget() <> nil);
   end;
 
+  function IsSystemTrayWidget(AEventType: Cardinal): boolean;
+  var
+    AName: WideString;
+    AWidget: QWidgetH;
+    RGeom: TRect;
+    AFlags: QtWindowFlags;
+    i: Integer;
+  begin
+    Result := False;
+    if QObject_isWidgetType(Sender) then
+    begin
+      AWidget := QWidgetH(Sender);
+      QObject_objectName(Sender, @AName);
+      if UTF8Copy(AName, 1, 16) = 'qtlclsystrayicon' then
+      begin
+        for i := 0 to SysTrayIconsList.Count - 1 do
+        begin
+          RGeom := TQtSystemTrayIcon(SysTrayIconsList.Items[i]).GetGeometry;
+          if TQtSystemTrayIcon(SysTrayIconsList.Items[i]).SysTrayWidget = nil then
+          begin
+            if QApplication_widgetAt(RGeom.Left, RGeom.Top) = AWidget then
+              TQtSystemTrayIcon(SysTrayIconsList.Items[i]).AttachSysTrayWidget(AWidget);
+          end;
+        end;
+        exit(True);
+      end;
+      if QWidget_isWindow(AWidget) and (QWidget_parentWidget(AWidget) = nil) then
+      begin
+        AFlags := QWidget_windowFlags(AWidget);
+        if QWidget_testAttribute(AWidget, QtWA_AlwaysShowToolTips) and
+          QWidget_testAttribute(AWidget, QtWA_PaintOnScreen) and
+          QWidget_testAttribute(AWidget, QtWA_NoSystemBackground) and
+          not QWidget_testAttribute(AWidget, QtWA_QuitOnClose) and
+          (AFlags and QtFramelessWindowHint = QtFramelessWindowHint) and
+          (AFlags and QtX11BypassWindowManagerHint = QtX11BypassWindowManagerHint) then
+        begin
+          if HwndFromWidgetH(AWidget) = 0 then
+          begin
+            // we must find it by geometry, but it's innacurate since
+            // qt systrayicon widget returns -1,-1 for left & top, so we
+            // use QApplication_widgetAt().
+            // Another problem is that QSystemTrayIcon geometry is updated
+            // too late, much after QEventShow/QEventShowToParent
+            // so no way to catch private QWidget until we enter
+            // it by mouse.
+            for i := 0 to SysTrayIconsList.Count - 1 do
+            begin
+              RGeom := TQtSystemTrayIcon(SysTrayIconsList.Items[i]).GetGeometry;
+              if QApplication_widgetAt(RGeom.Left, RGeom.Top) = AWidget then
+              begin
+                AName := 'qtlclsystrayicon_' + dbgHex(PtrUInt(AWidget));
+                QObject_setObjectName(Sender, @AName);
+                TQtSystemTrayIcon(SysTrayIconsList.Items[i]).AttachSysTrayWidget(AWidget);
+                {$IFDEF DEBUGSYSTRAYICON}
+                DebugLn('Attached systemtrayicon[',dbgs(I),'] with geometry ',dbgs(RGeom),' dbg=',
+                  dbgsName(TQtSystemTrayIcon(SysTrayIconsList.Items[i]).FTrayIcon));
+                {$ENDIF}
+                TQtSystemTrayIcon(SysTrayIconsList.Items[i]).UpdateSystemTrayWidget;
+                Result := True;
+                break;
+              end;
+            end;
+          end;
+        end;
+      end;
+    end;
+  end;
+
 begin
   Result := False;
+
+  // find QSystemTrayIcon
+  if QObject_isWidgetType(Sender) and (QObject_parent(Sender) = nil) and
+    QWidget_isWindow(QWidgetH(Sender)) and
+    (QWidget_focusPolicy(QWidgetH(Sender)) = QtNoFocus) then
+  begin
+    AParent := QWidgetH(Sender);
+    QWidget_frameGeometry(AParent, @R);
+    if (R.Left = -1) and (R.Top = -1) and (R.Right > 0) and (R.Bottom > 0) then
+    begin
+      {$IFDEF DEBUGSYSTRAYICON}
+      DebugLn('EVENT: ',dbgs(QEvent_type(Event)),' Sender 0x',dbgHex(PtrUInt(Sender)),' geometry ',dbgs(R));
+      {$ENDIF}
+      if (QEvent_type(Event) = QEventShowToParent) or (QEvent_type(Event) = QEventEnter) then
+      begin
+        if IsSystemTrayWidget(QEvent_type(Event)) then
+        begin
+          {$IFDEF DEBUGSYSTRAYICON}
+          DebugLn('Found SystemTrayIcon via event ',dbgs(QEvent_type(Event)),' SYSTRAYICON 0x',dbgHex(PtrUInt(Sender)));
+          {$ENDIF}
+        end;
+      end;
+    end;
+  end;
+
   case QEvent_type(Event) of
     QEventShortcutOverride: // issue #22827
     begin
@@ -1140,6 +1242,21 @@
   System.LeaveCriticalsection(CriticalSection);
 end;
 
+procedure TQtWidgetSet.RegisterSysTrayIcon(AHandle: TObject);
+begin
+  SysTrayIconsList.Add(AHandle);
+end;
+
+procedure TQtWidgetSet.UnRegisterSysTrayIcon(AHandle: TObject);
+begin
+  SysTrayIconsList.Remove(AHandle);
+end;
+
+function TQtWidgetSet.IsValidSysTrayIcon(AHandle: HWND): Boolean;
+begin
+  Result := SysTrayIconsList.IndexOf(TObject(AHandle)) >= 0;
+end;
+
 procedure TQtWidgetSet.RemoveHandle(AHandle: TObject);
 begin
   System.EnterCriticalsection(CriticalSection);
diff -ur lazarus.orig/lcl/interfaces/qt/qtobjects.pas lazarus/lcl/interfaces/qt/qtobjects.pas
--- lazarus.orig/lcl/interfaces/qt/qtobjects.pas	2014-05-13 01:17:16.000000000 +0400
+++ lazarus/lcl/interfaces/qt/qtobjects.pas	2014-09-02 17:50:35.000000000 +0400
@@ -520,28 +520,6 @@
     property Handle: QCursorH read FHandle;
   end;
   
-  { TQtSystemTrayIcon }
-
-  TQtSystemTrayIcon = class(TObject)
-  private
-    FHook: QSystemTrayIcon_hookH;
-  public
-    Handle: QSystemTrayIconH;
-    FTrayIcon: TCustomTrayIcon;
-  public
-    constructor Create(vIcon: QIconH); virtual;
-    destructor Destroy; override;
-  public
-    procedure setContextMenu(menu: QMenuH);
-    procedure setIcon(icon: QIconH);
-    procedure setToolTip(tip: WideString);
-    procedure signalActivated(AReason: QSystemTrayIconActivationReason); cdecl;
-    procedure showBaloonHint(const ATitle, AHint: String;
-      const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
-    procedure Show;
-    procedure Hide;
-  end;
-  
   { TQtButtonGroup }
   
   TQtButtonGroup = class(TObject)
@@ -3690,119 +3668,6 @@
   QPixmap_fromImage(retval, image, flags);
 end;
 
-{ TQtSystemTrayIcon }
-
-constructor TQtSystemTrayIcon.Create(vIcon: QIconH);
-begin
-  inherited Create;
-
-  if vIcon <> nil then
-    Handle := QSystemTrayIcon_create(vicon, nil)
-  else
-    Handle := QSystemTrayIcon_create();
-  FHook := QSystemTrayIcon_hook_create(Handle);
-  QSystemTrayIcon_hook_hook_activated(FHook, @signalActivated);
-end;
-
-destructor TQtSystemTrayIcon.Destroy;
-begin
-  QSystemTrayIcon_hook_destroy(FHook);
-  QSystemTrayIcon_destroy(Handle);
-  
-  inherited Destroy;
-end;
-
-procedure TQtSystemTrayIcon.setContextMenu(menu: QMenuH);
-begin
-  QSystemTrayIcon_setContextMenu(handle, menu);
-end;
-
-procedure TQtSystemTrayIcon.setIcon(icon: QIconH);
-begin
-  QSystemTrayIcon_setIcon(handle, icon);
-end;
-
-procedure TQtSystemTrayIcon.setToolTip(tip: WideString);
-begin
-  QSystemTrayIcon_setToolTip(handle, @tip)
-end;
-
-procedure TQtSystemTrayIcon.signalActivated(
-  AReason: QSystemTrayIconActivationReason); cdecl;
-var
-  MousePos: TQtPoint;
-begin
-  if not Assigned(FTrayIcon) then
-    exit;
-
-  QCursor_pos(@MousePos);
-  {$note: TODO: Mouse events of trayicon can be catched
-   in QApplication event filter (TQtWidgetSet.EventFilter),
-   so OnMouseDown and OnMouseUp can be properly sent.
-   Check if it works ok on qtwin32 and qtmac and
-   then replace this blind calls to mouse events.
-   To get systryicon object handle in application event filter
-   add property "lclsystrayicon" to this handle.}
-  case AReason of
-    QSystemTrayIconTrigger:
-      begin
-        if Assigned(FTrayIcon.OnMouseDown) then
-          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
-        if Assigned(FTrayIcon.OnClick) then
-          FTrayIcon.OnClick(FTrayIcon);
-        if Assigned(FTrayIcon.OnMouseUp) then
-          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
-      end;
-    QSystemTrayIconDoubleClick:
-      begin
-        if Assigned(FTrayIcon.OnMouseDown) then
-          FTrayIcon.OnMouseDown(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
-
-        if Assigned(FTrayIcon.OnDblClick) then
-          FTrayIcon.OnDblClick(FTrayIcon);
-
-        if Assigned(FTrayIcon.OnMouseUp) then
-          FTrayIcon.OnMouseUp(FTrayIcon, mbLeft, [], MousePos.x, MousePos.y);
-      end;
-    QSystemTrayIconMiddleClick:
-      begin
-        if Assigned(FTrayIcon.OnMouseDown) then
-          FTrayIcon.OnMouseDown(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
-        if Assigned(FTrayIcon.OnMouseUp) then
-          FTrayIcon.OnMouseUp(FTrayIcon, mbMiddle, [], MousePos.x, MousePos.y);
-      end;
-    QSystemTrayIconContext:
-      begin
-        if Assigned(FTrayIcon.OnMouseDown) then
-          FTrayIcon.OnMouseDown(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
-
-        if Assigned(FTrayIcon.OnMouseUp) then
-          FTrayIcon.OnMouseUp(FTrayIcon, mbRight, [], MousePos.x, MousePos.y);
-      end;
-  end;
-end;
-
-procedure TQtSystemTrayIcon.showBaloonHint(const ATitle, AHint: String;
-  const AFlag: QSystemTrayIconMessageIcon; const ATimeOut: Integer);
-var
-  WHint: WideString;
-  WTitle: WideString;
-begin
-  WHint := GetUTF8String(AHint);
-  WTitle := GetUTF8String(ATitle);
-  QSystemTrayIcon_showMessage(Handle, @WTitle, @WHint, AFlag, ATimeOut);
-end;
-
-procedure TQtSystemTrayIcon.Show;
-begin
-  QSystemTrayIcon_show(handle);
-end;
-
-procedure TQtSystemTrayIcon.Hide;
-begin
-  QSystemTrayIcon_hide(handle);
-end;
-
 { TQtButtonGroup }
 
 constructor TQtButtonGroup.Create(AParent: QObjectH);
diff -ur lazarus.orig/lcl/interfaces/qt/qtwsextctrls.pp lazarus/lcl/interfaces/qt/qtwsextctrls.pp
--- lazarus.orig/lcl/interfaces/qt/qtwsextctrls.pp	2013-09-06 10:16:53.000000000 +0400
+++ lazarus/lcl/interfaces/qt/qtwsextctrls.pp	2014-09-02 17:56:37.000000000 +0400
@@ -25,7 +25,7 @@
 uses
   // Bindings
   qt4,
-  qtwidgets, qtobjects, qtproc, QtWSControls,
+  qtwidgets, qtobjects, qtsystemtrayicon, qtproc, QtWSControls,
   // LCL
   LCLProc,
   SysUtils, Classes, Controls, Graphics, Forms, ExtCtrls, LCLType,
@@ -152,6 +152,7 @@
     class procedure InternalUpdate(const ATrayIcon: TCustomTrayIcon); override;
     class function ShowBalloonHint(const ATrayIcon: TCustomTrayIcon): Boolean; override;
     class function GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint; override;
+    class function GetCanvas(const ATrayIcon: TCustomTrayIcon): TCanvas; override;
   end;
 
 implementation
@@ -288,6 +289,8 @@
     if TQtMenu(ATrayIcon.PopUpMenu.Handle).Widget <> nil then
       SystemTrayIcon.setContextMenu(QMenuH(TQtMenu(ATrayIcon.PopUpMenu.Handle).Widget));
 
+  SystemTrayIcon.UpdateSystemTrayWidget;
+
   SystemTrayIcon.show;
 
   Result := True;
@@ -355,6 +358,17 @@
 class function TQtWSCustomTrayIcon.GetPosition(const ATrayIcon: TCustomTrayIcon): TPoint;
 begin
   Result := Point(0, 0);
+  if (ATrayIcon.Handle = 0) then
+    exit;
+  Result := TQtSystemTrayIcon(ATrayIcon.Handle).GetPosition;
+end;
+
+class function TQtWSCustomTrayIcon.GetCanvas(const ATrayIcon: TCustomTrayIcon
+  ): TCanvas;
+begin
+  Result := nil;
+  if (ATrayIcon.Handle <> 0) then
+    Result := TQtSystemTrayIcon(ATrayIcon.Handle).Canvas;
 end;
 
 end.

Zeljan Rikalo

2014-09-14 13:59

developer   ~0077212

hm...I've succesfully implemented mousemove and paint under qt-x11, but it looks impossible to implement it under qt-win32 since qt implementation does not provide any event to widget's event filter since it uses winapi directly.

Zeljan Rikalo

2014-09-14 14:43

developer   ~0077213

Gtk2 part is commited in r46221

Zeljan Rikalo

2014-09-14 14:56

developer   ~0077214

Please test and close if ok.
IMPORTANT NOTE: This is fix only for x11 targets. Under qt-win32 it's impossible to implement OnMouseMove and OnPaint without big hack, since qtlib implementation uses pure winapi and does not provide events to underlaying qwidget.

Zeljan Rikalo

2014-09-14 15:02

developer   ~0077215

Forgot to add revisions.

Zeljan Rikalo

2014-09-14 15:04

developer   ~0077216

Please test and close if ok.
IMPORTANT NOTE: This is fix only for x11 targets. Under qt-win32 it's impossible to implement OnMouseMove and OnPaint without big hack, since qtlib implementation uses pure winapi and does not provide events to underlaying qwidget.

Issue History

Date Modified Username Field Change
2012-10-26 19:03 zmey New Issue
2012-10-26 20:36 Zeljan Rikalo LazTarget => -
2012-10-26 20:36 Zeljan Rikalo Note Added: 0063479
2012-10-26 20:36 Zeljan Rikalo Status new => feedback
2012-10-26 20:51 zmey Note Added: 0063481
2012-10-26 22:03 Stas Note Added: 0063484
2012-10-27 06:10 zmey Note Added: 0063490
2013-05-14 17:06 zmey Note Added: 0067697
2013-05-14 17:06 zmey Status feedback => new
2013-10-27 09:17 word Note Added: 0070989
2013-10-27 13:26 Zeljan Rikalo Note Added: 0070993
2013-11-12 19:33 word Note Added: 0071285
2014-04-09 16:11 AlexL File Added: lazarus_trayicon_onmousemove_mga.patch
2014-04-09 16:12 AlexL Note Added: 0074232
2014-04-09 18:09 Zeljan Rikalo Assigned To => Zeljan Rikalo
2014-04-09 18:09 Zeljan Rikalo Status new => assigned
2014-04-10 17:03 Zeljan Rikalo Note Added: 0074273
2014-04-10 17:41 Zeljan Rikalo Note Added: 0074276
2014-04-10 22:18 Zeljan Rikalo Note Added: 0074285
2014-04-11 07:43 AlexL Note Added: 0074291
2014-04-11 08:35 Zeljan Rikalo Note Added: 0074292
2014-04-11 08:59 AlexL Note Added: 0074295
2014-04-11 09:12 Zeljan Rikalo Note Added: 0074296
2014-04-11 14:23 Zeljan Rikalo File Added: qtsystemtrayicon.pas
2014-04-11 14:23 Zeljan Rikalo File Added: qtsystemtrayicon_events.diff
2014-04-11 14:26 Zeljan Rikalo Note Added: 0074306
2014-05-11 11:05 AlexL Note Added: 0074900
2014-09-02 16:42 AlexL File Added: lazarus-1.2.4-mga-qtsystemtrayicon-events.patch
2014-09-14 13:59 Zeljan Rikalo Note Added: 0077212
2014-09-14 14:43 Zeljan Rikalo Note Added: 0077213
2014-09-14 14:43 Zeljan Rikalo Status assigned => feedback
2014-09-14 14:56 Zeljan Rikalo LazTarget - => 1.2.6
2014-09-14 14:56 Zeljan Rikalo Note Added: 0077214
2014-09-14 14:56 Zeljan Rikalo Status feedback => resolved
2014-09-14 14:56 Zeljan Rikalo Fixed in Version => 1.3 (SVN)
2014-09-14 14:56 Zeljan Rikalo Resolution open => fixed
2014-09-14 14:56 Zeljan Rikalo Target Version => 1.2.6
2014-09-14 15:02 Zeljan Rikalo Note Added: 0077215
2014-09-14 15:02 Zeljan Rikalo Status resolved => feedback
2014-09-14 15:04 Zeljan Rikalo Fixed in Revision => 46221,46222,46223
2014-09-14 15:04 Zeljan Rikalo Widgetset => GTK 2, QT
2014-09-14 15:04 Zeljan Rikalo Note Added: 0077216
2014-09-14 15:04 Zeljan Rikalo Status feedback => resolved