mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-20 22:26:54 +01:00
d293517e7c
My VSIZE is no longer legal, and apparently there's no workaround (no way to safely figure the length of an array whose size is known at compile time.) To avoid the risk of duplicating little constants, added macros that define length in a way a new VSIZE can pick it up. Couldn't make that work for struct field arrays, however, so there I'm using constants.
376 lines
12 KiB
C
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 < COMMS_CONN_NTYPES );
|
|
}
|
|
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
|