1

I want a Motif application to redraw a Drawing Area widget on reception of SIGUSR1 signal.

I have configured the signal using the Xt functionalities in X11R6:

/* CONFIGURE READ SIGNAL, TRAPS SIGUSR1 TO FORCE APPLICATION READ DATA FILE */
signal(SIGUSR1, signal_usr1_handler);
signal_id = XtAppAddSignal (app, read_data, (XtPointer)chart_area);

Where signal_usr1_handler is the OS Unix handler and read_data is the Xt signal handler.

For the Xt signal handler I am trying to pass the widget chart_area which is a Drawing Area Widget.

These are the handlers:

/* SIGNAL HANDLER */
void signal_usr1_handler() {
    printf("SIGUSR1 RECEIVED\n");
    XtNoticeSignal(signal_id);
}
    
/* READ DATA XT SIGNAL HANDLER */
void read_data(XtPointer client_data, XtSignalId *id) {

    posx += 5;
    printf("XT HANDLES SIGUSR1\n"); 
    
    XmDrawingAreaCallbackStruct da_struct;

    da_struct.reason = XmCR_EXPOSE;
    da_struct.event = (XEvent *) NULL;
    da_struct.window = XtWindow((Widget)client_data);

    XtCallCallbacks((Widget)client_data, XmNexposeCallback, (XtPointer) &da_struct);
    
}

The application raises a Segmentation fault (core dumped) exactly when executing the XtCallCallbacks function.

This is the complete source code:

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
 
#include <Xm/Xm.h>
#include <Xm/DrawingA.h>
#include <Xm/Label.h>

/* FUNCTION DECLARATIONS */
void draw_chart(Widget widget, XtPointer client_data, XtPointer call_data);
void signal_usr1_handler();
void read_data(XtPointer client_data, XtSignalId *id);

/* XT SIGNAL ID */
XtSignalId  signal_id;      /* Signal ID used to receive data read via SIGUSR1 */
     
int main(int argc, char *argv[]) {

    /* WIDGETS */
    XtAppContext    app;            /* Application Context */
    Widget      toplevel;       /* Top Level Button */
    Widget      chart_area;     /* Drawing Area Widget to draw the chart */
        
    /* DRAWING AREA RELATED */
    XGCValues   gcv;
    GC      gc;
    
    /* RESOURCE VALUE ARRAYS/COUNT */
    Arg al[10];
    int ac;
    
    /* INITIALIZE TOP LEVEL WINDOW */
    XtSetLanguageProc(NULL, NULL, NULL);
    toplevel = XtVaOpenApplication( 
        &app, argv[0], NULL, 0, &argc, argv, NULL, sessionShellWidgetClass,
        XmNwidth, 400, XmNheight, 300, NULL
    );
    
    /* CREATE AND MANAGE DRAWING CANVAS WIDGET */
    ac=0; 
    chart_area = XmCreateDrawingArea(toplevel, "chart_area", al, ac);
                
    /* CREATE GRAPHICS CONTEXT */
    gcv.foreground = WhitePixelOfScreen(XtScreen(chart_area));
    gcv.background = BlackPixelOfScreen(XtScreen(chart_area));  
    gc = XCreateGC (
        XtDisplay(chart_area),
        RootWindowOfScreen(XtScreen(chart_area)), 
        (GCForeground | GCBackground), 
        &gcv);

    /* ASSIGN GRAPHICS CONTEXT */   
    XtVaSetValues(chart_area, XmNuserData, gc, NULL);   
    
    /* ASSIGN CALLBACKS AND MANAGE WIDGET */
    XtAddCallback(chart_area, XmNexposeCallback, draw_chart, NULL);
    XtManageChild(chart_area);  
                    
    /* CONFIGURE READ SIGNAL, TRAPS SIGUSR1 TO FORCE APPLICATION READ DATA FILE */
    signal(SIGUSR1, signal_usr1_handler);
    signal_id = XtAppAddSignal (app, read_data, (XtPointer)chart_area);
        
    /* REALIZE TOPLEVEL WINDOW AND LAUNCH APPLICATION LOOP */
    XtRealizeWidget(toplevel);  
    XtAppMainLoop(app);
    
    return 0;

}

void draw_chart(Widget widget, XtPointer client_data, XtPointer call_data) {

    XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *) call_data;
    XEvent *event = cbs->event;
    Display *dpy = event->xany.display;
    GC gc;
    
    /* DRAW LINE */
    if(cbs->reason == XmCR_EXPOSE || cbs->reason == XmCR_ACTIVATE) {

        XtVaGetValues(widget, XmNuserData, &gc, NULL);
        XDrawLine(dpy, cbs->window, gc, 10, 10, posx, 200);

    }
}
    
/* SIGNAL HANDLER */
void signal_usr1_handler() {
    printf("SIGUSR1 RECEIVED\n");
    XtNoticeSignal(signal_id);
}
    
/* READ DATA XT SIGNAL HANDLER */
void read_data(XtPointer client_data, XtSignalId *id) {

    /* ... READ DATA AND PROCESSING GOES HERE ... */

    posx += 5;
    printf("XT HANDLES SIGUSR1\n"); 
    
    XmDrawingAreaCallbackStruct da_struct;

    da_struct.reason = XmCR_EXPOSE;
    da_struct.event = (XEvent *) NULL;
    da_struct.window = XtWindow((Widget)client_data);

    /* XtCallCallbacks((Widget)client_data, XmNexposeCallback, (XtPointer) &da_struct); */
    
}
M.E.
  • 4,955
  • 4
  • 49
  • 128

1 Answers1

1

The following causes the crash:

Display *dpy = event->xany.display;

Because event was set to NULL.

Also you may need to deal with gc by passing its address and receiving XmUserData as

GC *gc;

then using *gc,

PaulB
  • 357
  • 2
  • 2
  • What shall I use as event then? BTW, the code excerpt is taken from the Motif FAQ (https://babbage.cs.qc.cuny.edu/courses/GUIDesign/motif-faq.html#160) – M.E. Jul 18 '21 at 19:20
  • 1
    If you want the Display pointer use XtDisplay((Widget)client_data); – PaulB Jul 19 '21 at 02:36
  • My understanding from your answer is that in the FAQ example, where `NULL` is assigned to the `event` member of `XmDrawingAreaCallbackStruct`, the application crashes as the display is taken from that `event`. So `event` shall be properly assigned. Could you please further elaborate the code before invoking `XtCallCallbacks`?, How do I populate `event`? It is not straightforward or obvious to me what to do. – M.E. Jul 19 '21 at 04:18
  • I am also wondering why is that solution part of the FAQ. – M.E. Jul 19 '21 at 04:21
  • Note: the answer refers to what it is written in `draw_chart` function used to redraw the area. – M.E. Jul 22 '21 at 00:01