491 lines
18 KiB
C
491 lines
18 KiB
C
/*
|
|
* The key pad
|
|
*
|
|
* This file is part of ANT (Ant is Not a Telephone)
|
|
*
|
|
* Copyright 2002, 2003 Roland Stigge
|
|
*
|
|
* ANT is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* ANT is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with ANT; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
/* regular GNU system includes */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* GTK */
|
|
#include <gtk/gtk.h>
|
|
|
|
/* own header files */
|
|
#include "globals.h"
|
|
#include "session.h"
|
|
#include "isdn.h"
|
|
#include "util.h"
|
|
#include "callerid.h"
|
|
|
|
/* graphical symbols */
|
|
#include "backspace.xpm"
|
|
#include "redial.xpm"
|
|
#include "mute.xpm"
|
|
|
|
|
|
/*
|
|
* called on preset edit confirmation (OK button)
|
|
* -> sets new preset values (name, number) and destroys window
|
|
*
|
|
* input: widget = the OK button, set data:
|
|
* "entry_name" - the entry with the new preset name
|
|
* "entry_number" - the entry with the new preset number
|
|
* "button" - the preset button
|
|
* "number" - the preset button number
|
|
* "window" - the window to destroy after setting values
|
|
* data = the session
|
|
*/
|
|
static void controlpad_preset_edit_ok(GtkWidget *widget, gpointer *data) {
|
|
session_t *session = (session_t *) data;
|
|
GtkWidget *entry_name = gtk_object_get_data(GTK_OBJECT(widget),
|
|
"entry_name");
|
|
GtkWidget *entry_number = gtk_object_get_data(GTK_OBJECT(widget),
|
|
"entry_number");
|
|
GtkWidget *button = gtk_object_get_data(GTK_OBJECT(widget), "button");
|
|
int n = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(widget), "number"));
|
|
|
|
free(session->preset_names[n]);
|
|
session->preset_names[n] = strdup(gtk_entry_get_text(GTK_ENTRY(entry_name)));
|
|
free(session->preset_numbers[n]);
|
|
session->preset_numbers[n] = strdup(
|
|
gtk_entry_get_text(GTK_ENTRY(entry_number)));
|
|
gtk_label_set_text(GTK_LABEL(GTK_BIN(button)->child),
|
|
gtk_entry_get_text(GTK_ENTRY(entry_name)));
|
|
|
|
gtk_widget_destroy(gtk_object_get_data(GTK_OBJECT(widget), "window"));
|
|
}
|
|
|
|
/*
|
|
* called on right-click on preset button to configure
|
|
*
|
|
* input: widget = the preset button
|
|
* event = the event (we determine the clicked mouse button from it)
|
|
* data = the session
|
|
*/
|
|
static gint controlpad_preset_edit_cb(GtkWidget *widget, GdkEventButton *event,
|
|
gpointer data) {
|
|
if (event->button == 3) {
|
|
session_t *session = (session_t *) data;
|
|
char *buttoncode = (char *)gtk_object_get_data(GTK_OBJECT(widget), "desc");
|
|
int n = strtol(&buttoncode[1], NULL, 0);
|
|
GtkWidget *window;
|
|
GtkWidget *button_box;
|
|
GtkWidget *button;
|
|
GtkWidget *label;
|
|
GtkWidget *table;
|
|
GtkWidget *entry_name;
|
|
GtkWidget *entry_number;
|
|
char *title;
|
|
char *labeltext;
|
|
|
|
window = gtk_dialog_new();
|
|
asprintf(&title, _("Preset %c"), buttoncode[1] + 1);
|
|
gtk_window_set_title(GTK_WINDOW(window), title);
|
|
gtk_window_set_modal(GTK_WINDOW(window), TRUE);
|
|
|
|
/* vbox area */
|
|
gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(window)->vbox), 0);
|
|
asprintf(&labeltext,
|
|
_("Please input new preset data for button %c:"), buttoncode[1] + 1);
|
|
label = gtk_label_new(labeltext);
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), label,
|
|
TRUE, FALSE, 0);
|
|
gtk_misc_set_padding(GTK_MISC(label), 10, 10);
|
|
gtk_widget_show(label);
|
|
|
|
table = gtk_table_new(2, 2, FALSE);
|
|
gtk_container_set_border_width(GTK_CONTAINER(table), 10);
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), table,
|
|
TRUE, FALSE, 0);
|
|
gtk_widget_show(table);
|
|
|
|
label = gtk_label_new(_("Name:"));
|
|
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
|
|
gtk_widget_show(label);
|
|
label = gtk_label_new(_("Number:"));
|
|
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
|
|
gtk_widget_show(label);
|
|
|
|
entry_name = gtk_entry_new();
|
|
gtk_entry_set_text(GTK_ENTRY(entry_name), session->preset_names[n]);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), entry_name, 1, 2, 0, 1);
|
|
gtk_widget_show(entry_name);
|
|
entry_number = gtk_entry_new();
|
|
gtk_entry_set_text(GTK_ENTRY(entry_number), session->preset_numbers[n]);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), entry_number, 1, 2, 1, 2);
|
|
gtk_widget_show(entry_number);
|
|
|
|
/* action area */
|
|
button_box = gtk_hbutton_box_new();
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->action_area),
|
|
button_box);
|
|
gtk_widget_show(button_box);
|
|
|
|
/* OK button */
|
|
button = gtk_button_new_with_label(_("OK"));
|
|
gtk_box_pack_start_defaults(GTK_BOX(button_box), button);
|
|
gtk_object_set_data(GTK_OBJECT(button), "entry_name", entry_name);
|
|
gtk_object_set_data(GTK_OBJECT(button), "entry_number", entry_number);
|
|
gtk_object_set_data(GTK_OBJECT(button), "button", widget);
|
|
gtk_object_set_data(GTK_OBJECT(button), "number", GINT_TO_POINTER(n));
|
|
gtk_object_set_data(GTK_OBJECT(button), "window", window);
|
|
gtk_signal_connect(GTK_OBJECT(button), "clicked",
|
|
GTK_SIGNAL_FUNC(controlpad_preset_edit_ok),
|
|
session);
|
|
gtk_widget_show(button);
|
|
|
|
/* cancel button */
|
|
button = gtk_button_new_with_label(_("Cancel"));
|
|
gtk_box_pack_start_defaults(GTK_BOX(button_box), button);
|
|
gtk_signal_connect_object(GTK_OBJECT(button), "clicked",
|
|
GTK_SIGNAL_FUNC(gtk_widget_destroy),
|
|
GTK_OBJECT(window));
|
|
gtk_widget_show(button);
|
|
gtk_widget_show(window);
|
|
|
|
free(labeltext);
|
|
free(title);
|
|
return TRUE; /* event handled */
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* called when button in key pad clicked (except mute)
|
|
*/
|
|
static void controlpad_button_cb(GtkWidget *button, gpointer data) {
|
|
session_t *session = (session_t *) data;
|
|
char *c = (char *) gtk_object_get_data(GTK_OBJECT(button), "desc");
|
|
char *temp;
|
|
|
|
switch (session->state) {
|
|
case STATE_READY: /* manipulate dial box */
|
|
if ((*c >= '0' && *c <= '9') || *c == '*' || *c == '#') { /* new char */
|
|
gtk_entry_append_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box)
|
|
->entry), c);
|
|
} else if (*c == 'P') { /* preset button */
|
|
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box)->entry),
|
|
session->preset_numbers[strtol(&c[1], NULL, 0)]);
|
|
} else if (*c == 'B') { /* clear one byte (Backspace) */
|
|
temp = strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(
|
|
session->dial_number_box)->entry)));
|
|
if (strlen(temp) > 0) {
|
|
temp[strlen(temp) - 1] = 0;
|
|
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box)
|
|
->entry), temp);
|
|
}
|
|
free(temp);
|
|
} else if (*c == 'C') { /* clear entry */
|
|
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box)
|
|
->entry), "");
|
|
} else if (*c == 'R') { /* Redial from history */
|
|
do {
|
|
temp = g_list_nth_data(session->dial_number_history,
|
|
session->dial_number_history_pointer);
|
|
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(session->dial_number_box)
|
|
->entry), temp);
|
|
if (session->dial_number_history_pointer <
|
|
session->dial_number_history_maxlen)
|
|
session->dial_number_history_pointer++;
|
|
if (session->dial_number_history_pointer ==
|
|
session->dial_number_history_maxlen)
|
|
session->dial_number_history_pointer = 0;
|
|
} while (*temp == '\0' && session->dial_number_history_pointer != 0);
|
|
}
|
|
gtk_widget_grab_focus(GTK_WIDGET(GTK_COMBO(session->dial_number_box)
|
|
->entry));
|
|
gtk_entry_set_position(GTK_ENTRY(GTK_COMBO(session->dial_number_box)
|
|
->entry), -1);
|
|
break;
|
|
case STATE_CONVERSATION: /* touchtones */
|
|
if ((*c >= '0' && *c <= '9') || *c == '*' || *c == '#') { /* new tt */
|
|
#define TOUCHTONE_LENGTH 0.1
|
|
session->touchtone_countdown_isdn = TOUCHTONE_LENGTH * ISDN_SPEED;
|
|
session->touchtone_countdown_audio =
|
|
TOUCHTONE_LENGTH * session->audio_speed_out;
|
|
session->touchtone_index =
|
|
*c == '*' ? 9 : *c == '0' ? 10 : *c == '#' ? 11 : *c - '1';
|
|
}
|
|
break;
|
|
default: /* other states */
|
|
;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* called when mute button in key pad toggled
|
|
*/
|
|
static void controlpad_mute_cb(GtkWidget *button, gpointer data) {
|
|
session_t *session = (session_t *) data;
|
|
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) { /* muted */
|
|
session->option_muted = 1;
|
|
gtk_widget_show(session->muted_warning);
|
|
} else { /* unmuted */
|
|
session->option_muted = 0;
|
|
gtk_widget_hide(session->muted_warning);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* called when record / local / remote checkbutton has been toggled
|
|
*/
|
|
static void controlpad_record_cb(GtkWidget *button, gpointer data) {
|
|
session_t *session = (session_t *) data;
|
|
char *digits = NULL;
|
|
|
|
if (button == session->record_checkbutton) {
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) { /* record! */
|
|
session->option_record = 1;
|
|
if (session->state == STATE_CONVERSATION) {
|
|
if (recording_open(session->recorder,
|
|
digits = util_digitstime(&session->vcon_time),
|
|
session->option_recording_format))
|
|
{
|
|
fprintf(stderr, "Error opening audio file.\n");
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
|
|
session->record_checkbutton), FALSE);
|
|
return;
|
|
}
|
|
free(digits);
|
|
cid_row_mark_record(session, session->cid_num - 1);
|
|
}
|
|
} else { /* don't record! */
|
|
session->option_record = 0;
|
|
if (session->state == STATE_CONVERSATION) {
|
|
recording_write(session->recorder, session->rec_buf_local,
|
|
session->rec_buf_local_index, RECORDING_LOCAL);
|
|
recording_write(session->recorder, session->rec_buf_remote,
|
|
session->rec_buf_remote_index, RECORDING_REMOTE);
|
|
recording_close(session->recorder);
|
|
session->rec_buf_local_index = 0;
|
|
session->rec_buf_remote_index = 0;
|
|
}
|
|
}
|
|
gtk_widget_set_sensitive(session->record_checkbutton_local,
|
|
session->option_record);
|
|
gtk_widget_set_sensitive(session->record_checkbutton_remote,
|
|
session->option_record);
|
|
} else if (button == session->record_checkbutton_local) {
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) {
|
|
/* record local channel (if recording is selected at all)! */
|
|
session->option_record_local = 1;
|
|
} else { /* don't record local channel! */
|
|
session->option_record_local = 0;
|
|
}
|
|
} else { /* button == session->record_checkbutton_remote */
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) {
|
|
/* record remote channel (if recording is selected at all)! */
|
|
session->option_record_remote = 1;
|
|
} else { /* don't record remote channel! */
|
|
session->option_record_remote = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The key pad etc.
|
|
*/
|
|
GtkWidget *controlpad_new(session_t *session) {
|
|
char *labels[4][5] = {{"1", "2", "3", "B", session->preset_names[0]},
|
|
{"4", "5", "6", "C", session->preset_names[1]},
|
|
{"7", "8", "9", "R", session->preset_names[2]},
|
|
{"*", "0", "#", "M", session->preset_names[3]}};
|
|
char *tips[4][5] = {
|
|
{",-./", "abc", "def", N_("Backspace"), N_("Preset 1")},
|
|
{"ghi", "jkl", "mno", N_("Clear Number"), N_("Preset 2")},
|
|
{"pqrs", "tuv", "wxyz", N_("Redial"), N_("Preset 3")},
|
|
{"", "0...9", "", N_("Mute Microphone"), N_("Preset 4")}};
|
|
char *presetcodes[4] = {"P0", "P1", "P2", "P3"};
|
|
|
|
GtkWidget *frame;
|
|
GtkWidget *hbox;
|
|
GtkWidget *table;
|
|
GtkWidget *button;
|
|
|
|
GtkWidget *recordframe;
|
|
GtkWidget *recordbox;
|
|
GtkWidget *record_checkbutton;
|
|
GtkWidget *record_checkbutton_local;
|
|
GtkWidget *record_checkbutton_remote;
|
|
|
|
GdkPixmap *pixmap;
|
|
GdkBitmap *mask;
|
|
GtkStyle *style;
|
|
GtkWidget *pixmapwid;
|
|
|
|
GtkTooltips *tooltips;
|
|
|
|
int i, j;
|
|
|
|
tooltips = gtk_tooltips_new();
|
|
/* tooltips are often grey by default and have to be set up with a gtkrc
|
|
file:
|
|
|
|
style "gtk-tooltips-style" {
|
|
bg[NORMAL] = "#ffffc0"
|
|
}
|
|
widget "gtk-tooltips" style "gtk-tooltips-style"
|
|
*/
|
|
|
|
frame = gtk_frame_new(_("Control"));
|
|
gtk_container_set_border_width(GTK_CONTAINER(frame), 8);
|
|
|
|
hbox = gtk_hbox_new(FALSE, 15);
|
|
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
|
|
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
|
gtk_widget_show(hbox);
|
|
|
|
table = gtk_table_new(4, 3, FALSE);
|
|
gtk_table_set_row_spacings(GTK_TABLE(table), 5);
|
|
gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, FALSE, 5);
|
|
gtk_widget_show(table);
|
|
|
|
for (i = 0; i < 5; i++) { /* columns */
|
|
for (j = 0; j < 4; j++) { /* rows */
|
|
if (i == 3 && j == 3) { /* mute */
|
|
button = gtk_toggle_button_new();
|
|
style = gtk_widget_get_style(session->main_window);
|
|
pixmap = gdk_pixmap_create_from_xpm_d(session->main_window->window,
|
|
&mask,
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
(gchar **) mute_xpm);
|
|
pixmapwid = gtk_pixmap_new(pixmap, mask);
|
|
gtk_container_add(GTK_CONTAINER(button), pixmapwid);
|
|
gtk_widget_show(pixmapwid);
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
|
|
session->option_muted);
|
|
session->mute_button = button;
|
|
gtk_signal_connect(GTK_OBJECT(button), "toggled",
|
|
GTK_SIGNAL_FUNC(controlpad_mute_cb), session);
|
|
} else { /* everything else (except mute) */
|
|
if (i == 3 && j == 0) { /* backspace icon */
|
|
button = gtk_button_new();
|
|
style = gtk_widget_get_style(session->main_window);
|
|
pixmap = gdk_pixmap_create_from_xpm_d(session->main_window->window,
|
|
&mask,
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
(gchar **) backspace_xpm);
|
|
pixmapwid = gtk_pixmap_new(pixmap, mask);
|
|
gtk_container_add(GTK_CONTAINER(button), pixmapwid);
|
|
gtk_widget_show(pixmapwid);
|
|
} else if (i == 3 && j == 2) { /* redial icon */
|
|
button = gtk_button_new();
|
|
style = gtk_widget_get_style(session->main_window);
|
|
pixmap = gdk_pixmap_create_from_xpm_d(session->main_window->window,
|
|
&mask,
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
(gchar **) redial_xpm);
|
|
pixmapwid = gtk_pixmap_new(pixmap, mask);
|
|
gtk_container_add(GTK_CONTAINER(button), pixmapwid);
|
|
gtk_widget_show(pixmapwid);
|
|
} else { /* icon with letter (or description) */
|
|
button = gtk_button_new_with_label(labels[j][i]);
|
|
gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
|
|
GTK_SIGNAL_FUNC(controlpad_preset_edit_cb),
|
|
session);
|
|
}
|
|
/* connect callback to widget */
|
|
gtk_object_set_data(GTK_OBJECT(button), "desc",
|
|
i < 4 ? labels[j][i] : presetcodes[j]);
|
|
gtk_signal_connect(GTK_OBJECT(button), "pressed",
|
|
GTK_SIGNAL_FUNC(controlpad_button_cb), session);
|
|
}
|
|
if (*tips[j][i])
|
|
gtk_tooltips_set_tip(tooltips, button, _(tips[j][i]), NULL);
|
|
gtk_table_attach_defaults(GTK_TABLE(table), button, i, i + 1, j, j + 1);
|
|
gtk_widget_set_size_request(button, i < 3 ? 30 : i == 3 ? 20 : 100, -1);
|
|
gtk_widget_show(button);
|
|
}
|
|
gtk_table_set_col_spacing(GTK_TABLE(table), i, i < 2 ? 5 : 15);
|
|
}
|
|
|
|
recordframe = gtk_frame_new(_("Recording"));
|
|
gtk_box_pack_start(GTK_BOX(hbox), recordframe, TRUE, FALSE, 5);
|
|
gtk_widget_show(recordframe);
|
|
|
|
recordbox = gtk_table_new(2, 3, FALSE);
|
|
gtk_table_set_row_spacings(GTK_TABLE(recordbox), 0);
|
|
gtk_table_set_col_spacings(GTK_TABLE(recordbox), 20);
|
|
gtk_container_add(GTK_CONTAINER(recordframe), recordbox);
|
|
gtk_widget_show(recordbox);
|
|
|
|
record_checkbutton =
|
|
gtk_check_button_new_with_label(_("Record to file"));
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_checkbutton),
|
|
session->option_record);
|
|
gtk_table_attach(GTK_TABLE(recordbox), record_checkbutton,
|
|
0, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
|
|
gtk_widget_show(record_checkbutton);
|
|
gtk_signal_connect(GTK_OBJECT(record_checkbutton), "toggled",
|
|
GTK_SIGNAL_FUNC(controlpad_record_cb), session);
|
|
session->record_checkbutton = record_checkbutton;
|
|
|
|
record_checkbutton_local =
|
|
gtk_check_button_new_with_label(_("Record local channel"));
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_checkbutton_local),
|
|
session->option_record_local);
|
|
gtk_table_attach(GTK_TABLE(recordbox), record_checkbutton_local,
|
|
1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
|
|
gtk_widget_show(record_checkbutton_local);
|
|
gtk_signal_connect(GTK_OBJECT(record_checkbutton_local), "toggled",
|
|
GTK_SIGNAL_FUNC(controlpad_record_cb), session);
|
|
session->record_checkbutton_local = record_checkbutton_local;
|
|
|
|
record_checkbutton_remote =
|
|
gtk_check_button_new_with_label(_("Record remote channel"));
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_checkbutton_remote),
|
|
session->option_record_remote);
|
|
gtk_table_attach(GTK_TABLE(recordbox), record_checkbutton_remote,
|
|
1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
|
|
gtk_widget_show(record_checkbutton_remote);
|
|
gtk_signal_connect(GTK_OBJECT(record_checkbutton_remote), "toggled",
|
|
GTK_SIGNAL_FUNC(controlpad_record_cb), session);
|
|
session->record_checkbutton_remote = record_checkbutton_remote;
|
|
|
|
if (!session->option_record) {
|
|
gtk_widget_set_sensitive(record_checkbutton_local, FALSE);
|
|
gtk_widget_set_sensitive(record_checkbutton_remote, FALSE);
|
|
}
|
|
|
|
return frame;
|
|
}
|
|
|
|
/* called when control pad state check button is toggled */
|
|
void controlpad_toggle_cb(GtkWidget *widget _U_,
|
|
gpointer data, guint action _U_) {
|
|
session_t *session = (session_t *) data;
|
|
|
|
if (GTK_CHECK_MENU_ITEM (session->controlpad_check_menu_item)->active) {
|
|
gtk_widget_show(session->controlpad);
|
|
session->option_show_controlpad = 1;
|
|
} else {
|
|
gtk_widget_hide(session->controlpad);
|
|
session->option_show_controlpad = 0;
|
|
/* shrink if no growing callerid monitor present */
|
|
if (!session->option_show_callerid)
|
|
gtk_window_resize(GTK_WINDOW(session->main_window), 1, 1);
|
|
}
|
|
}
|
|
|