diff --git a/Makefile.linux b/Makefile.linux index 1aaaf17d9f..873233ae92 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -14,9 +14,9 @@ ifdef GC CFLAGS += -ffunction-sections LDFLAGS += -Wl,--gc-sections endif -CFLAGS += -MMD -DHAVE_FILELENGTH -D__forceinline=inline -Izlib -IFLAC `sdl-config --cflags` +CFLAGS += -MMD -DHAVE_FILELENGTH -D__forceinline=inline -Izlib -IFLAC `sdl-config --cflags` `pkg-config gtk+-2.0 --cflags` CFLAGS += -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DNEED_STRUPR -LDFLAGS += -lFLAC++ -lFLAC -lz -ljpeg -lfmod `sdl-config --libs` +LDFLAGS += -lFLAC++ -lFLAC -lz -ljpeg -lfmod `sdl-config --libs` `pkg-config gtk+-2.0 --libs` NASMFLAGS += -f elf -DM_TARGET_LINUX SRCDIRS = src/ $(addprefix src/,g_doom/ g_heretic/ g_hexen/ g_raven/ g_shared/ g_strife/ oplsynth/ sound/ sdl/ textures/ ) @@ -139,4 +139,4 @@ ccdv: ccdv-posix.c ifeq (,$(findstring $(MAKECMDGOALS),clean cleandeps cleanobjs distclean toolsandpk3 cleantools updaterev)) -include $(DEPS) -endif +endif diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 5e9bfbb2c6..114d2daf14 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,7 @@ +January 15, 2007 +- Added a GTK+ version of the IWAD selection dialog box. That brings the + Linux port one step closer to feature parity with the Windows version. + January 13, 2007 (Changes by Graf Zahl) - Adjusted AlterWeaponSprite so that it properly handles multiple invisibility powerups at the same time. diff --git a/src/sdl/i_main.cpp b/src/sdl/i_main.cpp index e0f4378111..de0b436110 100644 --- a/src/sdl/i_main.cpp +++ b/src/sdl/i_main.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include "doomerrors.h" #include "m_argv.h" @@ -70,6 +71,8 @@ extern "C" int cc_install_handlers(int, int*, const char*, int(*)(char*, char*)) // PUBLIC DATA DEFINITIONS ------------------------------------------------- +bool GtkAvailable; + // The command line arguments. DArgs Args; @@ -187,6 +190,8 @@ int main (int argc, char **argv) seteuid (getuid ()); std::set_new_handler (NewFailure); + GtkAvailable = gtk_init_check (&argc, &argv); + if (SDL_Init (SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE) == -1) { fprintf (stderr, "Could not initialize SDL:\n%s\n", SDL_GetError()); @@ -242,4 +247,4 @@ int main (int argc, char **argv) throw; } return 0; -} +} diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index 3160d9175c..a82c6d6d26 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include "doomerrors.h" #include @@ -70,6 +72,8 @@ extern "C" CPUInfo CPU; } +extern bool GtkAvailable; + void CalculateCPUSpeed (); DWORD LanguageIDs[4] = @@ -338,9 +342,192 @@ void I_PrintStr (const char *cp) fflush (stdout); } -int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad) +// GtkTreeViews eats return keys. I want this to be like a Windows listbox +// where pressing Return can still activate the default button. +gint AllowDefault(GtkWidget *widget, GdkEventKey *event, gpointer func_data) +{ + if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Return) + { + gtk_window_activate_default (GTK_WINDOW(func_data)); + } + return FALSE; +} + +// Double-clicking an entry in the list is the same as pressing OK. +gint DoubleClickChecker(GtkWidget *widget, GdkEventButton *event, gpointer func_data) +{ + if (event->type == GDK_2BUTTON_PRESS) + { + *(int *)func_data = 1; + gtk_main_quit(); + } + return FALSE; +} + +// When the user presses escape, that should be the same as canceling the dialog. +gint CheckEscape (GtkWidget *widget, GdkEventKey *event, gpointer func_data) +{ + if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Escape) + { + gtk_main_quit(); + } + return FALSE; +} + +void ClickedOK(GtkButton *button, gpointer func_data) +{ + *(int *)func_data = 1; + gtk_main_quit(); +} + +EXTERN_CVAR (Bool, queryiwad); + +int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *bbox; + GtkWidget *widget; + GtkWidget *tree; + GtkWidget *check; + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + GtkTreeIter iter, defiter; + int close_style = 0; + int i; + + // Create the dialog window. + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW(window), GAMESIG " " DOTVERSIONSTR ": Select an IWAD to use"); + gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER); + gtk_container_set_border_width (GTK_CONTAINER(window), 10); + g_signal_connect (window, "delete_event", G_CALLBACK(gtk_main_quit), NULL); + g_signal_connect (window, "key_press_event", G_CALLBACK(CheckEscape), NULL); + + // Create the vbox container. + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER(window), vbox); + + // Create the top label. + widget = gtk_label_new ("ZDoom found more than one IWAD\nSelect from the list below to determine which one to use:"); + gtk_box_pack_start (GTK_BOX(vbox), widget, false, false, 0); + gtk_misc_set_alignment (GTK_MISC(widget), 0, 0); + + // Create a list store with all the found IWADs. + store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); + for (i = 0; i < numwads; ++i) + { + const char *filepart = strrchr (wads[i].Path, '/'); + if (filepart == NULL) + filepart = wads[i].Path; + else + filepart++; + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, + 0, filepart, + 1, IWADInfos[wads[i].Type].Name, + 2, i, + -1); + if (i == defaultiwad) + { + defiter = iter; + } + } + + // Create the tree view control to show the list. + tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store)); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("IWAD", renderer, "text", 0, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Game", renderer, "text", 1, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column); + gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(tree), true, true, 0); + g_signal_connect(G_OBJECT(tree), "button_press_event", G_CALLBACK(DoubleClickChecker), &close_style); + g_signal_connect(G_OBJECT(tree), "key_press_event", G_CALLBACK(AllowDefault), window); + + // Select the default IWAD. + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree)); + gtk_tree_selection_select_iter (selection, &defiter); + + // Create the hbox for the bottom row. + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_end (GTK_BOX(vbox), hbox, false, false, 0); + + // Create the "Don't ask" checkbox. + check = gtk_check_button_new_with_label ("Don't ask me this again"); + gtk_box_pack_start (GTK_BOX(hbox), check, false, false, 0); + gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON(check), showwin); + + // Create the OK/Cancel button box. + bbox = gtk_hbutton_box_new (); + gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_box_set_spacing (GTK_BOX(bbox), 10); + gtk_box_pack_end (GTK_BOX(hbox), bbox, false, false, 0); + + // Create the OK button. + widget = gtk_button_new_from_stock (GTK_STOCK_OK); + gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0); + GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT); + gtk_widget_grab_default (widget); + g_signal_connect (widget, "clicked", G_CALLBACK(ClickedOK), &close_style); + g_signal_connect (widget, "activate", G_CALLBACK(ClickedOK), &close_style); + + // Create the cancel button. + widget = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + gtk_box_pack_start (GTK_BOX(bbox), widget, false, false, 0); + g_signal_connect (widget, "clicked", G_CALLBACK(gtk_main_quit), &window); + + // Finally we can show everything. + gtk_widget_show_all (window); + + gtk_main (); + + if (close_style == 1) + { + GtkTreeModel *model; + GValue value = { 0, }; + + // Find out which IWAD was selected. + gtk_tree_selection_get_selected (selection, &model, &iter); + gtk_tree_model_get_value (GTK_TREE_MODEL(model), &iter, 2, &value); + i = g_value_get_int (&value); + g_value_unset (&value); + + // Set state of queryiwad based on the checkbox. + queryiwad = !gtk_toggle_button_get_mode (GTK_TOGGLE_BUTTON(check)); + } + else + { + i = -1; + } + + if (GTK_IS_WINDOW(window)) + { + gtk_widget_destroy (window); + // If we don't do this, then the X window might not actually disappear. + while (g_main_context_iteration (NULL, FALSE)) {} + } + + return i; +} + +int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) { int i; + + if (!showwin) + { + return defaultiwad; + } + + if (GtkAvailable) + { + return I_PickIWad_Gtk (wads, numwads, showwin, defaultiwad); + } printf ("Please select a game wad (or 0 to exit):\n"); for (i = 0; i < numwads; ++i) @@ -444,4 +631,4 @@ void I_PutInClipboard (const char *str) char *I_GetFromClipboard () { return NULL; -} +} diff --git a/src/v_font.cpp b/src/v_font.cpp index 31cfaa5435..d2c167665d 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -1845,7 +1845,7 @@ EColorRange V_FindFontColor (FName name) PalEntry V_LogColorFromColorRange (EColorRange range) { - if (range < 0 || range >= TranslationColors.Size()) + if ((unsigned int)range >= TranslationColors.Size()) { // Return default color return DEFAULT_LOG_COLOR; } @@ -1947,4 +1947,4 @@ void V_InitFonts() } ConFont = new FSingleLumpFont ("ConsoleFont", Wads.GetNumForName ("CONFONT")); V_InitCustomFonts (); -} +}