Avoiding global objects

Looks like I mistyped that code segments, there aren't nested calls to glib::idle_add, just one.

So let me give a little more detail on my program architecture. I have a background thread that acts as an interface to the serial port. It's connected to my main thread by two mpsc channels for bidirectional communication. It abstracts away the serial port, handles the near-real-time needs of interfacing with it, and it provides a higher-level API than the serial port library I'm using provides directly. So it works like "open serial port", "send file to serial port", "log incoming serial data to file", etc.

Now my main program runs entirely within the GTK+ event loop. Sending commands to the serial thread is trivial as the serial thread is constantly looking for new events in the background on a 10ms timer. But for receiving events I have the background thread queue up a call to a receiver function to run in the main thread after every message to process it. This prevents me needing some constant timer running to check for events.

So given that context, hopefully what I'm doing makes sense. I don't want to ever pass the various program state across to the thread so it can feed it back into the callback, I want that data to stay strictly within the single main thread.

1 Like

How about moving just a reference to the program state into the callback, rather than the actual state?

I had exactly this issue. All the gtk examples are just a static main thread and it's hard to 'break out' of that to start structuring a GUI so it's modular.

Garta is the most fully fledged example I've seen that has some UI patterns in it.

I'm working on a little glade desktop app for casting to ChromeCast that has a very similar architecture to what you're after and is a bit simpler than Garta.

Basically, a UI thread and a background thread. The two threads communicate commands and state changes to each other. The UI does a try_receive every 100ms (instead of on idle) and if there are any state changes, it renders them.

It uses RefCell as described in earlier posts.

pub struct AppState {
  channels: RefCell<AppChannels>,
  widgets: RefCell<AppWidgets>,
  model: RefCell<AppModel>

It's still a work in progress. I'm happy with being able to break handlers/background workers/ui updating into separate mods, but the first thing I found was that once you introduce RefCell, you lose your 'friend' the borrow checker. You now get runtime panics if you borrow the model mutably twice for example, so you have to be disciplined as to where and when you do that. Still playing to find the best structure...