我在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);
然而,正如这里所看到的,这并没有发生,除了正常的动态点击效果时,按下按钮显示总是未点击。
1条答案
按热度按时间64jmpszr1#
你所描述的期望行为就是“单选按钮”的用途。在Motif中,我相信你需要XmCreateRadioBox函数。