Files
2015-09-03 01:20:11 -07:00

402 lines
12 KiB
C

/*
PokeMini - Pokémon-Mini Emulator
Copyright (C) 2009-2015 JustBurn
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <math.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "SDL.h"
#include "PokeMini.h"
#include "PokeMini_Debug.h"
#include "Hardware_Debug.h"
#include "CPUWindow.h"
#include "ExternalWindow.h"
#include "PokeMiniIcon_96x128.h"
#include "InstructionProc.h"
#include "InstructionInfo.h"
#include <gtk/gtk.h>
#include "GtkXDialogs.h"
#include "SGtkXDrawingView.h"
int ExternalWindow_InConfigs = 0;
GtkWindow *ExternalWindow;
static GtkScrolledWindow *ExternalSW;
static GtkBox *VBox1;
static GtkTable *MTable;
static GtkLabel *MLabelTitle[10];
static GtkLabel *MLabelExec[10];
static GtkEntry *MEntryTitle[10];
static GtkEntry *MEntryExec[10];
static GtkToggleButton *MCurrDir[10];
static GtkLabel *LabelDesc;
static GtkButtonBox *HButtonBox;
static GtkButton *ButtonOk;
static GtkButton *ButtonCancel;
// Locals
GtkItemFactory *CPUItemFactory = NULL;
#define EXTMPV (4096)
// --------
// Launcher
// --------
static int RunCmdNoWait(const char *runcmd, int atcurrdir)
{
char **argv, *argpars = "", *launchdir;
int i, res = 1, argc;
// Select launch directory
launchdir = atcurrdir ? PokeMini_CurrDir : PokeMini_ExecDir;
// Decode arguments
argc = GetArgument(runcmd, 1, NULL, 0, &argpars);
argv = (char **)malloc((argc + 1) * sizeof(char *));
for (i=0; i<argc; i++) {
argv[i] = (char *)malloc(EXTMPV);
memset(argv[i], 0, EXTMPV);
GetArgument(runcmd, i, argv[i], EXTMPV-1, NULL);
}
argv[argc] = NULL;
#ifdef _WIN32
// Shell execute
res = (int)ShellExecute(NULL, "open", argv[0], argpars, launchdir, SW_SHOW) > 32;
#else
// Fork and execute
i = fork();
if (i == -1) {
fprintf(stderr, "Error: Couldn't fork()\n");
res = 0;
} else if (i == 0) {
// Child process
PokeMini_GotoCustomDir(launchdir);
execvp(argv[0], argv);
_exit(0);
}
#endif
// Free memory
for (i=0; i<argc; i++) free(argv[i]);
free(argv);
return res;
}
// Return:
// -1 - Required ROM
// 0 - Overflow, failure to call
// 1 - Empty
// 2 - Success
int ExternalWindow_Launch(const char *execcod, int atcurrdir)
{
char ch, execrun[EXTMPV], tmp[EXTMPV];
int execp = 0;
memset(execrun, 0, sizeof(EXTMPV));
while ((ch = *execcod++) != 0) {
if (ch == '%') {
switch (*execcod++) {
case 0: break;
case '%':
execrun[execp++] = '%';
break;
case 'x': case 'X': // Executable path
strcpy(tmp, PokeMini_ExecDir);
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
case 'c': case 'C': // Current path
strcpy(tmp, PokeMini_CurrDir);
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
case 'R': // ROM filename with path
if (!strlen(CommandLine.min_file)) return -1;
if ((CommandLine.min_file[0] != '/') && (CommandLine.min_file[1] != ':')) {
#ifdef _WIN32
sprintf(tmp, "%s\\%s", PokeMini_CurrDir, CommandLine.min_file);
#else
sprintf(tmp, "%s/%s", PokeMini_CurrDir, CommandLine.min_file);
#endif
} else strcpy(tmp, CommandLine.min_file);
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
case 'r': // ROM filename
if (!strlen(CommandLine.min_file)) return -1;
strcpy(tmp, CommandLine.min_file);
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
case 'F': // ROM filename without path
if (!strlen(CommandLine.min_file)) return -1;
strcpy(tmp, GetFilename(CommandLine.min_file));
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
case 'f': // ROM filename without path & extension
if (!strlen(CommandLine.min_file)) return -1;
strcpy(tmp, GetFilename(CommandLine.min_file));
RemoveExtension(tmp);
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
case 'N': // ROM filename with path but without extension
if (!strlen(CommandLine.min_file)) return -1;
if ((CommandLine.min_file[0] != '/') && (CommandLine.min_file[1] != ':')) {
#ifdef _WIN32
sprintf(tmp, "%s\\%s", PokeMini_CurrDir, CommandLine.min_file);
#else
sprintf(tmp, "%s/%s", PokeMini_CurrDir, CommandLine.min_file);
#endif
} else strcpy(tmp, CommandLine.min_file);
RemoveExtension(tmp);
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
case 'n': // ROM filename without extension
if (!strlen(CommandLine.min_file)) return -1;
strcpy(tmp, GetFilename(CommandLine.min_file));
RemoveExtension(tmp);
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
case 'P': // ROM path only, with slash
if (!strlen(CommandLine.min_file)) return -1;
strcpy(tmp, CommandLine.min_file);
ExtractPath(tmp, 1);
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
case 'p': // ROM path only, without slash
if (!strlen(CommandLine.min_file)) return -1;
strcpy(tmp, CommandLine.min_file);
ExtractPath(tmp, 0);
strncpy(&execrun[execp], tmp, EXTMPV-execp-1);
execp += strlen(tmp);
break;
}
} else {
execrun[execp++] = ch;
}
if ((EXTMPV-execp-1) <= 0) {
return 0;
}
}
execrun[execp] = 0;
if (strlen(execrun)) {
if (RunCmdNoWait(execrun, atcurrdir)) return 2;
return 0;
}
return 1;
}
// -----------------
// Widgets callbacks
// -----------------
static gint ExternalWindow_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_widget_hide(GTK_WIDGET(ExternalWindow));
return TRUE;
}
static void ExternalWindow_ButtonOk_clicked(GtkWidget *widget, gpointer data)
{
int i;
for (i=0; i<10; i++) {
memset(dclc_extapp_title[i], 0, PMTMPV);
strncpy(dclc_extapp_title[i], gtk_entry_get_text(MEntryTitle[i]), PMTMPV-1);
memset(dclc_extapp_exec[i], 0, PMTMPV);
strncpy(dclc_extapp_exec[i], gtk_entry_get_text(MEntryExec[i]), PMTMPV-1);
dclc_extapp_atcurrdir[i] = gtk_toggle_button_get_active(MCurrDir[i]) ? 1 : 0;
}
if (CPUItemFactory) ExternalWindow_UpdateMenu(CPUItemFactory);
gtk_widget_hide(GTK_WIDGET(ExternalWindow));
}
static void ExternalWindow_ButtonCancel_clicked(GtkWidget *widget, gpointer data)
{
ExternalWindow_UpdateConfigs();
gtk_widget_hide(GTK_WIDGET(ExternalWindow));
}
// ---------------
// External Window
// ---------------
int ExternalWindow_Create(void)
{
char tmp[PMTMPV];
int i;
// Window
ExternalWindow = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
gtk_window_set_title(GTK_WINDOW(ExternalWindow), "External configuration");
gtk_widget_set_size_request(GTK_WIDGET(ExternalWindow), 300, 250);
gtk_window_set_default_size(ExternalWindow, 350, 450);
g_signal_connect(ExternalWindow, "delete_event", G_CALLBACK(ExternalWindow_delete_event), NULL);
VBox1 = GTK_BOX(gtk_vbox_new(FALSE, 0));
gtk_container_add(GTK_CONTAINER(ExternalWindow), GTK_WIDGET(VBox1));
gtk_widget_show(GTK_WIDGET(VBox1));
// Table
MTable = GTK_TABLE(gtk_table_new(31, 2, FALSE));
gtk_widget_show(GTK_WIDGET(MTable));
// Applications
for (i=0; i<10; i++) {
sprintf(tmp, "App. %i Name:", i+1);
MLabelTitle[i] = GTK_LABEL(gtk_label_new(tmp));
gtk_misc_set_alignment(GTK_MISC(MLabelTitle[i]), 1.0, 0.5);
gtk_table_attach(MTable, GTK_WIDGET(MLabelTitle[i]), 0, 1, i*3, i*3+1, GTK_FILL, GTK_FILL, 2, 2);
gtk_widget_show(GTK_WIDGET(MLabelTitle[i]));
MEntryTitle[i] = GTK_ENTRY(gtk_entry_new());
gtk_table_attach(MTable, GTK_WIDGET(MEntryTitle[i]), 1, 2, i*3, i*3+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 2);
gtk_widget_show(GTK_WIDGET(MEntryTitle[i]));
sprintf(tmp, "App. %i Command:", i+1);
MLabelExec[i] = GTK_LABEL(gtk_label_new(tmp));
gtk_misc_set_alignment(GTK_MISC(MLabelExec[i]), 1.0, 0.5);
gtk_table_attach(MTable, GTK_WIDGET(MLabelExec[i]), 0, 1, i*3+1, i*3+2, GTK_FILL, GTK_FILL, 2, 2);
gtk_widget_show(GTK_WIDGET(MLabelExec[i]));
MEntryExec[i] = GTK_ENTRY(gtk_entry_new());
gtk_table_attach(MTable, GTK_WIDGET(MEntryExec[i]), 1, 2, i*3+1, i*3+2, GTK_FILL | GTK_EXPAND, GTK_FILL, 2, 2);
gtk_widget_show(GTK_WIDGET(MEntryExec[i]));
MCurrDir[i] = GTK_TOGGLE_BUTTON(gtk_check_button_new_with_label("Launch from current directory"));
gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(MCurrDir[i]), TRUE);
gtk_table_attach(MTable, GTK_WIDGET(MCurrDir[i]), 1, 2, i*3+2, i*3+3, GTK_FILL, GTK_FILL, 2, 2);
gtk_widget_show(GTK_WIDGET(MCurrDir[i]));
}
LabelDesc = GTK_LABEL(gtk_label_new(
"Special keywords for command:\n"
" %% = % character\n"
" %X = Executable path\n"
" %C = Current path\n"
" %R = ROM filename, with path\n"
" %r = ROM filename\n"
" %F = ROM filename, no path\n"
" %f = ROM filename, no path, no extension\n"
" %N = ROM filename, with path, no extension\n"
" %n = ROM filename, no extension\n"
" %p = ROM path only, without slash\n"
" %P = ROM path only, with slash\n"
));
gtk_misc_set_alignment(GTK_MISC(LabelDesc), 0.0, 0.5);
gtk_table_attach(MTable, GTK_WIDGET(LabelDesc), 0, 2, i*3, i*3+1, GTK_FILL | GTK_EXPAND, GTK_FILL, 12, 8);
gtk_widget_show(GTK_WIDGET(LabelDesc));
// Scrolling window
ExternalSW = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
gtk_scrolled_window_set_policy(ExternalSW, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_add_with_viewport(ExternalSW, GTK_WIDGET(MTable));
gtk_container_add(GTK_CONTAINER(VBox1), GTK_WIDGET(ExternalSW));
gtk_widget_show(GTK_WIDGET(ExternalSW));
// Horizontal buttons box and they buttons
HButtonBox = GTK_BUTTON_BOX(gtk_hbutton_box_new());
gtk_button_box_set_layout(GTK_BUTTON_BOX(HButtonBox), GTK_BUTTONBOX_END);
gtk_box_set_spacing(GTK_BOX(HButtonBox), 4);
gtk_box_pack_start(VBox1, GTK_WIDGET(HButtonBox), FALSE, TRUE, 4);
gtk_widget_show(GTK_WIDGET(HButtonBox));
ButtonOk = GTK_BUTTON(gtk_button_new_with_label("OK"));
g_signal_connect(ButtonOk, "clicked", G_CALLBACK(ExternalWindow_ButtonOk_clicked), NULL);
gtk_container_add(GTK_CONTAINER(HButtonBox), GTK_WIDGET(ButtonOk));
gtk_widget_show(GTK_WIDGET(ButtonOk));
ButtonCancel = GTK_BUTTON(gtk_button_new_with_label("Cancel"));
g_signal_connect(ButtonCancel, "clicked", G_CALLBACK(ExternalWindow_ButtonCancel_clicked), NULL);
gtk_container_add(GTK_CONTAINER(HButtonBox), GTK_WIDGET(ButtonCancel));
gtk_widget_show(GTK_WIDGET(ButtonCancel));
// Initialize command-line strings
for (i=0; i<10; i++) {
strcpy(dclc_extapp_title[i], "---");
strcpy(dclc_extapp_exec[i], "");
dclc_extapp_atcurrdir[i] = 0;
}
strcpy(dclc_extapp_title[8], "Color Mapper");
strcpy(dclc_extapp_exec[8], "\"%X/color_mapper\" \"%R\"");
dclc_extapp_atcurrdir[8] = 1;
#ifdef _WIN32
strcpy(dclc_extapp_title[9], "Shell (Win2K)");
strcpy(dclc_extapp_exec[9], "cmd");
dclc_extapp_atcurrdir[9] = 1;
#else
strcpy(dclc_extapp_title[9], "Terminal (Linux)");
strcpy(dclc_extapp_exec[9], "xterm");
dclc_extapp_atcurrdir[9] = 1;
#endif
return 1;
}
void ExternalWindow_Destroy(void)
{
}
void ExternalWindow_Activate(GtkItemFactory *itemfact)
{
CPUItemFactory = itemfact;
gtk_widget_show(GTK_WIDGET(ExternalWindow));
gtk_window_present(ExternalWindow);
}
void ExternalWindow_UpdateConfigs(void)
{
int i;
ExternalWindow_InConfigs = 1;
// Setup entries
for (i=0; i<10; i++) {
gtk_entry_set_text(MEntryTitle[i], dclc_extapp_title[i]);
gtk_entry_set_text(MEntryExec[i], dclc_extapp_exec[i]);
gtk_toggle_button_set_active(MCurrDir[i], dclc_extapp_atcurrdir[i]);
}
ExternalWindow_InConfigs = 0;
}
void ExternalWindow_UpdateMenu(GtkItemFactory *itemfact)
{
char tmp[PMTMPV];
GtkWidget *widg;
int i;
for (i=0; i<10; i++) {
sprintf(tmp, "/External/App%i", i+1);
widg = gtk_item_factory_get_item(itemfact, tmp);
gtk_menu_item_set_label(GTK_MENU_ITEM(widg), dclc_extapp_title[i]);
}
}