xwords/xwords4/linux/gtkconnsdlg.c
Eric House 43bd3c018a make an addr's conType a bitfield rather than holding a single value.
Works for large numbers of relay games in test, but will not yet
actually hold more than one value.  Should be safe to merge to main
branch once stream upgrade is verified.
2014-09-25 20:05:37 -07:00

365 lines
12 KiB
C

/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
/*
* Copyright 2001-2008 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef PLATFORM_GTK
#include "gtkconnsdlg.h"
#include "gtkutils.h"
#include "linuxbt.h"
typedef struct _GtkConnsState {
GtkGameGlobals* globals;
CommsAddrRec* addr;
DeviceRole role;
GtkWidget* invite;
GtkWidget* hostName;
GtkWidget* port;
GtkWidget* bthost;
GtkWidget* smsphone;
GtkWidget* smsport;
GtkWidget* iphost;
GtkWidget* ipport;
GtkWidget* bgScanButton;
GtkWidget* notebook;
CommsConnType pageTypes[COMMS_CONN_NTYPES];
gboolean cancelled;
gboolean readOnly;
} GtkConnsState;
static gint
conTypeToPageNum( const GtkConnsState* state, CommsConnType conType )
{
gint pageNum = 0; /* default */
int ii;
for ( ii = 0; ; ++ii ) {
CommsConnType thisType = state->pageTypes[ii];
if ( thisType == COMMS_CONN_NONE || thisType == conType ) {
pageNum = ii;
break;
}
XP_ASSERT( ii < VSIZE(state->pageTypes) );
}
return pageNum;
}
static CommsConnType
pageNoToConnType( const GtkConnsState* state, gint page )
{
XP_ASSERT( page < VSIZE(state->pageTypes) );
XP_ASSERT( state->pageTypes[page] != COMMS_CONN_NONE );
return state->pageTypes[page];
}
static void
handle_ok( GtkWidget* XP_UNUSED(widget), gpointer closure )
{
GtkConnsState* state = (GtkConnsState*)closure;
if ( !state->readOnly ) {
const gchar* txt;
gint page = gtk_notebook_get_current_page
( GTK_NOTEBOOK(state->notebook) );
CommsConnType conType = pageNoToConnType( state, page );
switch ( conType ) {
#ifdef XWFEATURE_DIRECTIP
case COMMS_CONN_IP_DIRECT:
txt = gtk_entry_get_text( GTK_ENTRY(state->iphost) );
XP_STRNCPY( state->addr->u.ip.hostName_ip, txt,
sizeof(state->addr->u.ip.hostName_ip) );
txt = gtk_entry_get_text( GTK_ENTRY(state->ipport) );
state->addr->u.ip.port_ip = atoi( txt );
break;
#endif
#ifdef XWFEATURE_RELAY
case COMMS_CONN_RELAY:
txt = gtk_entry_get_text( GTK_ENTRY(state->invite) );
XP_STRNCPY( state->addr->u.ip_relay.invite, txt,
sizeof(state->addr->u.ip_relay.invite) );
txt = gtk_entry_get_text( GTK_ENTRY(state->hostName) );
XP_STRNCPY( state->addr->u.ip_relay.hostName, txt,
sizeof(state->addr->u.ip_relay.hostName) );
txt = gtk_entry_get_text( GTK_ENTRY(state->port) );
state->addr->u.ip_relay.port = atoi( txt );
break;
#endif
#ifdef XWFEATURE_BLUETOOTH
case COMMS_CONN_BT:
txt = gtk_entry_get_text( GTK_ENTRY(state->bthost) );
XP_STRNCPY( state->addr->u.bt.hostName, txt,
sizeof(state->addr->u.bt.hostName) );
break;
#endif
case COMMS_CONN_SMS:
txt = gtk_entry_get_text( GTK_ENTRY(state->smsphone) );
XP_STRNCPY( state->addr->u.sms.phone, txt,
sizeof(state->addr->u.sms.phone) );
txt = gtk_entry_get_text( GTK_ENTRY(state->smsport) );
state->addr->u.sms.port = atoi( txt );
break;
default:
XP_ASSERT( 0 ); /* keep compiler happy */
break;
}
addr_setType( state->addr, conType );
}
state->cancelled = XP_FALSE;
gtk_main_quit();
} /* handle_ok */
static void
handle_scan( GtkWidget* XP_UNUSED(widget), gpointer closure )
{
GtkConnsState* state = (GtkConnsState*)closure;
XP_USE(state);
LOG_FUNC();
GSList* devNames = linux_bt_scan();
if ( !devNames ) {
XP_LOGF( "%s: got nothing", __func__ );
} else {
GSList* iter;
for ( iter = devNames; !!iter; iter = iter->next ) {
#ifdef DEBUG
gchar* name = iter->data;
XP_LOGF( "%s: got %s", __func__, name );
#endif
}
}
}
static void
handle_cancel( GtkWidget* XP_UNUSED(widget), void* closure )
{
GtkConnsState* state = (GtkConnsState*)closure;
state->cancelled = XP_TRUE;
gtk_main_quit();
}
/*
* Invite: _____
* Relay: _____
* Port: _____
* Cancel OK
*/
static GtkWidget*
makeRelayPage( GtkConnsState* state )
{
GtkWidget* vbox = gtk_vbox_new( FALSE, 0 );
const gchar* hint = NULL;
if ( SERVER_ISSERVER == state->role ) {
hint = "As host, you pick the room name for the game, and must "
"connect first";
} else {
XP_ASSERT( SERVER_ISCLIENT == state->role );
hint = "As guest, you get the room name from the host. Be sure to "
"let the host connect first to validate the name.";
}
gtk_box_pack_start( GTK_BOX(vbox), gtk_label_new( hint ), FALSE, TRUE, 0 );
GtkWidget* hbox = makeLabeledField( "Room", &state->invite, NULL );
if ( COMMS_CONN_RELAY == addr_getType( state->addr ) ) {
gtk_entry_set_text( GTK_ENTRY(state->invite),
state->addr->u.ip_relay.invite );
}
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
gtk_widget_set_sensitive( state->invite, !state->readOnly );
hbox = makeLabeledField( "Relay address", &state->hostName, NULL );
if ( COMMS_CONN_RELAY == addr_getType( state->addr ) ) {
gtk_entry_set_text( GTK_ENTRY(state->hostName),
state->addr->u.ip_relay.hostName );
}
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
gtk_widget_set_sensitive( state->hostName, !state->readOnly );
hbox = makeLabeledField( "Relay port", &state->port, NULL );
if ( COMMS_CONN_RELAY == addr_getType( state->addr ) ) {
char buf[16];
snprintf( buf, sizeof(buf), "%d", state->addr->u.ip_relay.port );
gtk_entry_set_text( GTK_ENTRY(state->port), buf );
}
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
gtk_widget_set_sensitive( state->port, !state->readOnly );
gtk_widget_show( vbox );
return vbox;
} /* makeRelayPage */
static GtkWidget*
makeBTPage( GtkConnsState* state )
{
GtkWidget* vbox = gtk_vbox_new( FALSE, 0 );
GtkWidget* hbox = makeLabeledField( "Host device", &state->bthost, NULL );
if ( COMMS_CONN_BT == addr_getType( state->addr ) ) {
gtk_entry_set_text( GTK_ENTRY(state->bthost), state->addr->u.bt.hostName );
}
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
gtk_widget_set_sensitive( state->bthost, !state->readOnly );
state->bgScanButton = makeButton( "Scan", GTK_SIGNAL_FUNC(handle_scan),
state );
gtk_box_pack_start( GTK_BOX(vbox), state->bgScanButton, FALSE, TRUE, 0 );
gtk_widget_show( vbox );
return vbox;
} /* makeBTPage */
#ifdef XWFEATURE_DIRECTIP
static GtkWidget*
makeIPDirPage( GtkConnsState* state )
{
GtkWidget* vbox = gtk_vbox_new( FALSE, 0 );
/* XP_UCHAR hostName_ip[MAX_HOSTNAME_LEN + 1]; */
/* XP_U16 port_ip; */
const gchar* name = COMMS_CONN_IP_DIRECT == addr_getType( state->addr ) ?
state->addr->u.ip.hostName_ip : state->globals->cGlobals.params->connInfo.ip.hostName;
GtkWidget* hbox = makeLabeledField( "Hostname", &state->iphost, name );
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
hbox = makeLabeledField( "Relay port", &state->ipport, NULL );
if ( COMMS_CONN_IP_DIRECT == addr_getType( state->addr ) ) {
char buf[16];
snprintf( buf, sizeof(buf), "%d", state->addr->u.ip.port_ip );
gtk_entry_set_text( GTK_ENTRY(state->ipport), buf );
}
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
return vbox;
}
#endif
static GtkWidget*
makeSMSPage( GtkConnsState* state )
{
GtkWidget* vbox = gtk_vbox_new( FALSE, 0 );
const gchar* phone = COMMS_CONN_SMS == addr_getType( state->addr ) ?
state->addr->u.sms.phone : state->globals->cGlobals.params->connInfo.sms.phone;
GtkWidget* hbox = makeLabeledField( "Host phone", &state->smsphone, phone );
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
gtk_widget_set_sensitive( state->smsphone, !state->readOnly );
int portVal = COMMS_CONN_SMS == addr_getType( state->addr )
? state->addr->u.sms.port
: state->globals->cGlobals.params->connInfo.sms.port;
gchar port[32];
snprintf( port, sizeof(port), "%d", portVal );
hbox = makeLabeledField( "Host port", &state->smsport, port );
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
gtk_widget_set_sensitive( state->smsport, !state->readOnly );
gtk_widget_show( vbox );
return vbox;
} /* makeBTPage */
gboolean
gtkConnsDlg( GtkGameGlobals* globals, CommsAddrRec* addr, DeviceRole role,
XP_Bool readOnly )
{
GtkConnsState state;
XP_MEMSET( &state, 0, sizeof(state) );
XP_U16 nTypes = 0;
state.readOnly = readOnly;
state.globals = globals;
state.addr = addr;
state.role = role;
GtkWidget* dialog;
GtkWidget* vbox;
GtkWidget* hbox;
state.notebook = gtk_notebook_new();
#ifdef XWFEATURE_RELAY
state.pageTypes[nTypes++] = COMMS_CONN_RELAY;
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
makeRelayPage(&state),
gtk_label_new( "Relay" ) );
#endif
#ifdef XWFEATURE_BLUETOOTH
state.pageTypes[nTypes++] = COMMS_CONN_BT;
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
makeBTPage(&state),
gtk_label_new( "Bluetooth" ) );
#endif
#ifdef XWFEATURE_DIRECTIP
state.pageTypes[nTypes++] = COMMS_CONN_IP_DIRECT;
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
makeIPDirPage(&state),
gtk_label_new( "Direct" ) );
#endif
state.pageTypes[nTypes++] = COMMS_CONN_SMS;
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
makeSMSPage(&state),
gtk_label_new( "SMS" ) );
vbox = gtk_vbox_new( FALSE, 0 );
gtk_box_pack_start( GTK_BOX(vbox), state.notebook, FALSE, TRUE, 0 );
state.pageTypes[nTypes++] = COMMS_CONN_NONE; /* mark end of list */
gint pageNo = conTypeToPageNum( &state, addr_getType( addr ) );
gtk_notebook_set_current_page( GTK_NOTEBOOK(state.notebook), pageNo );
gtk_widget_show( state.notebook );
/* buttons at the bottom */
hbox = gtk_hbox_new( FALSE, 0 );
gtk_box_pack_start( GTK_BOX(hbox),
makeButton( "Ok", GTK_SIGNAL_FUNC(handle_ok), &state ),
FALSE, TRUE, 0 );
if ( !readOnly ) {
gtk_box_pack_start( GTK_BOX(hbox),
makeButton( "Cancel",
GTK_SIGNAL_FUNC(handle_cancel),
&state ),
FALSE, TRUE, 0 );
}
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
gtk_widget_show( vbox );
dialog = gtk_dialog_new();
gtk_window_set_modal( GTK_WINDOW( dialog ), TRUE );
gtk_container_add( GTK_CONTAINER( GTK_DIALOG(dialog)->action_area), vbox );
gtk_widget_show_all( dialog );
gtk_main();
gtk_widget_destroy( dialog );
return !state.cancelled;
} /* gtkConnsDlg */
#endif