From 683ddffaa0940d7c8b792d790c617e6950ce7a1a Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Wed, 2 Mar 2022 23:37:18 -0500 Subject: [PATCH] Initial commit --- .gitignore | 18 ++++++ .gitmodules | 3 + Makefile.am | 51 ++++++++++++++++ common | 1 + configure.ac | 39 ++++++++++++ m4/.gitignore | 5 ++ src/.gitignore | 2 + src/motif.c | 142 +++++++++++++++++++++++++++++++++++++++++++ src/motif.h | 26 ++++++++ src/motif_ui.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++ src/motifgui.dat | 7 +++ src/options.opt | 17 ++++++ 12 files changed, 464 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Makefile.am create mode 160000 common create mode 100644 configure.ac create mode 100644 m4/.gitignore create mode 100644 src/.gitignore create mode 100644 src/motif.c create mode 100644 src/motif.h create mode 100644 src/motif_ui.c create mode 100644 src/motifgui.dat create mode 100644 src/options.opt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa34998 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +*.a +*.o +.deps +.dirstamp +/Makefile +/Makefile.in +/aclocal.m4 +/autom4te.cache +/compile +/config.* +/configure +/depcomp +/install-sh +/libtool +/ltmain.sh +/missing +/rrace-motif +/stamp-h1 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a0019b3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "common"] + path = common + url = https://git.draconx.ca/dxcommon.git diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..96e7340 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,51 @@ +# Copyright © 2022 Nick Bowler +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +ACLOCAL_AMFLAGS = -I m4 -I common/m4 + +EXTRA_DIST = +EXTRA_LIBRARIES = +MAINTAINERCLEANFILES = +DISTCLEANFILES = +CLEANFILES = $(EXTRA_LIBRARIES) + +AM_CPPFLAGS = -I$(DX_BASEDIR)/src +AM_CFLAGS = $(MOTIF_CFLAGS) + +bin_PROGRAMS = rrace-motif + +rrace_motif_SOURCES = #src/motif.c common/src/help.c +rrace_motif_LDADD = $(libmotifmain_a_OBJECTS) $(libmotifui_a_OBJECTS) \ + $(libglohelp_a_OBJECTS) $(MOTIF_LIBS) + +EXTRA_LIBRARIES += libmotifmain.a +libmotifmain_a_SOURCES = src/motif.c +$(libmotifmain_a_OBJECTS): src/options.h + +EXTRA_LIBRARIES += libmotifui.a +libmotifui_a_SOURCES = src/motif_ui.c +$(libmotifui_a_OBJECTS): src/motifgui.h + +EXTRA_LIBRARIES += libglohelp.a +libglohelp_a_SOURCES = common/src/help.c +libglohelp_a_CFLAGS = -DHELP_GETOPT_LONG_ONLY +libglohelp_a_SHORTNAME = glo + +OPTFILES = src/options.opt +.opt.h: + $(AM_V_GEN) $(AWK) -f $(DX_BASEDIR)/scripts/gen-options.awk $< >$@.tmp + $(AM_V_at) mv -f $@.tmp $@ +$(OPTFILES:.opt=.h): $(DX_BASEDIR)/scripts/gen-options.awk +DISTCLEANFILES += $(OPTFILES:.opt=.h) +EXTRA_DIST += $(DX_BASEDIR)/scripts/gen-options.awk $(OPTFILES) + +GUIFILES = src/motifgui.dat +.dat.h: + $(AM_V_GEN) $(AWK) -f $(DX_BASEDIR)/scripts/gen-tree.awk $< >$@.tmp + $(AM_V_at) mv -f $@.tmp $@ +$(GUIFILES:.dat=.h): $(DX_BASEDIR)/scripts/gen-tree.awk +DISTCLEANFILES += $(GUIFILES:.dat=.h) +EXTRA_DIST += $(DX_BASEDIR)/scripts/gen-tree.awk $(GUIFILES) diff --git a/common b/common new file mode 160000 index 0000000..a7cabb5 --- /dev/null +++ b/common @@ -0,0 +1 @@ +Subproject commit a7cabb5d0f067e78afd029d8ec41d14660d8f9e2 diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..fb7dd41 --- /dev/null +++ b/configure.ac @@ -0,0 +1,39 @@ +dnl Copyright © 2022 Nick Bowler +dnl +dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2. +dnl This is free software: you are free to do what the fuck you want to. +dnl There is NO WARRANTY, to the extent permitted by law. + +AC_INIT([rrace], [0], [nbowler@draconx.ca]) +AC_CONFIG_HEADERS([config.h]) + +AM_INIT_AUTOMAKE([-Wall -Wno-portability foreign subdir-objects]) +AM_SILENT_RULES([yes]) +DX_AUTOMAKE_COMPAT + +AC_PROG_CC_C99 +LT_INIT + +AC_PATH_XTRA +AS_IF([test x"$no_x" != x"yes"], +[AC_CACHE_CHECK([for Motif], [dx_cv_have_motif], +[save_CFLAGS=$CFLAGS save_LIBS=$LIBS +dx_cv_motif_cflags="$X_CFLAGS" +dx_cv_motif_libs="$X_LIBS $X_PRE_LIBS -lXm -lXt -lX11 $X_EXTRA_LIBS" +CFLAGS="$dx_cv_motif_cflags $CFLAGS" +LIBS="$dx_cv_motif_libs $LIBS" +AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [XmCreateMainWindow(0, 0, 0, 0); XtAppSetExitFlag(0)])], + [dx_cv_have_motif=yes], [dx_cv_have_motif=no]) +CFLAGS=$save_CFLAGS LIBS=$save_LIBS])]) + +AS_IF([test x"$with_x" = x"yes" && test "$dx_cv_have_motif" != x"yes"], + [AC_MSG_FAILURE([--with-x requested but Motif was not found])]) + +AC_SUBST([MOTIF_CFLAGS], [@&t@]) +AC_SUBST([MOTIF_LIBS], [@&t@]) +AS_IF([test x"$dx_cv_have_motif" = x"yes"], + [MOTIF_CFLAGS=$dx_cv_motif_cflags MOTIF_LIBS=$dx_cv_motif_libs]) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..94e6f26 --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,5 @@ +/libtool.m4 +/ltoptions.m4 +/ltsugar.m4 +/ltversion.m4 +/lt~obsolete.m4 diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..7537698 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,2 @@ +/motifgui.h +/options.h diff --git a/src/motif.c b/src/motif.c new file mode 100644 index 0000000..cce9f3f --- /dev/null +++ b/src/motif.c @@ -0,0 +1,142 @@ +/* + * X11 GUI for slide puzzle game + * Copyright © 2022 Nick Bowler + * + * 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 . + */ + +#include +#include +#include +#include + +#include + +#include "help.h" +#include "motif.h" +#include "options.h" + +#define PROGNAME "rrace" +static const char *progname = PROGNAME; +static const struct option lopts[] = { LOPTS_INITIALIZER, {0} }; + +static char * const default_resources[] = { + PROGNAME "*game.height: 371", // 365 + 2*shadowThickness + PROGNAME "*game.width: 498", + + PROGNAME "*game.XmFrame.shadowThickness: 3", + PROGNAME "*game.XmFrame.shadowType: shadow_in", + PROGNAME "*goalArea.leftOffset: 1", + + NULL +}; + +static void print_version(void) +{ + printf("%s %s\n", PROGNAME, PACKAGE_VERSION); + printf("Copyright (C) 2022 Nick Bowler\n"); + puts("License GPLv3+: GNU GPL version 3 or any later version"); + puts("This is free software: you are free to change and redistribute it."); + puts("There is NO WARRANTY, to the extent permitted by law."); +} + +static void print_usage(FILE *f) +{ + fprintf(f, "Usage: %s [options]\n", progname); + if (f != stdout) + fprintf(f, "Try %s --help for more information.\n", progname); +} + +static void print_help(void) +{ + const struct option *opt; + + print_usage(stdout); + + putchar('\n'); + puts("Options:"); + for (opt = lopts; opt->name; opt++) { + struct lopt_help help; + int w; + + if (!lopt_get_help(opt, &help)) + continue; + help_print_option(opt, help.arg, help.desc, 20); + } + putchar('\n'); + + printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT); +} + +static Widget early_setup(XtAppContext *app, int argc, char **argv) +{ + Widget shell; + int opt; + + /* Check for --help/--version early (before X connection) */ + opterr = 0; + while ((opt = getopt_long_only(argc, argv, "", lopts, NULL)) != -1) { + switch (opt) { + case LOPT_VERSION: + print_version(); + exit(EXIT_SUCCESS); + case LOPT_HELP: + print_help(); + exit(EXIT_SUCCESS); + } + } + + shell = XtOpenApplication(app, PROGNAME, NULL, 0, + &argc, argv, (String *)default_resources, + sessionShellWidgetClass, NULL, 0); + + opterr = optind = 1; + while ((opt = getopt_long_only(argc, argv, "", lopts, NULL)) != -1) { + switch (opt) { + default: + print_usage(stderr); + exit(EXIT_FAILURE); + } + } + + if (argv[optind]) { + fprintf(stderr, "%s: excess command-line arguments.\n", + progname); + print_usage(stderr); + exit(EXIT_FAILURE); + } + + return shell; +} + +static XtAppContext app_initialize(int argc, char **argv) +{ + XtAppContext app; + Widget shell; + + if (argc > 0) + progname = argv[0]; + + shell = early_setup(&app, argc, argv); + ui_initialize(shell); + XtRealizeWidget(shell); + + return app; +} + +int main(int argc, char **argv) +{ + XtAppMainLoop(app_initialize(argc, argv)); + return 0; +} diff --git a/src/motif.h b/src/motif.h new file mode 100644 index 0000000..f337618 --- /dev/null +++ b/src/motif.h @@ -0,0 +1,26 @@ +/* + * X11 GUI for slide puzzle game + * Copyright © 2022 Nick Bowler + * + * 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 . + */ + +#ifndef RRACE_MOTIF_H_ +#define RRACE_MOTIF_H_ + +#include + +void ui_initialize(Widget shell); + +#endif diff --git a/src/motif_ui.c b/src/motif_ui.c new file mode 100644 index 0000000..0708b40 --- /dev/null +++ b/src/motif_ui.c @@ -0,0 +1,153 @@ +/* + * X11 GUI for slide puzzle game + * Copyright © 2022 Nick Bowler + * + * 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 . + */ + +#include +#include +#include +#include + +#include "motif.h" +#include "motifgui.h" + +#define SPLIT_NUMERATOR 75 +#define SPLIT_DENOMINATOR 100 + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static void game_configure(Widget w); + +static const struct ui_widget { + uint_least16_t name; + uint_least16_t subtree; + WidgetClass *class; + void (*configure)(Widget w); +} mainwin[] = { MAINWIN_INITIALIZER }; + +static void +ResizeGameArea(Widget form, XEvent *e, String *args, Cardinal *num_args) +{ + Widget game = XtNameToWidget(form, &tree_strtab[gameArea]); + Widget goal = XtNameToWidget(form, &tree_strtab[goalArea]); + Dimension w, h, gamesz, gameborder, goalsz, goalborder; + int x, y, gap; + + XtVaGetValues(form, XmNwidth, &w, XmNheight, &h, (char *)NULL); + XtVaGetValues(game, XmNshadowThickness, &gameborder, (char *)NULL); + XtVaGetValues(goal, XmNshadowThickness, &goalborder, + XmNleftOffset, &gap, + (char *)NULL); + + gamesz = MIN(h, w * SPLIT_NUMERATOR / SPLIT_DENOMINATOR); + gamesz = 5*( (gamesz - 2*gameborder)/5 ) + 2*gameborder; + + goalsz = MIN(gamesz*3/5, w - gamesz - gap); + goalsz = 3*( (goalsz - 2*goalborder)/3 ) + 2*goalborder; + + x = (w - gamesz - goalsz - gap) / 2; + if (x < 2) x = 0; + + y = (h - gamesz) / 2; + if (y < 3) y = 0; + + XtVaSetValues(game, XmNleftOffset, x, XmNtopOffset, y, (char *)NULL); + XtVaSetValues(game, XmNwidth, gamesz, XmNheight, gamesz, (char *)NULL); + XtVaSetValues(goal, XmNwidth, goalsz, XmNheight, goalsz, (char *)NULL); +} + +static void game_configure(Widget form) +{ + Widget gamearea = XtNameToWidget(form, &tree_strtab[gameArea]); + Widget goalarea = XtNameToWidget(form, &tree_strtab[goalArea]); + XtActionsRec resize_rec; + + assert(gamearea && goalarea); + XtVaSetValues(form, XmNfractionBase, SPLIT_DENOMINATOR, (char *)NULL); + + XtVaSetValues(gamearea, //XmNrightAttachment, XmATTACH_POSITION, + //XmNrightPosition, SPLIT_NUMERATOR, + XmNleftAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_FORM, + (char *)NULL); + + XtVaSetValues(goalarea, XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, gamearea, + XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET, + XmNtopWidget, gamearea, + (char *)NULL); + + resize_rec.string = "ResizeGameArea"; + resize_rec.proc = ResizeGameArea; + XtAppAddActions(XtWidgetToApplicationContext(form), &resize_rec, 1); + XtOverrideTranslations(form, XtParseTranslationTable( + ": ResizeGameArea()\n" + ": ResizeGameArea()\n" + )); +} + +static void +construct_widgets(const struct ui_widget *root, Widget parent, unsigned i) +{ + const struct ui_widget *item; + + for (item = &root[i]; item->name; item++) { + Widget w; + + w = XtCreateWidget(&tree_strtab[item->name], *item->class, + parent, NULL, 0); + if (item->subtree) { + construct_widgets(root, w, item->subtree); + } + + if (item->configure) { + item->configure(w); + } + + XtManageChild(w); + } +} + +static void game_resize(Widget w, void *data, void *cb_data) +{ + Dimension width, height; + + XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, (char *)NULL); + + printf("game %ux%u\n", width, height); +} + +static void goal_resize(Widget w, void *data, void *cb_data) +{ + Dimension width, height; + + XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, (char *)NULL); + + printf("goal %ux%u\n", width, height); +} + +void ui_initialize(Widget shell) +{ + Widget game, goal; + + construct_widgets(mainwin, shell, 0); + + game = XtNameToWidget(shell, "*gameCanvas"); + goal = XtNameToWidget(shell, "*goalCanvas"); + + XtAddCallback(game, XmNresizeCallback, game_resize, NULL); + XtAddCallback(goal, XmNresizeCallback, goal_resize, NULL); +} diff --git a/src/motifgui.dat b/src/motifgui.dat new file mode 100644 index 0000000..a8d69cb --- /dev/null +++ b/src/motifgui.dat @@ -0,0 +1,7 @@ +MAINWIN + main, main_OFFSET, &xmMainWindowWidgetClass + game, game_OFFSET, &xmFormWidgetClass, game_configure + gameArea, gameArea_OFFSET, &xmFrameWidgetClass + gameCanvas, 0, &xmDrawingAreaWidgetClass + goalArea, goalArea_OFFSET, &xmFrameWidgetClass + goalCanvas, 0, &xmDrawingAreaWidgetClass diff --git a/src/options.opt b/src/options.opt new file mode 100644 index 0000000..9fd8240 --- /dev/null +++ b/src/options.opt @@ -0,0 +1,17 @@ +--display=DISPLAY +X server DISPLAY name to use. + +--geometry=[W][xH][+X[+Y]] +Set initial window size (W by H) and/or position (X, Y). + +--title=NAME +Set window title to NAME. + +--xrm=STRING +Set the X resource described by STRING, overriding defaults. + +--version +Print a version message and then exit. + +--help +Print this message and then exit. -- 2.43.2