Signal und mainloop

Post Reply
Message
Author
grisu1972
Posts: 16
Joined: 22. Jul 2008 11:03

Signal und mainloop

#1 Post by grisu1972 »

Hallo Leute,

folgendes Problem:
Ich habe eine Applikation die auf Intrinsics (XtAppMainLoop()) beruht.
Diese Applikation soll auf ein Signal (SIGUSR2) reagieren. Dabei soll die Abarbeitung nicht asychron zum Programmablauf geschehen, sondern innerhalb der mainloop.
Dazu brauche ich ein XtAddCallback().
Die Methode XtAddCallback() ist aber mit einem Widget verknüpft. An dieser Stelle ist mir das Konzept mit der Verknüpfung zum Signal nicht klar!?!

Kann mir bitte jemand helfen!

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#2 Post by Janka »

Xt... sind keine X-Intrinsics, sondern schon X-Toolkit. Deshalb ja Xt...

XtAddCallback() ist dazu da, um X-Events an ein Widget mit einer Callback-Routine zu verknüpfen, z.B. um beim Draufklicken aus das Widget dieses anders darzustellen und so einen Button zu bauen. Mit Signalen hat das gar nichts zu tun.

In der Mainloop steht ein X-Programm normalerweise mit XNextEvent(), welches blockiert. Das Blockieren ist nicht mehr nützlich, sobald man noch etwas anderes als X-Events verarbeiten will. Viele Programme verwenden dann für die Filevents einen zweiten Thread, aber in deinem Fall nützt das nichts.

Du könntest die Events stattdessen mit XCheckWindowEvent() oder ähnlich abholen, das blockiert nämlich nicht. Dann ein Flag in einer Variablen abfragen, die in der Signalhandlerfunktion gesetzt wird, sobald das Signal kommt. Dann das Flag löschen. Dann mit usleep() eine Zeit lang warten, damit der Prozess nicht 100% Last erzeugt.

Das funktioniert, ist aber ziemlich doof, weil man eben nicht blockierend warten kann und XtAppMainLoop funktioniert so auch nicht. Es wäre besser, statt eines Signals einen X-Event an die Applikation zu schicken. Evtl. kannst du das aber auch intern machen, indem du innerhalb des Signalhandlers XSendEvent() benutzt -- dann schickt die Applikation sozusagen einen Event an sich selbst, sobald sie von außen ein Signal bekommt.

Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

grisu1972
Posts: 16
Joined: 22. Jul 2008 11:03

#3 Post by grisu1972 »

Entschuldigung,
vielleicht bin ich ungeeignet aber alles was ich bzg callback Funktionen und XtAppMainLoop gefunden habe beruht auf XtAddCallback() und damit auf der verknüpfung mit einem Widget!

Mir ist nicht klar wie ich mit einem XSendEvent ein callback aus der XtAppMainLoop aufrufen kann? Kann Du mich an der Stelle bitte nochmals unterstützen?
Meiner Meinung nach wiederspricht sich das sogar!

Danke
Carsten

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#4 Post by Janka »

Es widerspricht sich nicht.

Also:
Du hast eine Applikation, die in XtAppMainLoop blockiert und auf das nächste Event -- Tastatur, Maus, Map, Configure etc. .. wartet. Dieses Event kann alles mögliche sein. Manche Events, wie z.B. Map und Configure wertet XtAppMainLoop() intern aus, indem es den Fensterinhalt neu zeichnet oder in der Größe ändert. Andere Events musst du selbst hinzufügen.

Du schickst also aus dem Signalhandler heraus ein Map oder Configure-Event an die Applikation selbst. Dadurch wird, sobald der Signalhandler beendet ist, XtAppMainLoop aus der Blockierung erwachen und genau dieses Event bearbeiten. So wie du das haben wolltest.


Zu den Callbacks:
Wie dir sicher schon aufgefallen ist, kehrt XtAppMainLoop() während des Laufes der Applikation nicht zurück. Wie also sollen Buttonklicks etc. implementiert werden? Ganz einfach: Du musst *zuvor* einen "Callback" einrichten. XtAppMainLoop() guckt in die Tabelle der aktuellen Callbacks rein, ob einer dem Event entspricht, der gerade zu bearbeiten ist. Wenn ja, wird der entsprechende Callback aufgerufen. Wenn nein, wird der Event verworfen.

