mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-21 06:39:39 +02:00
customdrawnws: Advances the X11 backend
git-svn-id: trunk@33557 -
This commit is contained in:
parent
88579992c9
commit
1b15a816ff
@ -32,6 +32,7 @@ uses
|
|||||||
Types, Classes, SysUtils, Math,
|
Types, Classes, SysUtils, Math,
|
||||||
{$ifdef CD_Windows}Windows, WinProc,{$endif}
|
{$ifdef CD_Windows}Windows, WinProc,{$endif}
|
||||||
{$ifdef CD_Cocoa}MacOSAll, CocoaAll,{$endif}
|
{$ifdef CD_Cocoa}MacOSAll, CocoaAll,{$endif}
|
||||||
|
{$ifdef CD_X11}X, XLib, XUtil, {unitxft, Xft font support}{$endif}
|
||||||
// Widgetset
|
// Widgetset
|
||||||
//CocoaPrivate, CocoaUtils, CocoaGDIObjects, CocoaTextLayout, CocoaProc,
|
//CocoaPrivate, CocoaUtils, CocoaGDIObjects, CocoaTextLayout, CocoaProc,
|
||||||
// LCL
|
// LCL
|
||||||
@ -78,6 +79,7 @@ type
|
|||||||
TCDWidgetSet = class(TWidgetSet)
|
TCDWidgetSet = class(TWidgetSet)
|
||||||
private
|
private
|
||||||
FTerminating: Boolean;
|
FTerminating: Boolean;
|
||||||
|
|
||||||
{$ifdef CD_WINDOWS}
|
{$ifdef CD_WINDOWS}
|
||||||
// In win32 it is: The parent of all windows, represents the button of the taskbar
|
// In win32 it is: The parent of all windows, represents the button of the taskbar
|
||||||
// In wince it is just an invisible window, but retains the following functions:
|
// In wince it is just an invisible window, but retains the following functions:
|
||||||
@ -112,6 +114,18 @@ type
|
|||||||
NSApp : NSApplication;
|
NSApp : NSApplication;
|
||||||
delegate : TCDAppDelegate;
|
delegate : TCDAppDelegate;
|
||||||
{$endif}
|
{$endif}
|
||||||
|
public
|
||||||
|
{$ifdef CD_X11}
|
||||||
|
FDisplayName: string;
|
||||||
|
FDisplay: PDisplay;
|
||||||
|
|
||||||
|
LeaderWindow: X.TWindow;
|
||||||
|
ClientLeaderAtom: TAtom;
|
||||||
|
|
||||||
|
FWMProtocols: TAtom; // Atom for "WM_PROTOCOLS"
|
||||||
|
FWMDeleteWindow: TAtom; // Atom for "WM_DELETE_WINDOW"
|
||||||
|
FWMHints: TAtom; // Atom for "_MOTIF_WM_HINTS"
|
||||||
|
{$endif}
|
||||||
protected
|
protected
|
||||||
{function CreateThemeServices: TThemeServices; override;
|
{function CreateThemeServices: TThemeServices; override;
|
||||||
function GetAppHandle: THandle; override;
|
function GetAppHandle: THandle; override;
|
||||||
|
@ -48,15 +48,186 @@ end;
|
|||||||
initialize Windows
|
initialize Windows
|
||||||
------------------------------------------------------------------------------}
|
------------------------------------------------------------------------------}
|
||||||
procedure TCDWidgetSet.AppInit(var ScreenInfo: TScreenInfo);
|
procedure TCDWidgetSet.AppInit(var ScreenInfo: TScreenInfo);
|
||||||
|
var
|
||||||
|
ClassHint: PXClassHint;
|
||||||
begin
|
begin
|
||||||
{$ifdef VerboseWinCE}
|
{$ifdef Verbose_CDWS}
|
||||||
// DebugLn('TWinCEWidgetSet.AppInit');
|
// DebugLn('TCDWidgetSet.AppInit');
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
|
// Maybe it was passed as a -display parameter. Lets check first!
|
||||||
|
if FDisplayName = '' then
|
||||||
|
FDisplayName := XDisplayName(nil);
|
||||||
|
|
||||||
|
FDisplay := XOpenDisplay(PChar(FDisplayName));
|
||||||
|
|
||||||
|
if not Assigned(FDisplay) then
|
||||||
|
raise Exception.Create('[TCDWidgetSet.AppInit] XOpenDisplay failed');
|
||||||
|
|
||||||
|
//if (not (woX11SkipWMHints in WindowOptions)) and (woWindow in WindowOptions) then
|
||||||
|
//begin
|
||||||
|
LeaderWindow := XCreateSimpleWindow(FDisplay, XDefaultRootWindow(FDisplay), 0, 0, 1, 1, 0, 0, 0);
|
||||||
|
|
||||||
|
ClassHint := XAllocClassHint;
|
||||||
|
ClassHint^.res_name := 'fpGFX'; // !!! use app name
|
||||||
|
ClassHint^.res_class := 'FpGFX';
|
||||||
|
XSetWMProperties(FDisplay, LeaderWindow, nil, nil, nil, 0, nil, nil, ClassHint);
|
||||||
|
XFree(ClassHint);
|
||||||
|
ClientLeaderAtom := XInternAtom(FDisplay, 'WM_CLIENT_LEADER', False);
|
||||||
|
//end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCDWidgetSet.AppRun(const ALoop: TApplicationMainLoop);
|
procedure TCDWidgetSet.AppRun(const ALoop: TApplicationMainLoop);
|
||||||
|
var
|
||||||
|
XEvent: TXEvent;
|
||||||
|
// WindowEntry: TX11Window;
|
||||||
|
MouseButton: TMouseButton;
|
||||||
|
Sum: Integer;
|
||||||
|
NewEvent: TXEvent;
|
||||||
|
DoBreakRun: Boolean = False;
|
||||||
begin
|
begin
|
||||||
|
while (DoBreakRun = False) do
|
||||||
|
begin
|
||||||
|
{ if Assigned(OnIdle) then
|
||||||
|
begin
|
||||||
|
if not XCheckMaskEvent(FDisplay, MaxInt, @XEvent) then
|
||||||
|
begin
|
||||||
|
if Assigned(OnIdle) then OnIdle(Self);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else}
|
||||||
|
XNextEvent(FDisplay, @XEvent);
|
||||||
|
|
||||||
|
// if the event filter returns true then it ate the message
|
||||||
|
//if Assigned(FEventFilter) and FEventFilter(XEvent) then continue;
|
||||||
|
|
||||||
|
//if Forms.Count = 0 then continue;
|
||||||
|
|
||||||
|
// According to a comment in X.h, the valid event types start with 2!
|
||||||
|
if XEvent._type >= 2 then
|
||||||
|
begin
|
||||||
|
// WindowEntry := TX11Window(FindWindowByXID(XEvent.XAny.Window));
|
||||||
|
|
||||||
|
// if not Assigned(WindowEntry) then
|
||||||
|
// begin
|
||||||
|
// WriteLn('fpGFX/X11: Received X event "', GetXEventName(XEvent._type), '" for unknown window');
|
||||||
|
// continue;
|
||||||
|
// end;
|
||||||
|
|
||||||
|
// WindowEntry.FXEvent := @XEvent;
|
||||||
|
|
||||||
|
case XEvent._type of
|
||||||
|
X.DestroyNotify:
|
||||||
|
begin
|
||||||
|
// Forms.Remove(WindowEntry);
|
||||||
|
end;
|
||||||
|
X.KeyPress:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvKeyPressed(XEvent.xkey.keycode);
|
||||||
|
end;
|
||||||
|
X.KeyRelease:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvKeyReleased(XEvent.xkey.keycode);
|
||||||
|
end;
|
||||||
|
X.ButtonPress:
|
||||||
|
begin
|
||||||
|
{ if XButtonToMouseButton(XEvent.xbutton.button, MouseButton) then
|
||||||
|
WindowEntry.EvMousePressed(MouseButton,
|
||||||
|
Point(XEvent.xbutton.x, XEvent.xbutton.y))
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if XEvent.xbutton.button = 4 then Sum := -1
|
||||||
|
else Sum := 1;
|
||||||
|
|
||||||
|
// Check for other mouse wheel messages in the queue
|
||||||
|
while XCheckTypedWindowEvent(GFApplication.Handle,
|
||||||
|
WindowEntry.Handle, X.ButtonPress, @NewEvent) do
|
||||||
|
begin
|
||||||
|
if NewEvent.xbutton.Button = 4 then Dec(Sum)
|
||||||
|
else if NewEvent.xbutton.Button = 5 then Inc(Sum)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
XPutBackEvent(GFApplication.Handle, @NewEvent);
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
WindowEntry.EvMouseWheel(
|
||||||
|
Sum, Point(XEvent.xbutton.x, XEvent.xbutton.y));
|
||||||
|
end;}
|
||||||
|
end;
|
||||||
|
X.ButtonRelease:
|
||||||
|
begin
|
||||||
|
{ Release events are only for mouse buttons, and not mouse wheel moviments }
|
||||||
|
{ if (XEvent.xbutton.button >= 1) and (XEvent.xbutton.button <= 3) then
|
||||||
|
begin
|
||||||
|
XButtonToMouseButton(XEvent.xbutton.button, MouseButton);
|
||||||
|
|
||||||
|
WindowEntry.EvMouseReleased(
|
||||||
|
MouseButton,
|
||||||
|
Point(XEvent.xbutton.x, XEvent.xbutton.y));
|
||||||
|
end;}
|
||||||
|
end;
|
||||||
|
X.EnterNotify:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvMouseEnter(
|
||||||
|
// Point(XEvent.xbutton.x, XEvent.xbutton.y));
|
||||||
|
end;
|
||||||
|
X.LeaveNotify:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvMouseLeave();
|
||||||
|
end;
|
||||||
|
X.MotionNotify:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvMouseMove(
|
||||||
|
// Point(XEvent.xbutton.x, XEvent.xbutton.y));
|
||||||
|
end;
|
||||||
|
X.FocusIn:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvFocusIn();
|
||||||
|
end;
|
||||||
|
X.FocusOut:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvFocusOut();
|
||||||
|
end;
|
||||||
|
X.MapNotify:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvShow();
|
||||||
|
end;
|
||||||
|
X.UnmapNotify:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvHide();
|
||||||
|
end;
|
||||||
|
X.ReparentNotify:
|
||||||
|
begin
|
||||||
|
// WindowEntry.EvCreate();
|
||||||
|
end;
|
||||||
|
X.Expose:
|
||||||
|
begin
|
||||||
|
{$Note We can do performance tuning here by looking at Count.
|
||||||
|
For now we are just ignoring all expose messages where Count <> 0 }
|
||||||
|
{ if XEvent.xexpose.count = 0 then
|
||||||
|
begin
|
||||||
|
WindowEntry.EvPaint();
|
||||||
|
end;}
|
||||||
|
end;
|
||||||
|
X.ConfigureNotify:
|
||||||
|
begin
|
||||||
|
// WindowEntry.Dispatch(XEvent);
|
||||||
|
end;
|
||||||
|
X.ClientMessage:
|
||||||
|
begin
|
||||||
|
// WindowEntry.Dispatch(XEvent);
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
// WriteLn('fpGFX/X11: Unhandled X11 event received: ', GetXEventName(XEvent._type));
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
DoBreakRun := False;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
(*
|
(*
|
||||||
|
@ -34,6 +34,7 @@ uses
|
|||||||
SysUtils, Classes,
|
SysUtils, Classes,
|
||||||
{$ifdef CD_Windows}Windows, WinProc,{$endif}
|
{$ifdef CD_Windows}Windows, WinProc,{$endif}
|
||||||
{$ifdef CD_Cocoa}MacOSAll, CocoaAll, CocoaPrivate, CocoaUtils,{$endif}
|
{$ifdef CD_Cocoa}MacOSAll, CocoaAll, CocoaPrivate, CocoaUtils,{$endif}
|
||||||
|
{$ifdef CD_X11}X, XLib, XUtil, {unitxft, Xft font support}{$endif}
|
||||||
// LCL
|
// LCL
|
||||||
Controls, LCLType, Forms, LCLProc,
|
Controls, LCLType, Forms, LCLProc,
|
||||||
// Widgetset
|
// Widgetset
|
||||||
|
@ -11,7 +11,116 @@
|
|||||||
------------------------------------------------------------------------------}
|
------------------------------------------------------------------------------}
|
||||||
class function TCDWSCustomForm.CreateHandle(const AWinControl: TWinControl;
|
class function TCDWSCustomForm.CreateHandle(const AWinControl: TWinControl;
|
||||||
const AParams: TCreateParams): TLCLIntfHandle;
|
const AParams: TCreateParams): TLCLIntfHandle;
|
||||||
|
const
|
||||||
|
WindowHints: TXWMHints = (
|
||||||
|
flags: InputHint or StateHint or WindowGroupHint;
|
||||||
|
input: 1;
|
||||||
|
initial_state: NormalState;
|
||||||
|
icon_pixmap: 0;
|
||||||
|
icon_window: 0;
|
||||||
|
icon_x: 0;
|
||||||
|
icon_y: 0;
|
||||||
|
icon_mask: 0;
|
||||||
|
window_group: 0;
|
||||||
|
);
|
||||||
|
var
|
||||||
|
Colormap: TColormap;
|
||||||
|
Attr: TXSetWindowAttributes;
|
||||||
|
SizeHints: TXSizeHints;
|
||||||
|
ClassHint: PXClassHint;
|
||||||
|
lParentHandle: X.TWindow;
|
||||||
|
mask: longword;
|
||||||
|
AForm: TCustomForm absolute AWinControl;
|
||||||
begin
|
begin
|
||||||
|
Colormap := XDefaultColormap(CDWidgetSet.FDisplay, XDefaultScreen(CDWidgetSet.FDisplay));
|
||||||
|
Attr.Colormap := Colormap;
|
||||||
|
|
||||||
|
SizeHints.flags := XUtil.PSize;
|
||||||
|
SizeHints.x := 0;
|
||||||
|
SizeHints.y := 0;
|
||||||
|
SizeHints.width := 200;
|
||||||
|
SizeHints.height := 200;
|
||||||
|
|
||||||
|
{ Make sure we use the correct parent handle }
|
||||||
|
{ if FParent <> nil then
|
||||||
|
lParentHandle := TX11Window(FParent).Handle
|
||||||
|
else}
|
||||||
|
lParentHandle := XDefaultRootWindow(CDWidgetSet.FDisplay);
|
||||||
|
|
||||||
|
{ setup attributes and masks }
|
||||||
|
if (AForm.BorderStyle in [bsNone, bsToolWindow]) then
|
||||||
|
begin
|
||||||
|
Attr.Override_Redirect := 1; // this removes window borders
|
||||||
|
mask := CWOverrideRedirect;// or CWColormap;
|
||||||
|
end
|
||||||
|
{ else if (woPopup in WindowOptions) then
|
||||||
|
begin
|
||||||
|
Attr.Override_Redirect := True; // this removes window borders
|
||||||
|
Attr.save_under := True;
|
||||||
|
mask := CWOverrideRedirect or CWSaveUnder;
|
||||||
|
end}
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Attr.Override_Redirect := 0;
|
||||||
|
mask := CWColormap;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := XCreateWindow(
|
||||||
|
CDWidgetSet.FDisplay,
|
||||||
|
lParentHandle, // parent
|
||||||
|
SizeHints.x, SizeHints.x, // position (top, left)
|
||||||
|
SizeHints.width, SizeHints.height, // default size (width, height)
|
||||||
|
0, // border size
|
||||||
|
CopyFromParent, // depth
|
||||||
|
InputOutput, // class
|
||||||
|
XDefaultVisual(CDWidgetSet.FDisplay, XDefaultScreen(CDWidgetSet.FDisplay)), // visual
|
||||||
|
mask,
|
||||||
|
@Attr);
|
||||||
|
|
||||||
|
if Result = 0 then
|
||||||
|
raise Exception.Create('[TCDWSCustomForm.CreateHandle] Window creation failed');
|
||||||
|
|
||||||
|
XSelectInput(CDWidgetSet.FDisplay, Result, KeyPressMask or KeyReleaseMask
|
||||||
|
or ButtonPressMask or ButtonReleaseMask
|
||||||
|
or EnterWindowMask or LeaveWindowMask
|
||||||
|
or ButtonMotionMask or PointerMotionMask
|
||||||
|
or ExposureMask
|
||||||
|
or FocusChangeMask
|
||||||
|
or StructureNotifyMask
|
||||||
|
// or PropertyChangeMask
|
||||||
|
);
|
||||||
|
|
||||||
|
// if (not (woX11SkipWMHints in WindowOptions)) and (woWindow in WindowOptions) then
|
||||||
|
// begin
|
||||||
|
XSetStandardProperties(CDWidgetSet.FDisplay, Result, nil, nil, 0,
|
||||||
|
argv, argc, @SizeHints);
|
||||||
|
|
||||||
|
XSetWMNormalHints(CDWidgetSet.FDisplay, Result, @SizeHints);
|
||||||
|
|
||||||
|
WindowHints.flags := WindowGroupHint;
|
||||||
|
WindowHints.window_group := CDWidgetSet.LeaderWindow;
|
||||||
|
XSetWMHints(CDWidgetSet.FDisplay, Result, @WindowHints);
|
||||||
|
|
||||||
|
XChangeProperty(CDWidgetSet.FDisplay, Result, CDWidgetSet.ClientLeaderAtom, 33, 32,
|
||||||
|
PropModeReplace, @CDWidgetSet.LeaderWindow, 1);
|
||||||
|
|
||||||
|
// We want to get a Client Message when the user tries to close this window
|
||||||
|
if CDWidgetSet.FWMProtocols = 0 then
|
||||||
|
CDWidgetSet.FWMProtocols := XInternAtom(CDWidgetSet.FDisplay, 'WM_PROTOCOLS', False);
|
||||||
|
if CDWidgetSet.FWMDeleteWindow = 0 then
|
||||||
|
CDWidgetSet.FWMDeleteWindow := XInternAtom(CDWidgetSet.FDisplay, 'WM_DELETE_WINDOW', False);
|
||||||
|
|
||||||
|
// send close event instead of quitting the whole application...
|
||||||
|
XSetWMProtocols(CDWidgetSet.FDisplay, Result, @CDWidgetSet.FWMDeleteWindow, 1);
|
||||||
|
// end;
|
||||||
|
|
||||||
|
{ Child windows do not appear until parent (lParentHandle) is mapped }
|
||||||
|
// if FParent <> nil then
|
||||||
|
// XMapSubwindows(CDWidgetSet.FDisplay, lParentHandle);
|
||||||
|
|
||||||
|
// for modal windows, this is necessary
|
||||||
|
// if (woModal in WindowOptions) then
|
||||||
|
// XSetTransientForHint(GFApplication.Handle, Handle, Handle);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class procedure TCDWSCustomForm.SetBorderIcons(const AForm: TCustomForm;
|
class procedure TCDWSCustomForm.SetBorderIcons(const AForm: TCustomForm;
|
||||||
|
Loading…
Reference in New Issue
Block a user