customdrawnws: Advances the X11 backend

git-svn-id: trunk@33557 -
This commit is contained in:
sekelsenmat 2011-11-16 10:36:59 +00:00
parent 88579992c9
commit 1b15a816ff
4 changed files with 297 additions and 2 deletions

View File

@ -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;

View File

@ -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;
(*

View File

@ -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

View File

@ -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;