Wenn du also noch was anderes als die von XtAppMainLoop() verarbeiteten Events erreichen willst, musst du dafür einen Eventhandler installieren.

Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

grisu1972
Posts: 16
Joined: 22. Jul 2008 11:03

#5 Post by grisu1972 »

Hallo nochmal (ich kriege Minderwertigkeitskomplexe):

Bis auf dieses Winzigkeit, das meine Applikationa abstürtzt nachdem ich das Event empfangen habe funktioniert es:

Folgendes habe ich gemacht

Methode die auf das SIGUSR2 reagiert!
void receiveSIGUSR2(int sig)
{
Window tmpWin = XtWindowOfObject(widgetParent);
XMapEvent ev;
ev.type = ClientMessage;
if (XSendEvent (display, tmpWin, True, 0L, (XEvent*) &ev))
{
printf ("Ich war es !\n");
fflush(stdout);
}
}



Folgende Methode ist mit dem XSendEvent verknüpft:
static void focusIn(Widget wid, XtPointer unsused ,XMapEvent *event, Boolean *cont)
{
printf ("Finger weg !\n");
fflush(stdout);
}



Wiefolgt regestriere ich den Handler in der main.c:
{
.....
widgetParent = XtVaAppInitialize(&app, "blockcolors", NULL, 0, &argc, argv, NULL, NULL);
EventMask mask = MapNotify;
Boolean nonmaskable = True;
XtEventHandler handler;
XtPointer clientData;
XtAddEventHandler(widgetParent, mask, nonmaskable, &focusIn, clientData );
..................
}


Folgende Ausgabe ich:
Ich war es !
Finger weg !
X Error of failed request: BadValue (integer parameter out of range for operation)
Major opcode of failed request: 25 (X_SendEvent)
Value in failed request: 0xff
Serial number of failed request: 204
Current serial number in output stream: 204



Was mache ich denn jetzt schon wieder Verkehrt?

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#6 Post by Janka »

Compilierbarer Quellcode (kleinstes Beispiel natürlich) würde es mir erlauben, ebenfalls nach dem Fehler zu suchen. So bleibt nur schätzen.

Ich vermute, du musst noch einige Felder im XEvent-Feld ausfüllen. Da du dich für einen XClientMessageEvent entschieden hast, vermutlich zumindest das "format"-Feld.

$ man XClientMessageEvent

Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

grisu1972
Posts: 16
Joined: 22. Jul 2008 11:03

#7 Post by grisu1972 »

Ich komme nicht weiter, hier die komprimierte Quelle:
Wäre toll wenn du einen Blick darauf werfen könntest!




#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

#include <pthread.h>
#include <sys/signal.h>
#include <X11/Intrinsic.h> /* Toolkit-Strukturen */
#include <X11/Xatom.h>
#include <X11/StringDefs.h> /* Toolkit-Konstanten, z.B. fuer Ressourcen */
#include <X11/Xaw/Command.h> /* Command-Widget des Athena Sets */
#include <X11/Xaw/Box.h> /* Command-Widget des Athena Sets */
#include <X11/Xaw/Dialog.h> /* Command-Widget des Athena Sets */

#include <X11/X.h>
#include <X11/Xatom.h>

#define MAX_NUM_COLORS 100000

Display *display;

typedef struct tagInstallColormapThreadData
{
Display *display;
Colormap colormap;
int numTries;
} installColormapThreadData;


const unsigned int installColormapPauseSeconds = 2;


XtAppContext app;
Widget widgetNumQueryColors, widgetFirstQueryColors, widgetShowColors, widgetListVisuals,
widgetAllocColors, widgetGlobalBox, widgetParent, widgetQuit, widgetShowColorsBox,
widgetNumAllocColors, widgetAllocCOlorsBox, widgetListColormaps, widgetInstallColormap,
widgetInstallColormapBox, widgetStopInstallColormap, widgetScreenNum, widgetShowBasicData,
widgetNumInstallColormaps;
static XColor colors[MAX_NUM_COLORS]; /* doesn't work if automatic */

