Furthermore as event loops are created on demand automatically, you can litter opens of FX::FXMessageBox or FX::FXExceptionDialog around the place and they shall run in the thread which creates them.
int main(int argc, char *argv[])
{
FXProcess myprocess(argc, argv);
FXApp myapp("MyApp");
myapp.init(argc, argv);
FXMainWindow *mainwnd=new FXMainWindow(&myapp, "My Main Window");
<widgets inside mainwnd>
...
myapp.create()
return myapp.run();
}
to: class MyPrimaryLoop : public TnFXAppEventLoop
{
FXMainWindow *mainwnd;
<widgets inside mainwnd>
public:
MyPrimaryLoop(TnFXApp *app) : TnFXAppEventLoop(app) { }
FXint execute(FXApp *app)
{
mainwnd=new FXMainWindow(app, "My Main Window");
<widgets inside mainwnd>
...
mainwnd->show();
app->create();
return app->run();
}
};
int main(int argc, char *argv[])
{
FXProcess myprocess(argc, argv);
TnFXApp myapp("MyApp");
myapp.init(argc, argv);
MyPrimaryLoop primaryLoop(&myapp);
return myapp.run(primaryLoop);
}
The reason for this is that on X11 per-thread event queues must be emulated and to prevent all threads deadlocking when the primary thread is busy, you must execute the application's core code separately.
Signals are a real hash with POSIX threads. Each thread maintains a signal mask which determines which signals it can received but signal handlers are on a per-thread basis. Thus the FOX signal intercept can be called in any thread but it should post an asynchronous message invoking the handler in the correct event loop.
You should probably know something about the implementation so you can correctly diagnose and avoid any issues which may arise. On Windows the implementation is extremely simple as Windows already provides per-thread event queues whereby messages are posted to the thread which created the window. This makes implementation on that platform trivial.
On X11 it gets more complicated as there's one event queue only. Therefore the primary thread must fetch X11 events, determine which event loop they belong to and post them to that loop for handling. Obviously to prevent deadlock the primary dispatch thread must always be available. Also because of the event loops in each thread being totally different implementations, internally TnFXApp subclasses FX::FXEventLoop twice - one for the the main X11 dispatch loop and the other for all other threads. You can always retrieve the event loop which quits the application using FXEventLoop::primaryLoop().
Watches on file descriptors are not performed the same way on Windows and X11. On Windows, the event loop local list is monitored as it monitors the thread message queue so all is well. On X11 it's much more complex as POSIX won't let you wait on a wait condition and kernel handles simultaneously, so the primary loop coalesces all the file descriptors and posts asynchronous messages when they signal.
|
Public Types |
| ID_QUIT |
| ID_DUMP |
| ID_HOVER |
| ID_LAST |
enum | { ID_QUIT,
ID_DUMP,
ID_HOVER,
ID_LAST
} |
Public Member Functions |
| TnFXApp (const FXString &name="Application", const FXString &vendor="FoxDefault") |
| ~TnFXApp () |
virtual FXEventLoop * | getEventLoop () const |
long | onCmdQuit (FXObject *, FXSelector, void *) |
virtual void | create () |
virtual void | destroy () |
virtual void | detach () |
virtual void | init (int &argc, char **argv, bool connect=TRUE) |
virtual void | exit (FXint code=0) |
virtual void | lock () |
virtual void | unlock () |
FXint | run (TnFXAppEventLoop &primaryLoop) |
QMUTEX_INLINEP bool | isLocked () const |
QMUTEX_INLINEP FXbool | locked () const |
QMUTEX_INLINEP FXuint | spinCount () const |
QMUTEX_INLINEP void | setSpinCount (FXuint c) |
QMUTEX_INLINEP bool | tryLock () |
QMUTEX_INLINEP FXbool | trylock () |
long | onCmdDump (FXObject *, FXSelector, void *) |
long | onCmdHover (FXObject *, FXSelector, void *) |
const FXString & | getAppName () const |
const FXString & | getVendorName () const |
bool | openDisplay (const FXchar *dpyname=NULL) |
bool | closeDisplay () |
void * | getDisplay () const |
bool | isInitialized () const |
FXint | getArgc () const |
const FXchar *const * | getArgv () const |
bool | hasInputMethod () const |
FXVisual * | getDefaultVisual () const |
void | setDefaultVisual (FXVisual *vis) |
FXVisual * | getMonoVisual () const |
FXRootWindow * | getRootWindow () const |
void | setRootWindow (FXRootWindow *rt) |
FXWindow * | getFocusWindow () const |
FXWindow * | getCursorWindow () const |
FXWindow * | getActiveWindow () const |
FXPopup * | getPopupWindow () const |
FXWindow * | findWindowWithId (FXID xid) const |
FXWindow * | findWindowAt (FXint rx, FXint ry, FXID window=0) const |
void | addTimeout (FXObject *tgt, FXSelector sel, FXuint ms=1000, void *ptr=NULL) |
void | removeTimeout (FXObject *tgt, FXSelector sel) |
bool | hasTimeout (FXObject *tgt, FXSelector sel) const |
FXuint | remainingTimeout (FXObject *tgt, FXSelector sel) const |
void | handleTimeouts () |
void | addChore (FXObject *tgt, FXSelector sel, void *ptr=NULL) |
void | removeChore (FXObject *tgt, FXSelector sel) |
FXbool | hasChore (FXObject *tgt, FXSelector sel) const |
void | addSignal (FXint sig, FXObject *tgt, FXSelector sel, FXbool immediate=FALSE, FXuint flags=0) |
void | removeSignal (FXint sig) |
bool | addInput (FXInputHandle fd, FXuint mode, FXObject *tgt, FXSelector sel) |
bool | removeInput (FXInputHandle fd, FXuint mode) |
bool | getKeyState (FXuint keysym) const |
bool | peekEvent () |
bool | runOneEvent (bool blocking=true) |
FXint | run () |
FXint | runUntil (FXuint &condition) |
FXint | runWhileEvents () |
FXint | runModalWhileEvents (FXWindow *window=NULL) |
FXint | runModal () |
FXint | runModalFor (FXWindow *window) |
FXint | runModalWhileShown (FXWindow *window) |
FXint | runPopup (FXWindow *window) |
FXbool | isModal (FXWindow *window) const |
FXWindow * | getModalWindow () const |
FXModality | getModality () const |
void | stop (FXint value=0) |
void | stopModal (FXWindow *window, FXint value=0) |
void | stopModal (FXint value=0) |
void | forceRefresh () |
void | refresh () |
void | flush (bool sync=false) |
void | repaint () |
FXRegistry & | reg () |
FXDragType | registerDragType (const FXString &name) const |
FXString | getDragTypeName (FXDragType type) const |
FXWindow * | getDragWindow () const |
void | beep () |
void | errorBeep () |
void | setNormalFont (FXFont *font) |
FXFont * | getNormalFont () const |
void | beginWaitCursor () |
void | endWaitCursor () |
void | setWaitCursor (FXCursor *cur) |
FXCursor * | getWaitCursor () const |
FXCursor * | getDefaultCursor (FXDefaultCursor which) const |
void | setDefaultCursor (FXDefaultCursor which, FXCursor *cur) |
FXbool | writeWindow (FXStream &store, FXWindow *window) |
FXbool | readWindow (FXStream &store, FXWindow *&window, FXWindow *father, FXWindow *owner) |
FXuint | getTypingSpeed () const |
FXuint | getClickSpeed () const |
FXuint | getScrollSpeed () const |
FXuint | getScrollDelay () const |
FXuint | getBlinkSpeed () const |
FXuint | getAnimSpeed () const |
FXuint | getMenuPause () const |
FXuint | getTooltipPause () const |
FXuint | getTooltipTime () const |
FXint | getDragDelta () const |
FXint | getWheelLines () const |
FXint | getScrollBarSize () const |
void | setTypingSpeed (FXuint speed) |
void | setClickSpeed (FXuint speed) |
void | setScrollSpeed (FXuint speed) |
void | setScrollDelay (FXuint delay) |
void | setBlinkSpeed (FXuint speed) |
void | setAnimSpeed (FXuint speed) |
void | setMenuPause (FXuint pause) |
void | setTooltipPause (FXuint pause) |
void | setTooltipTime (FXuint time) |
void | setDragDelta (FXint delta) |
void | setWheelLines (FXint lines) |
void | setScrollBarSize (FXint size) |
FXColor | getBorderColor () const |
FXColor | getBaseColor () const |
FXColor | getHiliteColor () const |
FXColor | getShadowColor () const |
FXColor | getBackColor () const |
FXColor | getForeColor () const |
FXColor | getSelforeColor () const |
FXColor | getSelbackColor () const |
FXColor | getTipforeColor () const |
FXColor | getTipbackColor () const |
FXColor | getSelMenuTextColor () const |
FXColor | getSelMenuBackColor () const |
void | setBorderColor (FXColor color) |
void | setBaseColor (FXColor color) |
void | setHiliteColor (FXColor color) |
void | setShadowColor (FXColor color) |
void | setBackColor (FXColor color) |
void | setForeColor (FXColor color) |
void | setSelforeColor (FXColor color) |
void | setSelbackColor (FXColor color) |
void | setTipforeColor (FXColor color) |
void | setTipbackColor (FXColor color) |
void | setSelMenuTextColor (FXColor color) |
void | setSelMenuBackColor (FXColor color) |
FXuint | getWindowCount () const |
virtual void | save (FXStream &store) const |
virtual void | load (FXStream &store) |
void | dumpWidgets () const |
void | addDestructionUpcall (void(*func)(void *), void *data) |
void | removeDestructionUpcall (void(*func)(void *), void *data) |
virtual long | onDefault (FXObject *, FXSelector, void *) |
const FXchar * | getClassName () const |
bool | isMemberOf (const FXMetaClass *metaclass) const |
virtual long | tryHandle (FXObject *sender, FXSelector sel, void *ptr) |
QTransString | tr (const char *text, const char *hint=0) |
virtual void * | getPythonObject () const |
virtual void | decouplePythonObject () const |
Static Public Member Functions |
static TnFXApp * | instance () |
static QMUTEX_INLINEP bool | setMutexDebugYield (bool v) |
static FXEventLoop * | getPrimaryEventLoop () |
static FXlong | time () |
Static Public Attributes |
static const FXuchar * | copyright |
Protected Member Functions |
virtual bool | getNextEvent (FXRawEvent &ev, bool blocking=true) |
virtual bool | dispatchEvent (FXRawEvent &ev) |
Protected Attributes |
FXEventLoop * | eventLoop |