unix 如何使Motif Push Button小工具显示为永久按下?

bz4sfanl  于 2023-01-08  发布在  Unix
关注(0)|答案(1)|浏览(112)

我在FreeBSD中编写了一个简单的工具来选择音频通道。
这是密码:
xaudio.c

#include <Xm/Xm.h>
#include <Xm/PushB.h>
#include <Xm/MainW.h>
#include <Xm/RowColumn.h>

#include <stdio.h>
#include <stdlib.h>

#include "devices.h"

struct button_data {
   int device_num;
   Widget button;
};

/* GLOBAL VARIABLES */
int num_devices;
struct device *devices;
struct button_data *buttons;

void button_callback(Widget widget, XtPointer client_data, XtPointer call_data);
void create_device_buttons(Widget parent, struct device *devices, int num_devices);

void button_callback(Widget widget, XtPointer client_data, XtPointer call_data) {
   int i;
   struct button_data *data = (struct button_data *)client_data;
   int device_num = data->device_num;

   // unclick all other buttons
   for (i = 0; i < num_devices; i++) {
      if (buttons[i].button != widget) {
         XtVaSetValues(buttons[i].button, XmNset, False, NULL);
      }
   }

   // click this button
   XtVaSetValues(widget, XmNset, True, NULL);
   
   // set audio device
   set_audio_device(device_num);
}

void create_device_buttons(Widget parent, struct device *devices, int num_devices) {
   int i;
   XmString label;
   struct button_data *data;
   Arg args[5];
   int n;

   buttons = malloc(num_devices * sizeof(struct button_data));
   if (buttons == NULL) {
      perror("Failed to allocate memory");
      exit(EXIT_FAILURE);
   }

   for (i = 0; i < num_devices; i++) {
      // create button
      n = 0;
      label = XmStringCreateLocalized(devices[i].description);
      XtSetArg(args[n], XmNlabelString, label); n++;
      buttons[i].button = XmCreatePushButton(parent, "device_button", args, n);
      XmStringFree(label);
      XtManageChild(buttons[i].button);

      // set button data
      buttons[i].device_num = devices[i].number;

      // set button callback
      XtAddCallback(buttons[i].button, XmNactivateCallback, button_callback, &buttons[i]);
   }
}

int main(int argc, char *argv[]) {
   XtAppContext app;
   Widget top_level, main_window, button_rowcolumn;
   int default_device;

   int n=0;
   Arg args[10];

   top_level = XtVaOpenApplication(&app, "XAudio", NULL, 0, &argc, argv, NULL, sessionShellWidgetClass, NULL);
   main_window = XmCreateMainWindow(top_level, "main_window", NULL, 0);
   XtManageChild(main_window);
   n=0;
   XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
   button_rowcolumn = XmCreateRowColumn(main_window, "button_rowcolumn", args, n);    
   XtManageChild(button_rowcolumn);

   /* GET LIST OF DEVICES AND DEFAULT DEVICE */
   default_device = get_default_device(&devices, &num_devices);

   int i=0;
   for(i=0; i<num_devices; i++) {
        printf("%d %s\n", devices[i].number, devices[i].description);
  }

   create_device_buttons(button_rowcolumn, devices, num_devices);
   
   XtRealizeWidget(top_level);
   
   /* CLICK DEFAULT BUTTON */
   if (default_device >= 0) {
      XtVaSetValues(buttons[default_device].button, XmNset, True, NULL);
   }

   XtAppMainLoop(app);
   
   free(devices);
   free(buttons);
   
   return 0;
}

装置c:

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

struct device {
   int number;
   char description[256];
};

void set_audio_device(int device_num) {
   char command[256];
   sprintf(command, "sysctl hw.snd.default_unit=%d", device_num);
   system(command);
}

int get_default_device(struct device **devices, int *num_devices) {
   FILE *fp;
   char *line = NULL;
   size_t len = 0;
   ssize_t read;
   int num_dev = 0;
   int default_device = -1;

   fp = popen("cat /dev/sndstat", "r");
   if (fp == NULL) {
      perror("Failed to run command");
      exit(EXIT_FAILURE);
   }

   while ((read = getline(&line, &len, fp)) != -1) {
      if (strstr(line, "pcm") == line) {
         // line starts with "pcm", so it is a device line
         // increase number of devices and reallocate memory
         num_dev++;
         *devices = realloc(*devices, num_dev * sizeof(struct device));
         if (*devices == NULL) {
            perror("Failed to allocate memory");
            exit(EXIT_FAILURE);
         }

         // get device number
         sscanf(line, "pcm%d:", &(*devices)[num_dev - 1].number);

         // get description
         char *start = strchr(line, '<');
         char *end = strchr(line, '>');
         if (start != NULL && end != NULL) {
            int length = end - start - 1;
            strncpy((*devices)[num_dev - 1].description, start + 1, length);
            (*devices)[num_dev - 1].description[length] = '\0';
         }

         // check if this is the default device
         if (strstr(line, "default") != NULL) {
            default_device = num_dev - 1;
         }
      }
   }

   *num_devices = num_dev;
   pclose(fp);
   return default_device;
}

设备. h:

#ifndef DEVICES_H
#define DEVICES_H

#include <stdio.h>
#include <stdlib.h>

struct device {
   int number;
   char description[256];
};

void set_audio_device(int device_num);
int get_default_device(struct device **devices, int *num_devices);

#endif

以及相应的makefile(对于FreeBSD):

CC = cc
CFLAGS = -Wall -Wextra -I/usr/local/include
LDFLAGS = -Wall -Wextra -L/usr/local/lib -lXm -lXt -lX11 

all: xaudio

xaudio: xaudio.o devices.o
        $(CC) $(LDFLAGS) -o $@ xaudio.o devices.o

xaudio.o: xaudio.c devices.h
        $(CC) $(CFLAGS) -c -o $@ $<

devices.o: devices.c devices.h
        $(CC) $(CFLAGS) -c -o $@ $<

clean:
        rm -f *.o xaudio

程序编译并工作(它按预期切换音频频道)。然而,我的预期行为是所选频道显示为永久按下的按钮,而当选择新频道时,按下的按钮会相应地改变。有点像"可选按钮集"。
据我所知,此类行为是通过以下小部件参数实现的:

XtVaSetValues(buttons[default_device].button, XmNset, True, NULL);

然而,正如这里所看到的,这并没有发生,除了正常的动态点击效果时,按下按钮显示总是未点击。

64jmpszr

64jmpszr1#

你所描述的期望行为就是“单选按钮”的用途。在Motif中,我相信你需要XmCreateRadioBox函数。

相关问题