unit XRandREventWatcher;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, x, xlib, xrandr, ctypes;
type
TNotifyProc = procedure(const AEvent: TXEvent) of object;
{ TXRandREventWatcherThread }
TXRandREventWatcherThread = class(TThread)
private
FNotifier: TNotifyProc;
FEventMask: cint;
FLastEvent: TXEvent;
TerminateNotificationAtom: TAtom;
Display: PDisplay;
procedure Notify;
protected
procedure Execute; override;
public
Constructor Create({ACreateSuspended: boolean;} AEventMask: cint;
ANotifier: TNotifyProc);
destructor Destroy; override;
procedure Terminate; //override;
end;
implementation
uses LazLoggerBase;
{ TXRandREventWatcherThread }
procedure TXRandREventWatcherThread.Notify;
begin
if Assigned(FNotifier) then
FNotifier(FLastEvent);
end;
procedure TXRandREventWatcherThread.Execute;
var
//DisplayName: String;
//Display: PDisplay;
RootWnd: TWindow;
begin
writeln(ClassName, '::Execute() started');
//DisplayName := GetEnvironmentVariable('DISPLAY');
//Display := XOpenDisplay({PChar(DisplayName)} Nil);
RootWnd := RootWindow(Display, DefaultScreen(Display));
XRRSelectInput(Display, RootWnd, FEventMask {NoEventMask});
while True do
begin
XNextEvent(Display, @FLastEvent);
DebugLn('Recieved event: %d', [FLastEvent._type]);
if Terminated then
Break;
{if (FLastEvent._type = ClientMessage) and
(FLastEvent.message_type = TerminateNotificationAtom) then
Break;}
Synchronize(@Notify);
// FixMe: Freezes when no events and impossible to terminate
end;
//XCloseDisplay(Display);
writeln(ClassName, '::Execute() ended');
end;
procedure TXRandREventWatcherThread.Terminate;
var
XEvent: TXClientMessageEvent;
begin
DebugLn(ClassName, '::Terminate() started');
fillchar(XEvent,sizeof(XEvent),0);
XEvent._type:=clientmessage;
//ev.send_event:=???;
//ev.serial:=???;
XEvent.display:={XOpenDisplay(Nil)}Display;
XEvent.window:=RootWindow(XEvent.display, DefaultScreen(XEvent.display));
XEvent.message_type:=TerminateNotificationAtom;
XEvent.format:=32;
XSendEvent(XEvent.display, XEvent.window, False, NoEventMask, @XEvent);
inherited;
DebugLn(ClassName, '::Terminate() ended');
end;
constructor TXRandREventWatcherThread.Create(AEventMask: cint;
ANotifier: TNotifyProc);
begin
FNotifier := ANotifier;
FEventMask := AEventMask;
FreeOnTerminate := {True} False;
Display := XOpenDisplay({PChar(DisplayName)} Nil);
TerminateNotificationAtom := XInternAtom(Display, 'XRandREventWatcher_Terminate_Notification', False);
DebugLn('TerminateNotificationAtom: %d', [TerminateNotificationAtom]);
inherited Create(False);
NameThreadForDebugging(ClassName, ThreadID);
DebugLn('Thread ', ClassName ,' started');
end;
destructor TXRandREventWatcherThread.Destroy;
begin
DebugLn(ClassName, '::Destroy() started');
//Terminate;
inherited Destroy;
XCloseDisplay(Display);
DebugLn(ClassName, '::Destroy() ended');
end;
end.