installColormapThreadData threadData;
pthread_t threadInstallColormapId;
pthread_mutex_t threadMutex;
pthread_mutex_t stopThreadMutex;

// chermanns
void receiveSIGUSR2(int sig)
{
Window tmpWin = XtWindowOfObject(widgetParent);
XMapEvent ev;
ev.type = ClientMessage;

if (XSendEvent (display, tmpWin, True, 0L, (XEvent*) &ev))
{
printf ("Ich war es !\n");
fflush(stdout);

}

}


static void focusIn(Widget wid, XtPointer unsused ,XMapEvent *event, Boolean *cont)
{

printf ("Finger weg !\n");
fflush(stdout);

if (event->send_event == True)
{
printf ("Das meine ich ernst!\n");
fflush(stdout);

Window tmpWin = XtWindowOfObject(widgetParent);


printf ("SIGUSR2 window: %ld !\n", tmpWin);
printf ("SIGUSR2 display: %ld !\n", display);

XMapWindow(display, tmpWin);
XMapRaised(display, tmpWin);
XFlush(display);

printf ("XMapRaised!\n");
XWindowChanges werte;
werte.stack_mode = Above;
XReconfigureWMWindow(display, tmpWin, DefaultScreen(display), CWStackMode, &werte);
XFlush(display);
}

}





/**
* Main function
*
* Makes the widgets, puts them into their hierarchy and calls the main
* event loop of Xt XtAppMainLoop.
*
* @param argc argument counter
* @param argv[] argument values
* @return would be EXIT_SUCCESS if reached
*/
int main(int argc, char *argv[])
{
//Display *display = NULL;
display = NULL;
char screenNumDefault[100];

// chermanns
(void) signal (SIGUSR2, receiveSIGUSR2);

widgetParent = XtVaAppInitialize(&app, "blockcolors", NULL, 0, &argc, argv, NULL, NULL);
display = XtDisplay(widgetParent )
// Aufzurufende Funktion
EventMask mask = MapNotify;
Boolean nonmaskable = True;
XtEventHandler handler;
XtPointer clientData;
XtAddEventHandler(widgetParent, mask, nonmaskable, &focusIn, clientData );


XtVaSetValues(widgetParent, XtNwidth, (XtArgVal)400, XtNheight, (XtArgVal)450, NULL);
XtRealizeWidget(widgetParent);
XtAppMainLoop(app);

return EXIT_SUCCESS;
}

Habe eine Zeile mit weggelöscht, die natürlich wichtig ist! -> die fett gedruckte!

grisu1972
Posts: 16
Joined: 22. Jul 2008 11:03

#8 Post by grisu1972 »

Hallo Janka,

ich bin ein Stück weiter gekommen habe aber das Problem, dass das Event in der EventSchlange verschwindet und erst abgearbeitet wird wenn z.B. mit der Maus über mein Widget gefahren wird:

Es bleibt also in der queue stecken bis ein anderes Event abgearbeitet wird!

Hst du einen Tip?

Hier der Sourcecode:



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

#include <pthread.h>
#include <sys/signal.h>
#include <X11/Intrinsic.h> /* Toolkit-Strukturen */
#include <X11/Xatom.h>
#include <X11/StringDefs.h> /* Toolkit-Konstanten, z.B. fuer Ressourcen */
#include <X11/Xaw/Command.h> /* Command-Widget des Athena Sets */
#include <X11/Xaw/Box.h> /* Command-Widget des Athena Sets */
#include <X11/Xaw/Dialog.h> /* Command-Widget des Athena Sets */

#include <X11/X.h>
#include <X11/Xatom.h>

#define MAX_NUM_COLORS 100000

Display *display;

typedef struct tagInstallColormapThreadData
{
Display *display;
Colormap colormap;
int numTries;
} installColormapThreadData;


const unsigned int installColormapPauseSeconds = 2;


