Sign in Join
Wiki copytemporary

Main Loop Hooks: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Main Loop Hooks

OldNewLine
1+## Problem statement
2+
3+You need to wait for some event (on socket or pipe or ...) to happen, but you want to do this in the main (GUI) thread and do not want to block the GUI and also you do not want multi-threading. Solution to this problem is the ability to add extra "handles" to be watched in the main event loop.
4+
5+## Solution details
6+
7+In unit [[doc:lcl/lclintf|LCLIntf]] three functions have been added to provide for this functionality, they are:
8+
9+``` pascal
10+AddEventHandler(AHandle: THandle; AFlags: dword;
11+ AEventHandler: TWaitHandleEvent; AData: PtrInt): PEventHandler;
12+RemoveEventHandler(var AHandler: PEventHandler);
13+SetEventHandlerFlags(AHandler: PEventHandler; NewFlags: dword);
14+```
15+
16+The [[doc:lcl/interfacebase/twaithandleevent.html|TWaitHandleEvent]] type is declared in unit InterfaceBase as:
17+
18+``` pascal
19+TWaitHandleEvent = procedure(AData: PtrInt; AFlags: dword) of object;
20+```
21+
22+[[doc:lcl/lclintf/addeventhandler.html|AddEventHandler]] adds a handle to be watched to the main event loop. When the handle is "signalled", then the procedure specified in ACallback will be called with as a parameter the AData that was passed when registering the event handler, and any Flags, which are OS specific. The flags passed to AddEventHandler can be modified using SetEventHandlerFlags. The returned handler (a pointer) by AddEventHandler should be passed to RemoveEventHandler to stop watching the associated handle. Main reason for the flags is to provide a way to turn on and off various event types which you want watched (read/write/error).
23+
24+[[doc:lcl/lclintf/removeeventhandler.html|RemoveEventHandler]] stops watching the specified handle. RemoveEventHandler will set AHandler to nil before returning. Its argument is a pointer returned by AddEventHandler.
25+
26+[[doc:lcl/lclintf/seteventhandlerflags.html|SetEventHandlerFlags]] changes the flags on an active EventHandler. Currently this does nothing on windows (see below), but it is vital on other platforms to provide ways on turning event types OFF and ON for being watched.
27+
28+### Windows
29+
30+The AFlags parameter in AddEventHandler is unused, and the AFlags in TWaitHandleEvent will be 0, in the current implementation.
31+
32+Win32 supports the following handle types, basically the things supported by MsgWaitForMultipleObjects:
33+
34+- change notifications (for files and directories)
35+- console input
36+- events: signalled with SetEvent winapi function
37+- mutexes: signalled when it is not owned anymore
38+- processes: signalled when they terminate
39+- semaphore: signalled when it's *count* is greater than zero
40+- threads: signalled when they terminate
41+- timers: signalled when expired, see SetWaitableTimer
42+
43+### Gtk/Unix
44+
45+The AFlags parameter in AddEventHandler specifies the condition in which the handle should be signalled, with the possible values being the ones documented in the GIOCondition type in the [glib](http://developer.gimp.org/api/2.0/glib/glib-IO-Channels.html#GIOCondition) reference.
46+
47+In the callback, the AFlags will contain the condition, of the above referenced GIOCondition type, that was satisfied.
48+
49+Gtk/unix supports the following handle types:
50+
51+- files
52+- sockets
53+- pipes
54+
55+Note that win32 does not support sockets or pipes (at least, their use is "discouraged" by MSDN). Suggestion: use WSAEventSelect to create an event associated with a socket and pass the event handle.
56+
57+### Qt4
58+
59+The Qt4 interface is internally different from Gtk and Win32, but has been emulated within LCL as close as possible to the GTK logic. Even the flags passed have been made compatible (GIO_IN, GIO_OUT and GIO_ERR). The only actual difference for the user is that should 2+ event types happen on the same socket "at once" the callback will not be called with an OR-ed version of the flags, but instead called twice in a row. This is a Qt4 limitation and the possibility of calling EXCEPTION event before a READ or WRITE event is to my knowledge unavoidable. The Qt4 interface was added in Lazarus v0.9.29 trunk (so it should appear in 0.9.30 stable).
60+
61+### Flags
62+
63+Currently the FLAGS parameters are widgetset specific. On windows, this parameter is completely unused (see above), but on Gtk, Qt and others it is used to set what type of events to watch.
64+
65+### Pipes and Process Termination
66+
67+To provide a cross-platform solution for pipes (not well supported on win32) and processes (not well supported on gtk/unix) additional functions have been added:
68+
69+``` pascal
70+TChildExitReason = (cerExit, cerSignal);
71+TPipeReason = (prDataAvailable, prBroken, prCanWrite);
72+TPipeReasons = set of TPipeReason;
73+
74+TChildExitEvent = procedure(AData: PtrInt; AReason: TChildExitReason; AInfo: dword) of object;
75+TPipeEvent = procedure(AData: PtrInt; AReasons: TPipeReasons) of object;
76+
77+function AddProcessEventHandler(AHandle: THandle;
78+ AEventHandler: TChildExitEvent; AData: PtrInt): PProcessEventHandler;
79+procedure RemoveProcessEventHandler(var AHandler: PProcessEventHandler);
80+
81+function AddPipeEventHandler(AHandle: THandle;
82+ AEventHandler: TPipeEvent; AData: PtrInt): PPipeEventHandler;
83+procedure RemovePipeEventHandler(var AHandler: PPipeEventHandler);
84+```
85+
86+When a process terminates the event handler specified will be called. AInfo will contain the exit code if AReason is cerExit, or (on unix only) the termination signal if AReason is cerSignal. For gtk/unix, use the PID to watch as AHandle. Internally, a signal handler is installed to catch the SIGCHLD signal. On win32, AddEventHandler is used to watch process termination.
87+
88+To watch a pipe for incoming data, pass the file descriptor (unix) or the pipe read-end handle to AddPipeEventHandler with a custom chosen event handler method as AEventHandler. On gtk/unix, AddEventHandler is called to watch the file descriptor for traffic. On win32, the message loop will timeout every 100 msecs to check all watched pipes for available data; if data is available, the event handler is called.
89+
90+## See also
91+
92+- [[Asynchronous Calls]]
93+- [[Multithreaded Application Tutorial]]
94+
95+---
96+*From the Free Pascal wiki, page "Main Loop Hooks", as it stood on 2020-02-19 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history