tarina

git clone https://git.tarina.org/tarina
Log | Files | Refs | README | LICENSE

card_select.c (5786B)


      1 /*
      2  * card_select.c - select a card by list or device name
      3  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
      4  *
      5  * This program is free software: you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation, either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include "aconfig.h"
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <assert.h>
     23 #include <alsa/asoundlib.h>
     24 #include <menu.h>
     25 #include "gettext_curses.h"
     26 #include "die.h"
     27 #include "mem.h"
     28 #include "utils.h"
     29 #include "colors.h"
     30 #include "widget.h"
     31 #include "mixer_widget.h"
     32 #include "device_name.h"
     33 #include "card_select.h"
     34 
     35 struct card {
     36 	struct card *next;
     37 	char *indexstr;
     38 	char *name;
     39 	char *device_name;
     40 };
     41 
     42 static struct widget list_widget;
     43 static struct card first_card;
     44 static ITEM **items;
     45 static MENU *menu;
     46 static ITEM *initial_item;
     47 
     48 static void on_key_enter(void)
     49 {
     50 	ITEM *item = current_item(menu);
     51 	if (item) {
     52 		struct card *card = item_userptr(item);
     53 		if (card->device_name) {
     54 			if (select_card_by_name(card->device_name))
     55 				list_widget.close();
     56 		} else {
     57 			create_device_name_form();
     58 		}
     59 	}
     60 }
     61 
     62 static void on_menu_key(int key)
     63 {
     64 	static const struct {
     65 		int key;
     66 		int request;
     67 	} key_map[] = {
     68 		{ KEY_DOWN, REQ_DOWN_ITEM },
     69 		{ KEY_UP, REQ_UP_ITEM },
     70 		{ KEY_HOME, REQ_FIRST_ITEM },
     71 		{ KEY_NPAGE, REQ_SCR_DPAGE },
     72 		{ KEY_PPAGE, REQ_SCR_UPAGE },
     73 		{ KEY_BEG, REQ_FIRST_ITEM },
     74 		{ KEY_END, REQ_LAST_ITEM },
     75 	};
     76 	unsigned int i;
     77 
     78 	for (i = 0; i < ARRAY_SIZE(key_map); ++i)
     79 		if (key_map[i].key == key) {
     80 			menu_driver(menu, key_map[i].request);
     81 			break;
     82 		}
     83 }
     84 
     85 static void on_handle_key(int key)
     86 {
     87 	switch (key) {
     88 	case 27:
     89 	case KEY_CANCEL:
     90 	case 'q':
     91 	case 'Q':
     92 		list_widget.close();
     93 		break;
     94 	case 10:
     95 	case 13:
     96 	case KEY_ENTER:
     97 		on_key_enter();
     98 		break;
     99 	default:
    100 		on_menu_key(key);
    101 		break;
    102 	}
    103 }
    104 
    105 static bool create(void)
    106 {
    107 	int rows, columns;
    108 	const char *title;
    109 
    110 	if (screen_lines < 3 || screen_cols < 10) {
    111 		beep();
    112 		list_widget.close();
    113 		return FALSE;
    114 	}
    115 	scale_menu(menu, &rows, &columns);
    116 	rows += 2;
    117 	columns += 2;
    118 	if (rows > screen_lines)
    119 		rows = screen_lines;
    120 	if (columns > screen_cols)
    121 		columns = screen_cols;
    122 
    123 	widget_init(&list_widget, rows, columns, SCREEN_CENTER, SCREEN_CENTER,
    124 		    attr_menu, WIDGET_BORDER | WIDGET_SUBWINDOW);
    125 
    126 	title = _("Sound Card");
    127 	mvwprintw(list_widget.window, 0, (columns - 2 - get_mbs_width(title)) / 2, " %s ", title);
    128 	set_menu_win(menu, list_widget.window);
    129 	set_menu_sub(menu, list_widget.subwindow);
    130 	return TRUE;
    131 }
    132 
    133 static void on_window_size_changed(void)
    134 {
    135 	unpost_menu(menu);
    136 	if (!create())
    137 		return;
    138 	post_menu(menu);
    139 }
    140 
    141 static void on_close(void)
    142 {
    143 	unsigned int i;
    144 	struct card *card, *next_card;
    145 
    146 	unpost_menu(menu);
    147 	free_menu(menu);
    148 	for (i = 0; items[i]; ++i)
    149 		free_item(items[i]);
    150 	free(items);
    151 	for (card = first_card.next; card; card = next_card) {
    152 		next_card = card->next;
    153 		free(card->indexstr);
    154 		free(card->name);
    155 		free(card->device_name);
    156 		free(card);
    157 	}
    158 	widget_free(&list_widget);
    159 }
    160 
    161 void close_card_select_list(void)
    162 {
    163 	on_close();
    164 }
    165 
    166 static struct widget list_widget = {
    167 	.handle_key = on_handle_key,
    168 	.window_size_changed = on_window_size_changed,
    169 	.close = on_close,
    170 };
    171 
    172 static int get_cards(void)
    173 {
    174 	int count, number, err;
    175 	snd_ctl_t *ctl;
    176 	snd_ctl_card_info_t *info;
    177 	char buf[16];
    178 	struct card *card, *prev_card;
    179 
    180 	first_card.indexstr = "-";
    181 	first_card.name = _("(default)");
    182 	first_card.device_name = "default";
    183 	count = 1;
    184 
    185 	snd_ctl_card_info_alloca(&info);
    186 	prev_card = &first_card;
    187 	number = -1;
    188 	for (;;) {
    189 		err = snd_card_next(&number);
    190 		if (err < 0)
    191 			fatal_alsa_error(_("cannot enumerate sound cards"), err);
    192 		if (number < 0)
    193 			break;
    194 		sprintf(buf, "hw:%d", number);
    195 		err = snd_ctl_open(&ctl, buf, 0);
    196 		if (err < 0)
    197 			continue;
    198 		err = snd_ctl_card_info(ctl, info);
    199 		snd_ctl_close(ctl);
    200 		if (err < 0)
    201 			continue;
    202 		card = ccalloc(1, sizeof *card);
    203 		sprintf(buf, "%d", number);
    204 		card->indexstr = cstrdup(buf);
    205 		card->name = cstrdup(snd_ctl_card_info_get_name(info));
    206 		sprintf(buf, "hw:%d", number);
    207 		card->device_name = cstrdup(buf);
    208 		prev_card->next = card;
    209 		prev_card = card;
    210 		++count;
    211 	}
    212 
    213 	card = ccalloc(1, sizeof *card);
    214 	card->indexstr = cstrdup(" ");
    215 	card->name = cstrdup(_("enter device name..."));
    216 	prev_card->next = card;
    217 	++count;
    218 
    219 	return count;
    220 }
    221 
    222 static void create_list_items(int cards)
    223 {
    224 	int i;
    225 	struct card *card;
    226 	ITEM *item;
    227 
    228 	initial_item = NULL;
    229 	items = ccalloc(cards + 1, sizeof(ITEM*));
    230 	i = 0;
    231 	for (card = &first_card; card; card = card->next) {
    232 		item = new_item(card->indexstr, card->name);
    233 		if (!item)
    234 			fatal_error("cannot create menu item");
    235 		set_item_userptr(item, card);
    236 		items[i++] = item;
    237 		if (!initial_item &&
    238 		    mixer_device_name &&
    239 		    (!card->device_name ||
    240 		     !strcmp(card->device_name, mixer_device_name)))
    241 			initial_item = item;
    242 	}
    243 	assert(i == cards);
    244 }
    245 
    246 void create_card_select_list(void)
    247 {
    248 	int cards;
    249 
    250 	cards = get_cards();
    251 	create_list_items(cards);
    252 
    253 	menu = new_menu(items);
    254 	if (!menu)
    255 		fatal_error("cannot create menu");
    256 	set_menu_fore(menu, attr_menu_selected);
    257 	set_menu_back(menu, attr_menu);
    258 	set_menu_mark(menu, NULL);
    259 	if (initial_item)
    260 		set_current_item(menu, initial_item);
    261 	set_menu_spacing(menu, 2, 1, 1);
    262 	menu_opts_on(menu, O_SHOWDESC);
    263 
    264 	if (!create())
    265 		return;
    266 
    267 	post_menu(menu);
    268 }