Is there a C library for GUIs that does not require its own event loop to be used?
Asked Answered
T

4

6

I am looking for a GUI toolkit that I can use from plain C, that works at least on Linux and that does not force me to use its own eventloop – I want to use libev for the main loop and have it notify the toolkit library when X events come in or so.

I have not found anything like that – do I really have to patch a toolkit library to get what I want?

Tani answered 6/11, 2013 at 15:8 Comment(9)
I've used ncurses in my own epoll event loop -- I only call the ncurses handler, one time only, once stdin is available for reading.Brandi
@KerrekSB Yeah, I considered something like that... however, I'd probably also have to at least patch the toolkit's logic for timeouts.Tani
Even if a gui toolkit has connections to its own event loop, you should not have to set any connecting properties eg. The one I use is tied to an event loop, but only through the properties I set once I draw a control. Therefore I can avoid using the event loop altogether and choose to programmatically set any attribute as I need to reflect the state of my application.Sparker
Out of curiosity, why do you have such a need?Rawlins
For Xlib, see #8592792 , though pretty much all higher level toolkits will wrap that up and run their own event loop..Farmstead
@MatteoItalia There are several mostly network-based applications that I'd like to write, and I prefer nonblocking, callback-based programming over threaded programming – partly because I want to avoid wasting resources on extra threads and context switches, partly because I hate dealing with mutexes and stuff like that. And I want that code to be reusable in non-graphical applications, with the kind of performance that libev can give me.Tani
@Sparker I'm not sure I understand that. You mean you're using a toolkit that only reacts to data on its Xlib fd and doesn't require timeouts or anything like that?Tani
"wasting resources on extra threads and context switches" — the main resource you want to avoid wasting is your time. Act accordingly.Yan
You can use nonblocking, callback-based programming with main loop. I even think that that's how it's most often done.Bareback
S
4

Unfortunately this demand probably seriously restricts what GUI toolkits you can choose from, since they're all so bad in this regard (among many others). I don't know if this is quite fair as an answer, but I'd like to propose to you a different solution: let the GUI toolkit run whatever event loop it wants to run in its own thread or process. Since GUI libraries are notoriously bad (crashing or exiting without warning), the "own process" version might actually be the best idea -- you could communicate with your UI via a pipe, and roll your own event loop like you want to in the main process. Threads of course have their own benefits: no need to serialize data shared with the GUI, and no need to worry about the case where the user kills the main program without killing the GUI or vice versa (since threads cannot be killed individually).

Solicitude answered 6/11, 2013 at 15:32 Comment(2)
And I thought I was the only one who dislikes GUI toolkits that much... heh. Yes, using multiple threads would probably work if I find nothing better – although I somewhat dislike that solution because I'd have to write some code for preventing the two threads from fiddling with the same datastructures at the same time, because it would mean additional unnecessary context switches and because it would probably make debugging and profiling a bit harder.Tani
The cost of "unnecessary context switches" is a myth. Even if it were expensive, you're talking about something that happens once per GUI event or output, not millions of times per second. In reality, even on a single core, the latency to switch between threads of the same process is trivial. There is no page table/TLB flushing required, just swapping out the general purpose registers and a few other trivial things. The latency is on the scale of single-digit microseconds. On multi-core (the norm, now) there's no switch at all; the other thread just ends up running on the other core.Solicitude
S
2

Nuklear.

https://github.com/Immediate-Mode-UI/Nuklear

Nuklear is a GUI toolkit that only creates widgets, buttons, labels and similar but does not use a render backend on its own. You have to provide the render backend for it. You can use Xlib/X11 for the rendering. Xlib does not need a main loop. You can do something like this:

  1. Create a connection to the X11-server and create a windows
  2. Init the windows (set up an event mask, load fonts and so on)
  3. Init a Nuklear context
  4. Check for events from the X11-socket and send them to Nuklear
  5. Draw your GUI to Nuklear
  6. Send the graphic primitives from Nuklear to the X11-Server.
  7. Do all the other things you need to do
  8. Use XConnectionNumber() to get the file descriptor for the X11-Socket
  9. Use pselect() to wait on this file descriptor for reading and everything else you wait on.
  10. Repeat at step 4.

Nuklear has an example header file that provides the functions needed to combine Nuklear and Xlib, that can help you with steps 4 and 6: https://github.com/Immediate-Mode-UI/Nuklear/blob/master/demo/x11/nuklear_xlib.h

Nuklear has this features and disadvantages:

  • You can have complete control over it.
  • It is written in C89
  • It does not need any external library by itself, not even the standard headers
  • single header implementation
  • You can use the render backend you want.
  • No unrelated functions like file handling or image loading. You need other libraries or write your own functions for that.
  • Graphical possibilities limited compared to toolkits like Qt
Stila answered 20/8, 2020 at 17:12 Comment(0)
I
0

I haven't tried it, but GTK+ at least has the gtk_main_iteration_do() function, which consumes a single event. That event is a GDK event though (not a raw X11 event) so that might not be what you want.

On the other hand GTK also has some functions for working with the events so perhaps you can glue something together. I'm not very familiar with libev so I'm not sure.

Intertidal answered 6/11, 2013 at 15:39 Comment(3)
The problem is that my program/libev needs to know when that method needs to be called, and that's not really possible unless I either watch everything that glib is watching from libev or I busyloop, calling that method over and over again and wasting resources.Tani
@Tani You know whether an event is available by watching the X connection socket (only). Once you have some data on the socket, run while (gtk_events_pending()){ gtk_main_iteration(); }.Yan
@thejeh Note that e.g. glib/gtk also have an event loop that you can integrate with in the same way you use libev - you add your own sockets , timers or what else you have, and receive callbacks in a similar manner as libevFarmstead
Y
0

All toolkits support this mode of operation.

You need to watch the X server connection socket in your own event engine. Once data is available, you do (in pseudocode)

while (PendingEvent())
  ProcessEvent()

Each toolkit has its own version of ProcessEvent() and perhaps PendingEvent() too (but you can always use XPending(Display*) for that). Namely,

  • Gtk+ has gtk_events_pending() and gtk_main_iteration()
  • Xt-based toolkits have XtAppPending() and XtDispatchEvent()
  • (c++) wxWidgets has wxApp::.Pending() and wxApp::Dispatch()
  • (c++) Qt has QApplication::processEvents(), you can also implement your own QAbstractEventDispatcher and/or QEventLoop class

There are not that many actively developed C toolkits, I think Gtk+ is the only reasonable choice.

Edit With GTK at least, this technique will not work with toolkit-added timeouts, i.e. blinking cursors won't blink unless there are some other toolkit events to process. Periodic calling of gtk_main_iteration_do(FALSE) even without events pending kind of "fixes" this, but doing the toolkit loop in a different thread would be more robust.

Yan answered 6/11, 2013 at 21:58 Comment(2)
What if the toolkit wants to set a timeout or so? For blinking cursors, for example?Tani
Hm. A good question. I have not used this lately. The last time I have tried it Motif was the only game in town. I don't remember any particular problems with blinking cursors.Yan

© 2022 - 2024 — McMap. All rights reserved.