Reference » Window classes » MWindow » runMessageLoop

Elgrint::MWindow::runMessageLoop(bool) method

Declaration (see MWindow.h):

void runMessageLoop(bool disableParent = false);

Description

Executes the message loop, which brings all windows "to life".

Parameters:

Name Type Def value Description
disableParent bool false

Details

1. Message loop:

'runMessageLoop' is one of the most important (and complicated) functions in Elgrint. Without it, app windows cannot respond to input events, and, more importantly, the app is terminated immediately after creating all the windows, which usually takes a fraction of a second. This means that runMessageLoop has to be called at least once for the app to be useful as a user interface.

Even though the function is pretty complex on the inside, the basic principle is very simple: the function contains a while loop, which extracts a message from a message queue and dispatches it to a proper message handler (i.e. calls the suitable OnXXXX function of a suitable window). This while loop is called the "message loop".

 

2. The message queue:

The message queue is a special internal structure, which contains various messages, delivered to the app but not processed yet. Not all messages get into the queue – some are generated within the message loop iteration. See Messages for a detailed explanation about which messages are queued and which are not.

A message queue is needed because queued messages usually arrive from outside (from other threads, other apps, or from the system), which can happen at any moment. If the app is processing other messages at that moment, it cannot start processing the newly arrived message, because all windows operate under a single thread, and even if they weren't, it would be extremely unsafe or impractically difficult to process several messages in parallel. Therefore, the newly arrived messages wait their turn in the queue, and the app processes them one by one.

The messages are not necessarily processed in the same order they arrive, and not necessarily processed at all. For example, if a keyboard event occurs while a previous keyboard event is still in the queue, then the new event may be discarded for safety (to prevent an input event buildup, which could make the app unresponsive). Also, some messages have a higher priority and can be processed out of their turn. However, there is no need to know the specific details here – the extraction from the queue is a fully encapsulated feature.

 

3. Loop iteration:

Once a message is extracted from the queue, it is dispatched to a suitable window. For example, KeysEntered message usually goes to the current focus window (see isFocused), and CursorMoved goes to the hot window (see isHot). External messages, such as SystemSuspending, go to the screen window (see MApp::screen), and Paint message goes to the window that needs to be repainted. And so on.

The message processing itself can generate "non-queued" (aka "stacked") messages, i.e. another OnXXXX handler (of the same one) is called before the initial OnXXXX returns. For example, if OnKeysEntered calls setSize, then the resulting RectChanging and then Resized messages are stacked over the original KeysEntered. Of course such stacking can consist of more than two messages, which is especially true in case of multiple propagations. Say, a KeysEntered message is dispatched to a button inside the main bar of a mainframe window, and the key being pressed is kbCalculator. Then, the button propagates this message to the main bar, which propagates it to the mainframe, which propagates it to the screen window (which launches the calculator program). So the screen window is handling the topmost message in the stack of four KeysEntered messages.

But sooner or later, all message stacks unwind, the original OnXXXX returns, all the propagations are complete, and the main thread returns back to runMessageLoop (the message loop is said to be "resumed"), thus completing the message loop iteration. Then, runMessageLoop extracts the next message from the queue and the next iteration begins. If there are no messages in the queue, then the main thread of the app is suspended until a message appears in the queue.

 

4. Circular message prevention:

In principle, message stacking due to propagation can be infinite, if the propagation chain creates a closed circle, returning to a window, which has already propagated this message (and will propagate it again). To prevent such circular loops, which would hang the app, Elgrint forbids the same message to be delivered to the same window more than once during the same loop iteration of the same loop. Two messages are defined as the same one, if they have the same code (as returned by digMessageCode), and the same origin (as returned by digOrigin). The only exception is the Notice message, for which the notice name and ID (as returned by digNN and digNID respectively) are equal, in addition to the code and the origin. If a message is delivered to a window, while the same message is already in the stack, it is ignored (not processed in any way). That being said, two identical messages can be processed within by the same window, if the second message belongs to another message loop, which is nested within the first loop.

 

5. Nested loops:

The runMessageLoop function can be called many times during the program's run, which means that it can be called while another instance of it is already running. This is useful for creating the so called modal windows. Modal windows are windows that are opened and closed "on the spot". Although, strictly speaking, modal windows are not really necessary, they can be very convenient in certain circumstances. See example below for one possible usage. Note, however, that all message loops share the same message queue.

 

6. Loop owner:

The message loop affects all windows, because all messages for all windows arrive to the same queue, but the window that called runMessageLoop does have a special status among other windows – it becomes the owner of the loop. The loop runs for as long as its owner is open. Once the owner window is closed, the loop terminates automatically. Any window can be a loop owner, including the screen window, in which case the loop terminates when all the app windows are closed. A window can own more than one loop, i.e. it can call runMessageLoop many times.

If disableParent parameter is true, then the parent of the loop owner is automatically disabled before the message loop starts, and re-enabled (and refocused) after the loop ends. The owner itself is enabled explicitly so that it would not become disabled (see enable). This setting is useful for modal dialog boxes (see MDialogBox).

Remarks

Let us know

Please Contact us to report any errors on this page, or to suggest any improvements.

Miranor Home | About Miranor | About Elgrint | Create account | Login | Account settings | Contact Us | Privacy Policy | Site map

© Copyright 2014 by Miranor. All rights reserved. By using this site you agree to the Terms of Use.

Page last updated on August 10th, 2014.