xwords/xwords4/linux/gtkinvit.c
Eric House 87418d63d1 fix linux "sms" and modify script to test it
My linux sms hack used inotify and didn't check for messages that were
there when the app launched. Replace inotify with a simple glib periodic
timer. A bit of latency mimics SMS better anyway. Update test script to
support SMS, and add params to and otherwise fix linux client so
everything works.
2018-07-05 21:22:20 -07:00

376 lines
12 KiB
C

/* -*- compile-command: "make MEMDEBUG=TRUE -j5"; -*- */
/*
* Copyright 2001-2014 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 "gtkinvit.h"
#include "gtkutils.h"
#include "linuxbt.h"
#include "comtypes.h"
typedef struct _PageData {
CommsConnType pageType;
gboolean doUse;
const char* labelText;
GtkWidget* label;
const char* okButtonTxt;
} PageData;
static XP_UCHAR s_devIDBuf[32] = {0};
typedef struct _GtkInviteState {
GtkGameGlobals* globals;
CommsAddrRec* addr;
gint* nPlayersP;
XP_U32* devIDp;
gint maxPlayers;
GtkWidget* nPlayersCombo;
/* relay */
GtkWidget* devID;
/* BT */
GtkWidget* bthost;
/* SMS */
GtkWidget* smsphone;
GtkWidget* smsport;
GtkWidget* bgScanButton;
GtkWidget* okButton;
GtkWidget* notebook;
guint curPage;
XP_U16 nTypes;
PageData pageData[COMMS_CONN_NTYPES];
gboolean cancelled;
} GtkInviteState;
/* Make it static so we remember user's late entry */
static gint
conTypeToPageNum( const GtkInviteState* state, CommsConnType conType )
{
gint pageNum = 0; /* default */
int ii;
for ( ii = 0; ; ++ii ) {
const PageData* pageData = &state->pageData[ii];
CommsConnType thisType = pageData->pageType;
if ( thisType == COMMS_CONN_NONE || thisType == conType ) {
pageNum = ii;
break;
}
XP_ASSERT( ii < VSIZE(state->pageData) );
}
return pageNum;
}
static void
handle_ok( GtkWidget* XP_UNUSED(widget), gpointer closure )
{
GtkInviteState* state = (GtkInviteState*)closure;
const gchar* txt;
guint curPage = state->curPage;
PageData* data = &state->pageData[curPage];
CommsConnType conType = data->pageType;
addr_addType( state->addr, conType );
switch ( conType ) {
#ifdef XWFEATURE_RELAY
case COMMS_CONN_RELAY:
txt = gtk_entry_get_text( GTK_ENTRY(state->devID) );
snprintf( s_devIDBuf, sizeof(s_devIDBuf), "%s", txt );
*state->devIDp = 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;
}
/* get the number to invite */
gchar* num =
gtk_combo_box_text_get_active_text( GTK_COMBO_BOX_TEXT(state->nPlayersCombo) );
*(state->nPlayersP) = atoi( num );
state->cancelled = XP_FALSE;
gtk_main_quit();
} /* handle_ok */
static void
handle_scan( GtkWidget* XP_UNUSED(widget), gpointer closure )
{
GtkInviteState* state = (GtkInviteState*)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 )
{
GtkInviteState* state = (GtkInviteState*)closure;
state->cancelled = XP_TRUE;
gtk_main_quit();
}
/*
* Invite: _____
* Relay: _____
* Port: _____
* Cancel OK
*/
static GtkWidget*
makeRelayPage( GtkInviteState* state, PageData* data )
{
data->okButtonTxt = "Invite via Relay";
GtkWidget* vbox = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
GtkWidget* hbox;
hbox = makeLabeledField( "Invitee DeviceID", &state->devID, NULL );
gtk_entry_set_text( GTK_ENTRY(state->devID), s_devIDBuf );
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
gtk_widget_show( vbox );
return vbox;
} /* makeRelayPage */
static GtkWidget*
makeBTPage( GtkInviteState* state, PageData* data )
{
data->okButtonTxt = "Invite via Bluetooth";
GtkWidget* vbox = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
GtkWidget* hbox = makeLabeledField( "Invitee device", &state->bthost, NULL );
if ( addr_hasType( state->addr, data->pageType ) ) {
gtk_entry_set_text( GTK_ENTRY(state->bthost), state->addr->u.bt.hostName );
}
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
state->bgScanButton = makeButton( "Scan", (GCallback)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( GtkInviteState* state, PageData* data ) */
/* { */
/* GtkWidget* vbox = boxWithUseCheck( state, data ); */
/* /\* XP_UCHAR hostName_ip[MAX_HOSTNAME_LEN + 1]; *\/ */
/* /\* XP_U16 port_ip; *\/ */
/* XP_Bool hasIP = addr_hasType( state->addr, data->pageType ); */
/* const gchar* name = hasIP ? */
/* 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 ( hasIP ) { */
/* 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( GtkInviteState* state, PageData* data )
{
data->okButtonTxt = "Invite via SMS";
GtkWidget* vbox = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
XP_Bool hasSMS = addr_hasType( state->addr, data->pageType );
const gchar* phone = hasSMS ?
state->addr->u.sms.phone : state->globals->cGlobals.params->connInfo.sms.myPhone;
GtkWidget* hbox = makeLabeledField( "Invitee phone", &state->smsphone, phone );
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
int portVal = hasSMS ? state->addr->u.sms.port
: state->globals->cGlobals.params->connInfo.sms.port;
gchar port[32];
snprintf( port, sizeof(port), "%d", portVal );
hbox = makeLabeledField( "Invitee port", &state->smsport, port );
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
gtk_widget_show( vbox );
return vbox;
} /* makeBTPage */
static PageData*
getNextData( GtkInviteState* state, CommsConnType typ, gchar* label )
{
PageData* result = &state->pageData[state->nTypes++];
result->pageType = typ;
result->label = gtk_label_new( label );
result->labelText = label;
return result;
}
static void
onPageChanged( GtkNotebook* XP_UNUSED(notebook), gpointer XP_UNUSED(arg1),
guint arg2, gpointer data )
{
GtkInviteState* state = (GtkInviteState*)data;
state->curPage = arg2;
PageData* pageData = &state->pageData[arg2];
gtk_button_set_label(GTK_BUTTON(state->okButton), pageData->okButtonTxt );
}
XP_Bool
gtkInviteDlg( GtkGameGlobals* globals, CommsAddrRec* addr,
gint* nPlayersP, XP_U32* devIDp )
{
GtkInviteState state;
XP_MEMSET( &state, 0, sizeof(state) );
state.globals = globals;
state.addr = addr;
state.nPlayersP = nPlayersP;
state.devIDp = devIDp;
state.maxPlayers = *nPlayersP;
GtkWidget* dialog;
GtkWidget* hbox;
GtkWidget* vbox = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 );
GtkWidget* label = gtk_label_new( "Invite how many:" );
gtk_box_pack_start( GTK_BOX(hbox), label, FALSE, TRUE, 0 );
state.nPlayersCombo = gtk_combo_box_text_new();
for ( int ii = 1; ii <= state.maxPlayers; ++ii ) {
gchar buf[8];
sprintf( buf, "%d", ii );
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(state.nPlayersCombo), buf );
}
gtk_combo_box_set_active( GTK_COMBO_BOX(state.nPlayersCombo), 0 );
gtk_box_pack_start( GTK_BOX(hbox), state.nPlayersCombo, FALSE, TRUE, 0 );
gtk_widget_show( state.nPlayersCombo );
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
state.notebook = gtk_notebook_new();
g_signal_connect( state.notebook, "switch-page",
G_CALLBACK(onPageChanged), &state );
PageData* data;
#ifdef XWFEATURE_RELAY
data = getNextData( &state, COMMS_CONN_RELAY, "Relay" );
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
makeRelayPage( &state, data ),
data->label );
#endif
#ifdef XWFEATURE_BLUETOOTH
data = getNextData( &state, COMMS_CONN_BT, "Bluetooth" );
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
makeBTPage( &state, data ),
data->label );
#endif
/* #ifdef XWFEATURE_DIRECTIP */
/* data = getNextData( &state, COMMS_CONN_IP_DIRECT, "Direct" ); */
/* (void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook), */
/* makeIPDirPage(&state, data), */
/* data->label ); */
/* #endif */
#ifdef XWFEATURE_SMS
data = getNextData( &state, COMMS_CONN_SMS, "SMS" );
(void)gtk_notebook_append_page( GTK_NOTEBOOK(state.notebook),
makeSMSPage( &state, data ),
data->label );
#endif
gtk_box_pack_start( GTK_BOX(vbox), state.notebook, FALSE, TRUE, 0 );
/* Set page to the first we actually have */
XP_U32 st = 0;
CommsConnType firstType;
if ( addr_iter( addr, &firstType, &st ) ) {
gint pageNo = conTypeToPageNum( &state, firstType );
gtk_notebook_set_current_page( GTK_NOTEBOOK(state.notebook), pageNo );
}
gtk_widget_show( state.notebook );
/* buttons at the bottom */
hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 );
state.okButton = makeButton( state.pageData[0].okButtonTxt,
(GCallback)handle_ok, &state );
gtk_box_pack_start( GTK_BOX(hbox), state.okButton, FALSE, TRUE, 0 );
gtk_box_pack_start( GTK_BOX(hbox),
makeButton( "Cancel", (GCallback)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_dialog_add_action_widget( GTK_DIALOG(dialog), vbox, 0 );
gtk_widget_show_all( dialog );
gtk_main();
gtk_widget_destroy( dialog );
return !state.cancelled;
} /* gtkInviteDlg */
#endif