XtAppContext app;
Widget widgetNumQueryColors, widgetFirstQueryColors, widgetShowColors, widgetListVisuals,
widgetAllocColors, widgetGlobalBox, widgetParent, widgetQuit, widgetShowColorsBox,
widgetNumAllocColors, widgetAllocCOlorsBox, widgetListColormaps, widgetInstallColormap,
widgetInstallColormapBox, widgetStopInstallColormap, widgetScreenNum, widgetShowBasicData,
widgetNumInstallColormaps;
static XColor colors[MAX_NUM_COLORS]; /* doesn't work if automatic */

installColormapThreadData threadData;
pthread_t threadInstallColormapId;
pthread_mutex_t threadMutex;
pthread_mutex_t stopThreadMutex;

// chermanns
void receiveSIGUSR2(int sig)
{

//printf ("Habe SIGUSR2 empfangen!\n");
//fflush(stdout);

Window tmpWin = XtWindowOfObject(widgetParent);

//ev.type = ClientMessage;
XMapEvent ev;
ev.type = ClientMessage;
ev.serial =0;
ev.display = tmpWin;
ev.event= display;
ev.send_event = True;




XEvent xev;
memset (&xev,0,sizeof(xev));
xev.xclient.type = ClientMessage;
xev.xclient.serial =0;
xev.xclient.send_event = False;
xev.xclient.format = 32;
xev.xclient.message_type =MapNotify;
xev.xclient.display = display;
xev.xclient.window= tmpWin;
xev.xclient.data.l[0]= 0;



//if (XSendEvent (display, tmpWin, True, 0L, (XEvent*) &ev) != 0)

if (XSendEvent (display, tmpWin, False, 0L, &xev) != 0)
{
printf ("Ich war es !\n");
fflush(stdout);

}
else
{
printf ("ups: Fehler bei XSendEvent!\n");
fflush(stdout);

}

}


static void focusIn(Widget wid, XtPointer unsused ,XMapEvent *event, Boolean *cont)
{

printf ("Finger weg !\n");
fflush(stdout);



if (event->send_event == True)
{
printf ("Das meine ich ernst!\n");
fflush(stdout);
Window tmpWin = XtWindowOfObject(widgetParent);

printf ("SIGUSR2 window: %ld !\n", tmpWin);
printf ("SIGUSR2 display: %ld !\n", display);

XMapWindow(display, tmpWin);
XMapRaised(display, tmpWin);
XFlush(display);

printf ("XMapRaised!\n");
XWindowChanges werte;
werte.stack_mode = Above;
//XReconfigureWMWindow(display, tmpWin, DefaultScreen(display), CWStackMode, &werte);
//XFlush(display);
}

}





/**
* Main function
*
* Makes the widgets, puts them into their hierarchy and calls the main
* event loop of Xt XtAppMainLoop.
*
* @param argc argument counter
* @param argv[] argument values
* @return would be EXIT_SUCCESS if reached
*/
int main(int argc, char *argv[])
{
//Display *display = NULL;
display = NULL;
char screenNumDefault[100];
// chermanns
(void) signal (SIGUSR2, receiveSIGUSR2);

widgetParent = XtVaAppInitialize(&app, "blockcolors", NULL, 0, &argc, argv, NULL, NULL);
display = XtDisplay(widgetParent);
printf ("display: %ld !\n", display);

// Aufzurufende Funktion
EventMask mask = MapNotify;
Boolean nonmaskable = True;
XtEventHandler handler;
XtPointer clientData;
XtAddEventHandler(widgetParent, mask, ClientMessage, (XtEventHandler)focusIn, clientData );

XtVaSetValues(widgetParent, XtNwidth, (XtArgVal)400, XtNheight, (XtArgVal)450, NULL);
XtRealizeWidget(widgetParent);

XtAppMainLoop(app);

return EXIT_SUCCESS;
}

grisu1972
Posts: 16
Joined: 22. Jul 2008 11:03

#9 Post by grisu1972 »

Ich habe es!!!!!!!!

XFlush(display); // Immer die Spülung betätigen!!!! :-)


Quellcode:

if (XSendEvent (display, tmpWin, False, 0L, &xev) != 0)
{
printf ("Ich war es !\n");
fflush(stdout);
XFlush(display);


}
else
{
printf ("ups: Fehler bei XSendEvent!\n");
fflush(stdout);

}




Danke für die Hilfe und Grüsse an Janka
Carsten

Post Reply