1/* 2 This file is part of GNOME 2048. 3 4 Copyright (C) 2014-2015 Juan R. García Blanco <juanrgar@gmail.com> 5 Copyright (C) 2016-2019 Arnaud Bonatti <arnaud.bonatti@gmail.com> 6 7 GNOME 2048 is free software: you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation, either version 3 of the License, or 10 (at your option) any later version. 11 12 GNOME 2048 is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GNOME 2048. If not, see <https://www.gnu.org/licenses/>. 19*/ 20 21using Gtk; 22 23private class TwentyFortyEight : Gtk.Application 24{ 25 private GameWindow _window; 26 27 private static bool show_version; 28 private static string? size = null; 29 private static string? cli = null; 30 private uint8 cols = 0; 31 private uint8 rows = 0; 32 33 private const OptionEntry [] option_entries = 34 { 35 /* Translators: command-line option description, see 'gnome-2048 --help' */ 36 { "cli", 0, OptionFlags.OPTIONAL_ARG, OptionArg.CALLBACK, (void*) _cli, N_("Play in the terminal (see “--cli=help”)"), 37 38 /* Translators: in the command-line options description, text to indicate the user should give a command after '--cli' for playing in the terminal, see 'gnome-2048 --help' */ 39 N_("COMMAND") }, 40 41 /* Translators: command-line option description, see 'gnome-2048 --help' */ 42 { "size", 's', OptionFlags.NONE, OptionArg.STRING, ref size, N_("Start new game of given size"), 43 44 /* Translators: in the command-line options description, text to indicate the user should specify a size after '--size', see 'gnome-2048 --help' */ 45 N_("SIZE") }, 46 47 /* Translators: command-line option description, see 'gnome-2048 --help' */ 48 { "version", 'v', OptionFlags.NONE, OptionArg.NONE, ref show_version, N_("Print release version and exit"), null }, 49 {} 50 }; 51 52 private bool _cli (string? option_name, string? val) 53 { 54 cli = option_name == null ? "" : (!) option_name; // TODO report bug: should probably be val... 55 return true; 56 } 57 58 private const GLib.ActionEntry [] action_entries = 59 { 60 { "quit", quit_cb } 61 }; 62 63 private static int main (string [] args) 64 { 65 Intl.setlocale (LocaleCategory.ALL, ""); 66 Intl.bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); 67 Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); 68 Intl.textdomain (GETTEXT_PACKAGE); 69 70 OptionContext context = new OptionContext (""); 71 context.add_main_entries (option_entries, GETTEXT_PACKAGE); 72 73 context.add_group (get_option_group (true)); 74 context.add_group (Clutter.get_option_group_without_init ()); 75 76 try { 77 context.parse (ref args); 78 } catch (Error e) { 79 stderr.printf ("%s\n", e.message); 80 return Posix.EXIT_FAILURE; 81 } 82 83 const string application_name = "org.gnome.TwentyFortyEight"; 84 Environment.set_application_name (application_name); 85 Environment.set_prgname ("org.gnome.TwentyFortyEight"); 86 Window.set_default_icon_name ("org.gnome.TwentyFortyEight"); 87 88 try { 89 GtkClutter.init_with_args (ref args, "", new OptionEntry[0], null); 90 } catch (Error e) { 91 MessageDialog dialog = new MessageDialog (null, 92 DialogFlags.MODAL, 93 MessageType.ERROR, 94 ButtonsType.NONE, 95 "Unable to initialize Clutter:\n%s", e.message); 96 dialog.set_title (application_name); 97 dialog.run (); 98 dialog.destroy (); 99 return Posix.EXIT_FAILURE; 100 } 101 102 TwentyFortyEight app = new TwentyFortyEight (); 103 return app.run (args); 104 } 105 106 private TwentyFortyEight () 107 { 108 Object (application_id: "org.gnome.TwentyFortyEight", flags: ApplicationFlags.FLAGS_NONE); 109 } 110 111 protected override int handle_local_options (GLib.VariantDict options) // options will be empty, we used a custom OptionContext 112 { 113 if (show_version) 114 { 115 /* NOTE: Is not translated so can be easily parsed */ 116 stdout.printf ("%1$s %2$s\n", "gnome-2048", VERSION); 117 return Posix.EXIT_SUCCESS; 118 } 119 120 if (size != null && !CLI.parse_size ((!) size, out cols, out rows)) 121 { 122 /* Translators: command-line error message, displayed for an incorrect game size request; try 'gnome-2048 -s 0' */ 123 stderr.printf ("%s\n", _("Failed to parse size. Size must be between 2 and 9, or in the form 2x3.")); 124 return Posix.EXIT_FAILURE; 125 } 126 127 if (cli != null) 128 { 129 if ((!) cli == "help" || (!) cli == "HELP") 130 { 131 string help_string = "" 132 + "\n" + "To play GNOME 2048 in command-line:" 133 + "\n" + " --cli " + "Display current game. Alias: “status” or “show”." 134 + "\n" + " --cli new " + "Start a new game; for changing size, use --size." 135 + "\n" 136 + "\n" + " --cli up " + "Move tiles up. Alias: “u”." 137 + "\n" + " --cli down " + "Move tiles down. Alias: “d”." 138 + "\n" + " --cli left " + "Move tiles left. Alias: “l”." 139 + "\n" + " --cli right " + "Move tiles right. Alias: “r”." 140 + "\n\n"; 141 stdout.printf (help_string); 142 return Posix.EXIT_SUCCESS; 143 } 144 return CLI.play_cli ((!) cli, "org.gnome.TwentyFortyEight", ref cols, ref rows); 145 } 146 147 /* Activate */ 148 return -1; 149 } 150 151 protected override void startup () 152 { 153 base.startup (); 154 155 add_action_entries (action_entries, this); 156 157 _window = new GameWindow (this, cols, rows); 158 159 set_accels_for_action ("ui.toggle-new-game", { "<Primary>n" }); 160 set_accels_for_action ("ui.new-game", { "<Shift><Primary>n" }); 161 set_accels_for_action ("app.quit", { "<Primary>q" }); 162 set_accels_for_action ("ui.undo", { "<Primary>z" }); 163 set_accels_for_action ("ui.about", { "<Shift>F1", 164 "<Shift><Primary>F1" }); // as usual, this second shortcut does not work 165 set_accels_for_action ("win.show-help-overlay", { "F1", 166 "<Primary>F1", 167 "<Primary>question", 168 "<Shift><Primary>question"}); 169 set_accels_for_action ("ui.toggle-hamburger", { "F10", 170 "Menu" }); 171 } 172 173 protected override void activate () 174 { 175 _window.present (); 176 } 177 178 private void quit_cb (/* SimpleAction action, Variant? variant */) 179 { 180 _window.destroy (); 181 } 182} 183