尝试将文本附加到 Xm 文本小部件时出现多线程或 Motif 小部件问题

Multithread or Motif widget issue while trying to append text to a Xm Text Widget

我正在尝试将 TextWidget 用作日志,其中以编程方式添加了文本。 通过使用 XmTextInsertXtVaSetValuesXmTextShowPosition 我可以将文本附加到文本小部件,但是我注意到只有当小部件具有焦点或滚动鼠标时文本才会更新指向文本小部件区域的指针。否则,Widget 似乎只更新了大约 5/6 秒,所以你看到一次出现几行。

我无法确定它是与 Motif 相关的问题还是纯粹的 X11/Xt/Xm 多线程问题,但显然附加的代码缺少相关内容。

例如,此源代码只有 TextWidget,并且更新工作正常,即使焦点在另一个应用程序中,每秒您都会看到一个新的 TEST 词添加到 Text Widget:

#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void displayMessage(char *textLineBuffer);
void createWindow(int argc, char *argv[]);
void *logText(void *arg);

/* X11 RELATED VARIABLES */
XtAppContext    context;

Widget          toplevel;
Widget          busForm;
Widget          textWidget;
pthread_mutex_t textWidgetMutex;
long            textWidgetLength = 0;

int main(int argc, char *argv[]) {

        pthread_t       thread;

        /* INITIALIZE MULTITHREAD X11 ENVIRONMENT */
        XInitThreads();

        /* CREATE X WINDOW */
        createWindow(argc, argv);

        /* GET NEW THREAD TO PROCESS QUEUES */
        /* PARENTS HANDLES X11 */
        pthread_create(&thread, NULL, logText, NULL);

        /* BEGIN X11 APPLICATION */
        XtAppMainLoop(context);

}

void *logText(void *arg) {

        /* READ CLIENT QUEUE MESSAGES */
        while(1) {
                sleep(1);
                displayMessage("TEST\n");
        }

}

void createWindow(int argc, char *argv[]){

        Arg             al[10];
        int             ac;
        XmStringCharSet char_set = XmSTRING_DEFAULT_CHARSET;
        char            pidString[50];

        /* CREATE TOP LEVEL */
        sprintf(pidString, "Bus Client %d", getpid());
        toplevel = XtAppInitialize(&context, pidString, NULL, 0, &argc, argv, NULL, NULL, 0);

        /* RESIZE TOP LEVEL */
        ac = 0;
        XtSetArg(al[ac], XmNwidth, 300); ac++;
        XtSetArg(al[ac], XmNheight, 300); ac++;
        XtSetValues(toplevel, al, ac);

        /* CREATE TOP LEVEL FORM MANAGER */
        ac = 0;
        busForm  = XmCreateForm(toplevel, "busForm", al, ac);
        XtManageChild(busForm);

        /* CREATE TEXT WIDGET */
        ac = 0;
        XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
        XtSetArg(al[ac], XmNscrollingPolicy, XmVARIABLE); ac++;
        XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmSTATIC); ac++;
        XtSetArg(al[ac], XmNscrollHorizontal, FALSE); ac++;
        XtSetArg(al[ac], XmNeditable, FALSE); ac++;
        textWidget = XmCreateScrolledText(busForm, "textWidget", al, ac);
        XtManageChild(textWidget);

        /* DISPLAY TOP LEVEL */
        XtRealizeWidget(toplevel);
}

void displayMessage(char *textLineBuffer) {
        pthread_mutex_lock(&textWidgetMutex);
        XmTextInsert(textWidget, textWidgetLength, textLineBuffer); 
        textWidgetLength += strlen(textLineBuffer);
        XtVaSetValues(textWidget, XmNcursorPosition, textWidgetLength, NULL);
        XmTextShowPosition(textWidget, textWidgetLength);
        pthread_mutex_unlock(&textWidgetMutex);
}

如输出所示,即使 windows 没有焦点,消息也会不断显示:

但是,如果您添加一个按钮,当 Motif 应用程序中的焦点位于 Button Widget 中时,文本不会更新,直到鼠标滑过 Text Widget。如果您单击“文本小部件”,文本会像前面的示例一样不断更新。

这是源代码和对应的例子。

