mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-19 09:09:32 +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,
|
||||
{$ifdef CD_Windows}Windows, WinProc,{$endif}
|
||||
{$ifdef CD_Cocoa}MacOSAll, CocoaAll,{$endif}
|
||||
{$ifdef CD_X11}X, XLib, XUtil, {unitxft, Xft font support}{$endif}
|
||||
// Widgetset
|
||||
//CocoaPrivate, CocoaUtils, CocoaGDIObjects, CocoaTextLayout, CocoaProc,
|
||||
// LCL
|
||||
@ -78,6 +79,7 @@ type
|
||||
TCDWidgetSet = class(TWidgetSet)
|
||||
private
|
||||
FTerminating: Boolean;
|
||||
|
||||
{$ifdef CD_WINDOWS}
|
||||
// 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:
|
||||
@ -112,6 +114,18 @@ type
|
||||
NSApp : NSApplication;
|
||||
delegate : TCDAppDelegate;
|
||||
{$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
|
||||
{function CreateThemeServices: TThemeServices; override;
|
||||
function GetAppHandle: THandle; override;
|
||||
|
@ -48,15 +48,186 @@ end;
|
||||
initialize Windows
|
||||
------------------------------------------------------------------------------}
|
||||
procedure TCDWidgetSet.AppInit(var ScreenInfo: TScreenInfo);
|
||||
var
|
||||
ClassHint: PXClassHint;
|
||||
begin
|
||||
{$ifdef VerboseWinCE}
|
||||
// DebugLn('TWinCEWidgetSet.AppInit');
|
||||
{$ifdef Verbose_CDWS}
|
||||
// DebugLn('TCDWidgetSet.AppInit');
|
||||
{$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;
|
||||
|
||||
procedure TCDWidgetSet.AppRun(const ALoop: TApplicationMainLoop);
|
||||
var
|
||||
XEvent: TXEvent;
|
||||
// WindowEntry: TX11Window;
|
||||
MouseButton: TMouseButton;
|
||||
Sum: Integer;
|
||||
NewEvent: TXEvent;
|
||||
DoBreakRun: Boolean = False;
|
||||
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;
|
||||
|
||||
(*
|
||||
|
@ -34,6 +34,7 @@ uses
|
||||
SysUtils, Classes,
|
||||
{$ifdef CD_Windows}Windows, WinProc,{$endif}
|
||||
{$ifdef CD_Cocoa}MacOSAll, CocoaAll, CocoaPrivate, CocoaUtils,{$endif}
|
||||
{$ifdef CD_X11}X, XLib, XUtil, {unitxft, Xft font support}{$endif}
|
||||
// LCL
|
||||
Controls, LCLType, Forms, LCLProc,
|
||||
// Widgetset
|
||||
|
@ -11,7 +11,116 @@
|
||||
------------------------------------------------------------------------------}
|
||||
class function TCDWSCustomForm.CreateHandle(const AWinControl: TWinControl;
|
||||
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
|
||||
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;
|
||||
|
||||
class procedure TCDWSCustomForm.SetBorderIcons(const AForm: TCustomForm;
|
||||
|
Loading…
Reference in New Issue
Block a user