|
@@ -21,7 +21,7 @@ uses
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
// fresnel
|
|
// fresnel
|
|
Fresnel.Classes, Fresnel.Forms, Fresnel.WidgetSet, Fresnel.DOM,
|
|
Fresnel.Classes, Fresnel.Forms, Fresnel.WidgetSet, Fresnel.DOM,
|
|
- Fresnel.Events, FCL.Events, Fresnel.Keys;
|
|
|
|
|
|
+ Fresnel.Events, FCL.Events, Fresnel.Keys, Fresnel.ClipBoard;
|
|
|
|
|
|
const
|
|
const
|
|
GTK3_LEFT_BUTTON = 1;
|
|
GTK3_LEFT_BUTTON = 1;
|
|
@@ -105,6 +105,43 @@ type
|
|
property FontEngineGtk3: TGtk3FontEngine read FFontEngine;
|
|
property FontEngineGtk3: TGtk3FontEngine read FFontEngine;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+ { TGtkClipboard }
|
|
|
|
+
|
|
|
|
+ TGtkClipboard = class(TFresnelClipBoard)
|
|
|
|
+ private
|
|
|
|
+ Type
|
|
|
|
+
|
|
|
|
+ { TFormatEnumerator }
|
|
|
|
+
|
|
|
|
+ TFormatEnumerator = class
|
|
|
|
+ Clipboard : PGtkClipboard;
|
|
|
|
+ Formats : Array of string; // atom names
|
|
|
|
+ constructor create (aClipboard : PGtkClipboard);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ { TClipboardData }
|
|
|
|
+
|
|
|
|
+ TClipboardData = class
|
|
|
|
+ Clipboard : PGtkClipboard;
|
|
|
|
+ Data : TBytes;
|
|
|
|
+ Target : String;
|
|
|
|
+ constructor create (aClipboard : PGtkClipboard;aData : TBytes; aTargetName : string);
|
|
|
|
+ end;
|
|
|
|
+ Private
|
|
|
|
+ FClipboard : PGtkClipboard;//
|
|
|
|
+
|
|
|
|
+ protected
|
|
|
|
+ function MimeTypeToAtomName(const aMimeType : string) : string;
|
|
|
|
+ function AtomNameToMimeType(const aAtom : string) : string;
|
|
|
|
+ function DoGetClipboardAsType(const aMimeType: String; out aContents: TBytes): string; override;
|
|
|
|
+ function DoGetContentTypes: TStringDynArray; override;
|
|
|
|
+ function DoHasClipboardType(const aMimeType: String): boolean; override;
|
|
|
|
+ procedure DoSetClipboardAsType(const aMimeType: String; aContents: TBytes); override;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(AOwner: TComponent); override;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
var
|
|
var
|
|
Gtk3WidgetSet: TGtk3WidgetSet;
|
|
Gtk3WidgetSet: TGtk3WidgetSet;
|
|
|
|
|
|
@@ -480,6 +517,7 @@ end;
|
|
|
|
|
|
{ TGtk3WSForm }
|
|
{ TGtk3WSForm }
|
|
|
|
|
|
|
|
+
|
|
procedure TGtk3WSForm.SetFormBounds(const AValue: TFresnelRect);
|
|
procedure TGtk3WSForm.SetFormBounds(const AValue: TFresnelRect);
|
|
var
|
|
var
|
|
aRect: TGdkRectangle;
|
|
aRect: TGdkRectangle;
|
|
@@ -923,7 +961,6 @@ var
|
|
AId: String;
|
|
AId: String;
|
|
begin
|
|
begin
|
|
inherited Create(AOwner);
|
|
inherited Create(AOwner);
|
|
-
|
|
|
|
Gtk3WidgetSet:=Self;
|
|
Gtk3WidgetSet:=Self;
|
|
SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);
|
|
SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);
|
|
FWSFormClass:=TGtk3WSForm;
|
|
FWSFormClass:=TGtk3WSForm;
|
|
@@ -947,6 +984,7 @@ begin
|
|
|
|
|
|
FFontEngine:=TGtk3FontEngine.Create(nil);
|
|
FFontEngine:=TGtk3FontEngine.Create(nil);
|
|
TFresnelFontEngine.WSEngine:=FFontEngine;
|
|
TFresnelFontEngine.WSEngine:=FFontEngine;
|
|
|
|
+ TFresnelClipboard._ClipboardClass:=TGtkClipboard;
|
|
end;
|
|
end;
|
|
|
|
|
|
destructor TGtk3WidgetSet.Destroy;
|
|
destructor TGtk3WidgetSet.Destroy;
|
|
@@ -1017,8 +1055,196 @@ begin
|
|
aWSForm.CreateGtkWindow;
|
|
aWSForm.CreateGtkWindow;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+{ TGtkClipboard }
|
|
|
|
+
|
|
|
|
+function TGtkClipboard.MimeTypeToAtomName(const aMimeType: string): string;
|
|
|
|
+var
|
|
|
|
+ lMime : String;
|
|
|
|
+begin
|
|
|
|
+ lMime:=lowercase(trim(aMimeType));
|
|
|
|
+ if pos('/',lMime)=0 then
|
|
|
|
+ lMime:=lMime+'/';
|
|
|
|
+ // todo: transform
|
|
|
|
+ if (pos('text/',lMime)=1) then
|
|
|
|
+ result:='STRING'
|
|
|
|
+ else
|
|
|
|
+ Result:=aMimeType;
|
|
|
|
+
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGtkClipboard.AtomNameToMimeType(const aAtom: string): string;
|
|
|
|
+begin
|
|
|
|
+ // todo: transform
|
|
|
|
+ if aAtom='STRING' then
|
|
|
|
+ result:='text/text';
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGtkClipboard.DoGetClipboardAsType(const aMimeType: String; out aContents: TBytes): string;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lAtom:PGdkAtom;
|
|
|
|
+ lName : String;
|
|
|
|
+ lData : PGtkSelectionData;
|
|
|
|
+ lDataLen : Integer;
|
|
|
|
+ lDataName : PAnsiChar;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ aContents:=[];
|
|
|
|
+ lName:=MimeTypeToAtomName(aMimeType);
|
|
|
|
+ lAtom:=TGdkAtom.intern(PAnsiChar(lName), False);
|
|
|
|
+ lData:=gtk_clipboard_wait_for_contents(fClipboard,lAtom);
|
|
|
|
+ if assigned(lData) then
|
|
|
|
+ begin
|
|
|
|
+ lDataLen:=gtk_selection_data_get_length(lData);
|
|
|
|
+ lAtom:=gtk_selection_data_get_data_type(lData);
|
|
|
|
+ lDataName:=gdk_atom_name(lAtom^);
|
|
|
|
+ if lDataName<>Nil then
|
|
|
|
+ begin
|
|
|
|
+ lName:=lDataName;
|
|
|
|
+ Result:=AtomNameToMimeType(lName);
|
|
|
|
+ g_free(lDataName);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ Result:=aMimeType;
|
|
|
|
+ SetLength(aContents,lDataLen);
|
|
|
|
+ if lDataLen>0 then
|
|
|
|
+ move(gtk_selection_data_get_data(lData)^,aContents[0],lDataLen);
|
|
|
|
+ Result:=aMimeType;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure targets_received(clipboard : PGtkClipboard; atoms : PGdkAtom; n_atoms : cInt; user_data: gpointer ); cdecl;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ I,Count : integer;
|
|
|
|
+ lName : PAnsiChar;
|
|
|
|
+ lPasName : RawByteString;
|
|
|
|
+ lEnum : TGtkClipBoard.TFormatEnumerator absolute user_data;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if lEnum.Clipboard<>clipboard then // Safety
|
|
|
|
+ exit;
|
|
|
|
+ SetLength(lEnum.Formats,n_atoms);
|
|
|
|
+ Count:=0;
|
|
|
|
+ for i:=0 to n_atoms-1 do
|
|
|
|
+ begin
|
|
|
|
+ lName:=gdk_atom_name(atoms[i]);
|
|
|
|
+ if assigned(lName) then
|
|
|
|
+ begin
|
|
|
|
+ lPasName:=lName;
|
|
|
|
+ lEnum.Formats[Count]:=lPasName;
|
|
|
|
+ g_free(lName);
|
|
|
|
+ inc(Count);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ SetLength(lEnum.Formats,Count);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGtkClipboard.DoGetContentTypes: TStringDynArray;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ Enum : TFormatEnumerator;
|
|
|
|
+ i,len : Integer;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ Result:=[];
|
|
|
|
+ Enum:=TFormatEnumerator.Create(FClipboard);
|
|
|
|
+ try
|
|
|
|
+ gtk_clipboard_request_targets(fclipboard, @targets_received, enum);
|
|
|
|
+ Len:=Length(enum.Formats);
|
|
|
|
+ SetLength(Result,Len);
|
|
|
|
+ For I:=0 to Len-1 do
|
|
|
|
+ Result[I]:=AtomNameToMimeType(enum.Formats[i]);
|
|
|
|
+ finally
|
|
|
|
+ enum.free;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TGtkClipboard.DoHasClipboardType(const aMimeType: String): boolean;
|
|
|
|
+var
|
|
|
|
+ lTypes : TStringDynArray;
|
|
|
|
+ i : integer;
|
|
|
|
+begin
|
|
|
|
+ LTypes:=DoGetContentTypes;
|
|
|
|
+ Result:=False;
|
|
|
|
+ I:=Length(lTypes)-1;
|
|
|
|
+ While (I>=0) and Not Result do
|
|
|
|
+ begin
|
|
|
|
+ Result:=SameText(LTypes[i],aMimeType);
|
|
|
|
+ Dec(I);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure GetClipboardData(clipboard: PGtkClipboard; selection_data: PGtkSelectionData; info: guint; user_data_or_owner: gpointer); cdecl;
|
|
|
|
+var
|
|
|
|
+ ldata : TGtkClipboard.TClipboardData absolute user_data_or_owner;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if lData.Clipboard<>clipboard then
|
|
|
|
+ exit;
|
|
|
|
+ gtk_selection_data_set(selection_data,gdk_atom_intern(PAnsiChar(lData.Target),False),8,PByte(lData.Data),Length(lData.Data));
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure ClearClipboardData(clipboard: PGtkClipboard; user_data_or_owner: gpointer); cdecl;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ ldata : TGtkClipboard.TClipboardData absolute user_data_or_owner;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if lData.Clipboard<>clipboard then
|
|
|
|
+ exit;
|
|
|
|
+ lData.Free;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+procedure TGtkClipboard.DoSetClipboardAsType(const aMimeType: String; aContents: TBytes);
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lTargets : PGtkTargetEntry;
|
|
|
|
+ lData : TClipboardData;
|
|
|
|
+ lAtom : PGdkAtom;
|
|
|
|
+ lTargetName : string;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ lTargetName:=MimeTypeToAtomName(aMimeType);
|
|
|
|
+ lAtom:=gdk_atom_intern(pansichar(lTargetName),false);
|
|
|
|
+ lTargets:=gtk_target_entry_new(Pansichar(lTargetName),0,0);
|
|
|
|
+ lData:=TClipboardData.Create(fClipboard,aContents,lTargetName);
|
|
|
|
+ gtk_clipboard_set_with_data(fclipboard,lTargets,1,@GetClipboardData,@ClearClipboardData,lData);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+constructor TGtkClipboard.Create(AOwner: TComponent);
|
|
|
|
+
|
|
|
|
+const
|
|
|
|
+ sClipboard = 'CLIPBOARD';
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ lName:PgdkAtom;
|
|
|
|
+begin
|
|
|
|
+ inherited Create(AOwner);
|
|
|
|
+ lName:=TGdkAtom.intern(sClipboard,false);
|
|
|
|
+ FClipboard:=gtk_clipboard_get(lName);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGtkClipboard.TFormatEnumerator }
|
|
|
|
+
|
|
|
|
+constructor TGtkClipboard.TFormatEnumerator.create(aClipboard: PGtkClipboard);
|
|
|
|
+begin
|
|
|
|
+ Clipboard:=aClipboard;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TGtkClipboard.TClipboardData }
|
|
|
|
+
|
|
|
|
+constructor TGtkClipboard.TClipboardData.create(aClipboard: PGtkClipboard; aData: TBytes; aTargetName: string);
|
|
|
|
+begin
|
|
|
|
+ Clipboard:=aClipBoard;
|
|
|
|
+ Data:=aData;
|
|
|
|
+ Target:=aTargetName;
|
|
|
|
+end;
|
|
|
|
+
|
|
initialization
|
|
initialization
|
|
TGtk3WidgetSet.Create(nil);
|
|
TGtk3WidgetSet.Create(nil);
|
|
|
|
+
|
|
finalization
|
|
finalization
|
|
Gtk3WidgetSet.Free; // it will nil itself
|
|
Gtk3WidgetSet.Free; // it will nil itself
|
|
|
|
|