#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <Xm/PushB.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <pthread.h>
#include <unistd.h>

void displayMessage(char *textLineBuffer);
void createWindow(int argc, char *argv[]);
void sendButtonCB(Widget w, XtPointer  client_data, XtPointer call_data);
void *logText(void *arg);

/* X11 RELATED VARIABLES */
XtAppContext    context;

Widget          toplevel;
Widget          busForm;
Widget          textWidget;
Widget          registerButton;
Widget          sendButton;
pthread_mutex_t textWidgetMutex;
long            textWidgetLength = 0;

/* BUS CLIENT SYS V QUEUE VARIABLES */
int client_queue_id;
key_t client_queue_key;
int client_message_id;

int main(int argc, char *argv[]) {

        pthread_t       thread;

        /* INITIALIZE MULTITHREAD X11 ENVIRONMENT */
        XInitThreads();

        /* CREATE X WINDOW */
        createWindow(argc, argv);

        /* GET NEW THREAD TO PROCESS QUEUES */
        /* PARENTS HANDLES X11 */
        pthread_create(&thread, NULL, logText, NULL);

        /* BEGIN X11 APPLICATION */
        XtAppMainLoop(context);

}

void *logText(void *arg) {

        /* READ CLIENT QUEUE MESSAGES */
        while(1) {
                sleep(1);
                displayMessage("TEST\n");
        }

}

void createWindow(int argc, char *argv[]){

        Arg             al[10];
        int             ac;
        XmStringCharSet char_set = XmSTRING_DEFAULT_CHARSET;
        char            pidString[50];

        /* CREATE TOP LEVEL */
        sprintf(pidString, "Bus Client %d", getpid());
        toplevel = XtAppInitialize(&context, pidString, NULL, 0, &argc, argv, NULL, NULL, 0);

        /* RESIZE TOP LEVEL */
        ac = 0;
        XtSetArg(al[ac], XmNwidth, 300); ac++;
        XtSetArg(al[ac], XmNheight, 300); ac++;
        XtSetValues(toplevel, al, ac);

        /* CREATE TOP LEVEL FORM MANAGER */
        ac = 0;
        busForm  = XmCreateForm(toplevel, "busForm", al, ac);
        XtManageChild(busForm);

        /* CREATE SEND BUTTON WIDGET */
        ac = 0;
        XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
        XtSetArg(al[ac], XmNlabelString, XmStringCreateLtoR("Send", char_set)); ac++;
        sendButton = XmCreatePushButton(busForm, "sendButton", al, ac);
        XtManageChild(sendButton);
        XtAddCallback(sendButton, XmNactivateCallback, sendButtonCB, NULL); 

        /* CREATE TEXT WIDGET */
        ac = 0;
        XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
        XtSetArg(al[ac], XmNtopWidget, registerButton); ac++;
        XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
        XtSetArg(al[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
        XtSetArg(al[ac], XmNscrollingPolicy, XmVARIABLE); ac++;
        XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmSTATIC); ac++;
        XtSetArg(al[ac], XmNscrollHorizontal, FALSE); ac++;
        XtSetArg(al[ac], XmNeditable, FALSE); ac++;
        textWidget = XmCreateScrolledText(busForm, "textWidget", al, ac);
        XtManageChild(textWidget);

        /* DISPLAY TOP LEVEL */
        XtRealizeWidget(toplevel);
}

void displayMessage(char *textLineBuffer) {
        pthread_mutex_lock(&textWidgetMutex);
        XmTextInsert(textWidget, textWidgetLength, textLineBuffer); 
        textWidgetLength += strlen(textLineBuffer);
        XtVaSetValues(textWidget, XmNcursorPosition, textWidgetLength, NULL);
        XmTextShowPosition(textWidget, textWidgetLength);
        pthread_mutex_unlock(&textWidgetMutex);
}

我刚刚发现:

void displayMessage(char *textLineBuffer) {
        pthread_mutex_lock(&textWidgetMutex);
        XmTextInsert(textWidget, textWidgetLength, textLineBuffer); 
        textWidgetLength += strlen(textLineBuffer);
        XmUpdateDisplay(textWidget);
        pthread_mutex_unlock(&textWidgetMutex);
}

强制重绘小部件。