klavaro  3.13
About: Klavaro is a touch typing tutor program.
  Fossies Dox: klavaro-3.13.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

main.c
Go to the documentation of this file.
1 /**************************************************************************/
2 /* Klavaro - a flexible touch typing tutor */
3 /* Copyright (C) 2005-2021 Felipe Emmanuel Ferreira de Castro */
4 /* */
5 /* This file is part of Klavaro, which is a free software: you can */
6 /* redistribute it and/or modify it under the terms of the GNU General */
7 /* Public License as published by the Free Software Foundation, either */
8 /* version 3 of the License, or (at your option) any later version. */
9 /* */
10 /* Klavaro is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU General Public License for more details (in the file COPYING). */
14 /* You should have received a copy of the GNU General Public License */
15 /* along with Klavaro. If not, see <https://www.gnu.org/licenses/> */
16 /**************************************************************************/
17 
18 #include <string.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <glib.h>
22 #include <glib/gstdio.h>
23 #include <pango/pango-attributes.h>
24 #include <gtk/gtk.h>
25 #include <curl/curl.h>
26 
27 #include "auxiliar.h"
28 #include "callbacks.h"
29 #include "translation.h"
30 #include "keyboard.h"
31 #include "tutor.h"
32 #include "accuracy.h"
33 #include "top10.h"
34 #include "main.h"
35 
36 /*******************************************************************************
37  * Variables
38  */
39 GtkBuilder *gui;
40 
41 gchar *KEYB_CUSTOM;
42 gchar *KEYB_EDIT;
44 
45 static GKeyFile *preferences = NULL;
46 static GKeyFile *altcolor = NULL;
47 static gboolean curl_ok;
48 static gboolean velo_txt;
49 static struct
50 {
51  gchar *user;
52  gchar *stats;
53  gchar *data;
54  gchar *score;
55 } path;
56 
57 /*******************************************************************************
58  * Interface functions
59  */
60 gchar *
62 {
63  return (path.user);
64 }
65 
66 gchar *
68 {
69  return (path.stats);
70 }
71 
72 gchar *
74 {
75  return (path.data);
76 }
77 
78 gchar *
80 {
81  return (path.score);
82 }
83 
84 gboolean
86 {
87  return (curl_ok);
88 }
89 
90 gboolean
92 {
93  return (velo_txt);
94 }
95 
96 gboolean
97 main_preferences_exist (gchar * group, gchar * key)
98 {
99  return (g_key_file_has_key (preferences, group, key, NULL));
100 }
101 
102 void
103 main_preferences_remove (gchar * group, gchar * key)
104 {
105  g_key_file_remove_key (preferences, group, key, NULL);
106 }
107 
108 gchar *
109 main_preferences_get_string (gchar * group, gchar * key)
110 {
111  return (g_key_file_get_string (preferences, group, key, NULL));
112 }
113 
114 void
115 main_preferences_set_string (gchar * group, gchar * key, gchar * value)
116 {
117  g_key_file_set_string (preferences, group, key, value);
118 }
119 
120 gint
121 main_preferences_get_int (gchar * group, gchar * key)
122 {
123  return (g_key_file_get_integer (preferences, group, key, NULL));
124 }
125 
126 void
127 main_preferences_set_int (gchar * group, gchar * key, gint value)
128 {
129  g_key_file_set_integer (preferences, group, key, value);
130 }
131 
132 gboolean
133 main_preferences_get_boolean (gchar * group, gchar * key)
134 {
135  return (g_key_file_get_boolean (preferences, group, key, NULL));
136 }
137 
138 void
139 main_preferences_set_boolean (gchar * group, gchar * key, gboolean value)
140 {
141  g_key_file_set_boolean (preferences, group, key, value);
142 }
143 
144 gboolean
145 main_altcolor_exist (gchar * group, gchar * key)
146 {
147  return (g_key_file_has_key (altcolor, group, key, NULL));
148 }
149 
150 gchar *
151 main_altcolor_get_string (gchar * group, gchar * key)
152 {
153  return (g_key_file_get_string (altcolor, group, key, NULL));
154 }
155 
156 
157 gboolean
158 main_altcolor_get_boolean (gchar * group, gchar * key)
159 {
160  return (g_key_file_get_boolean (altcolor, group, key, NULL));
161 }
162 
163 void
164 main_altcolor_set_boolean (gchar * group, gchar * key, gboolean value)
165 {
166  g_key_file_set_boolean (altcolor, group, key, value);
167 }
168 
169 void
171 {
172  gchar *tmp_name;
173  FILE *fh;
174 
175  /* Save preferences
176  */
177  assert_user_dir ();
178  tmp_name = g_build_filename (main_path_user (), "preferences.ini", NULL);
179  fh = (FILE *) g_fopen (tmp_name, "w");
180  if (fh == NULL)
181  g_warning ("couldn't save your preferences at the user folder:\n %s", tmp_name);
182  else
183  {
184  g_free (tmp_name);
185  tmp_name = NULL;
186  tmp_name = g_key_file_to_data (preferences, NULL, NULL);
187  if (tmp_name != NULL)
188  fputs (tmp_name, fh);
189  else
190  g_warning ("no preferences to be saved!");
191  fclose (fh);
192  }
193  g_free (tmp_name);
194 
195  /* Save altcolor
196  */
197  tmp_name = g_build_filename (main_path_user (), "altcolor.ini", NULL);
198  fh = (FILE *) g_fopen (tmp_name, "w");
199  if (fh == NULL)
200  g_warning ("couldn't save your altcolor file at the user folder:\n %s", tmp_name);
201  else
202  {
203  g_free (tmp_name);
204  tmp_name = NULL;
205  tmp_name = g_key_file_to_data (altcolor, NULL, NULL);
206  if (tmp_name != NULL)
207  fputs (tmp_name, fh);
208  else
209  g_warning ("no altcolors to be saved!");
210  fclose (fh);
211  }
212  g_free (tmp_name);
213 }
214 
215 /*
216  * End of interface, start of private functions
217  */
218 
219 /**********************************************************************
220  * Initialize the value of the global variables
221  */
222 static void
224 {
225  gchar *tmp;
226  FILE *fh;
227 
228  /* Set the home user dir
229  */
230  path.user = g_build_filename (g_get_user_config_dir (), "klavaro", NULL);
231  if (!g_file_test (path.user, G_FILE_TEST_IS_DIR))
232  {
233  if (g_mkdir_with_parents (path.user, DIR_PERM) == -1)
234  g_error ("Sorry, not able to create the user config dir: %s", path.user);
235  }
236 
237  /* Set the home user stats dir (~/.local/share dir)
238  */
239  if (UNIX_OK)
240  path.stats = g_build_filename (g_get_user_data_dir (), "klavaro", NULL);
241  else
242  path.stats = g_build_filename (g_get_user_config_dir (), "klavaro", NULL);
243  if (!g_file_test (path.stats, G_FILE_TEST_IS_DIR))
244  {
245  g_mkdir_with_parents (path.stats, DIR_PERM);
246  }
247 
248  /* Get a valid data path.
249  * First searches the path at the source directory.
250  */
251  path.data = g_build_filename ("..", "data", NULL);
252  tmp = g_build_filename (path.data, "basic_lessons.txt", NULL);
253  if (!g_file_test (tmp, G_FILE_TEST_EXISTS))
254  {
255  g_free (path.data);
256  g_free (tmp);
257  path.data = g_build_filename (PACKAGE_DATA_DIR, PACKAGE, NULL);
258  tmp = g_build_filename (path.data, "basic_lessons.txt", NULL);
259  }
260  if (! g_file_test (tmp, G_FILE_TEST_EXISTS))
261  g_error ("couldn't find a data file at the data path:\n %s", tmp);
262  g_free (tmp);
263 
264  /* Get a valid scoring path.
265  */
266  path.score = g_build_filename (path.stats, "ksc", NULL);
267  if (!g_file_test (path.score, G_FILE_TEST_IS_DIR))
268  {
269  g_mkdir_with_parents (path.score, DIR_PERM);
270  }
271 
272  /* Retrieve saved preferences or initial one
273  */
274  preferences = g_key_file_new ();
275  tmp = g_build_filename (main_path_user (), "preferences.ini", NULL);
276  if (!g_file_test (tmp, G_FILE_TEST_EXISTS))
277  {
278  g_free (tmp);
279  tmp = g_strdup ("/etc/klavaro/preferences.ini");
280  }
281  g_key_file_load_from_file (preferences, tmp, G_KEY_FILE_NONE, NULL);
282  g_free (tmp);
283 
284  /* Retrieve saved alternative colors or initial ones
285  */
286  altcolor = g_key_file_new ();
287  tmp = g_build_filename (main_path_user (), "altcolor.ini", NULL);
288  if (!g_file_test (tmp, G_FILE_TEST_EXISTS))
289  {
290  g_free (tmp);
291  tmp = g_build_filename ("/etc/klavaro/altcolor.ini", NULL);
292  }
293  if (!g_file_test (tmp, G_FILE_TEST_EXISTS))
294  {
295  g_free (tmp);
296  tmp = g_build_filename (main_path_data (), "altcolor.ini", NULL);
297  }
298  g_key_file_load_from_file (altcolor, tmp, G_KEY_FILE_NONE, NULL);
299  g_free (tmp);
300 
301  /* Other initializations
302  */
305  srand (time (0));
307 
308  KEYB_CUSTOM = g_strdup (_("(Custom)"));
309  KEYB_EDIT = g_strdup (_("(Edit custom)"));
310  OTHER_DEFAULT = g_strdup (_("(Default)"));
311 }
312 
313 static void
315 {
316  gchar *lb;
317  GSList *ls;
318  GSList *it;
319  GtkWidget *wg;
320 
321  ls = gtk_builder_get_objects (gui);
322  it = ls;
323  do
324  {
325  if (G_OBJECT_TYPE (it->data) == GTK_TYPE_LABEL)
326  {
327  lb = (gchar *) gtk_label_get_label (GTK_LABEL (it->data));
328  if (lb[0] != '\0')
329  gtk_label_set_text_with_mnemonic (GTK_LABEL (it->data), _(lb));
330  }
331  else if (G_OBJECT_TYPE (it->data) == GTK_TYPE_ENTRY)
332  {
333  lb = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (it->data), GTK_ENTRY_ICON_SECONDARY);
334  if (lb)
335  {
336  if (lb[0] != '\0')
337  gtk_entry_set_icon_tooltip_text (GTK_ENTRY (it->data), GTK_ENTRY_ICON_SECONDARY, _(lb));
338  }
339  }
340  else if (G_OBJECT_TYPE (it->data) == GTK_TYPE_WINDOW)
341  gtk_window_set_title (GTK_WINDOW (it->data), _(gtk_window_get_title (GTK_WINDOW (it->data))));
342 
343  if (GTK_IS_WIDGET (it->data))
344  {
345  wg = GTK_WIDGET (it->data);
346  if (gtk_widget_get_has_tooltip (wg))
347  gtk_widget_set_tooltip_text (wg, _(gtk_widget_get_tooltip_text (wg)));
348  }
349 
350  it = g_slist_next (it);
351  } while (it);
352 
353  g_slist_free (ls);
354 }
355 
356 /*******************************************************************************
357  * Initialize some interface widgets
358  */
359 static void
361 {
362  gchar *tmp = NULL;
363  gchar *ttip = NULL;
364  PangoAttrList *palist;
365 
366  /* Workaround to make GtkBuilder translate all text, on Windows :-(
367  */
368  if (! UNIX_OK)
370 
371  /* Set the language
372  */
374 
375  /* Set keyboard
376  */
378  hints_init ();
379 
380  /* Set if speech is enabled
381  */
382  callbacks_shield_set (TRUE);
383  if (!main_preferences_exist ("interface", "speech"))
384  main_preferences_set_boolean ("interface", "speech", TRUE);
385  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (get_wg ("checkbutton_speech")),
386  main_preferences_get_boolean ("interface", "speech"));
387  tmp = g_strdup (dngettext (PACKAGE, "Dictation mode (depends on this speech synthesizer: %s)",
388  "Dictation mode (depends on one of these speech synthesizers: %s)", 1));
389  ttip = g_strdup_printf (tmp, "Espeak");
390  g_free (tmp);
391  gtk_widget_set_tooltip_text (get_wg ("checkbutton_speech"), ttip);
392  callbacks_shield_set (FALSE);
393 
394  /* Set the initial keyboard to use
395  */
396  keyb_set_combo_kbd ("combobox_kbd_country", "combobox_kbd_variant");
397  keyb_set_combo_kbd ("combobox_keyboard_country", "combobox_keyboard_variant");
398 
399  /* Set window icons
400  */
401  gtk_window_set_default_icon_name ("klavaro");
402 
403  /* Set pixmaps
404  */
405  set_pixmap ("image_altcolor", "altcolor.png");
406  set_pixmap ("image_fluid", "fluid.png");
407  set_pixmap ("image_keyboard", "key.png");
408  set_pixmap ("image_other", "other.png");
409  set_pixmap ("image_progress", "progress.png");
410  set_pixmap ("image_top10", "top10.png");
411 
412  /* Set Top10 TreeViews and Combo
413  */
414  top10_init ();
415 
416  /* Set big and bold labels
417  */
418  pango_parse_markup ("<big><b>----------------------------------------------------------------</b></big>",
419  -1, 0, &palist, NULL, NULL, NULL);
420  gtk_label_set_attributes (GTK_LABEL (get_wg ("label_keyboard_title")), palist);
421  gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_intro")), palist);
422  gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_basic")), palist);
423  gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_adapt")), palist);
424  gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_velo")), palist);
425  gtk_label_set_attributes (GTK_LABEL (get_wg ("label_main_fluid")), palist);
426 
427  /* Set main labels (for translation)
428  */
429  tmp = g_strdup_printf ("0 - %s", _("Introduction"));
430  gtk_label_set_text (GTK_LABEL (get_wg ("label_main_intro")), tmp);
431  g_free (tmp);
432  tmp = g_strdup_printf ("1 - %s", _("Basic course"));
433  gtk_label_set_text (GTK_LABEL (get_wg ("label_main_basic")), tmp);
434  g_free (tmp);
435  tmp = g_strdup_printf ("2 - %s", _("Adaptability"));
436  gtk_label_set_text (GTK_LABEL (get_wg ("label_main_adapt")), tmp);
437  g_free (tmp);
438  if (velo_txt)
439  tmp = g_strdup_printf ("3 - %s (TXT)", _("Speed"));
440  else
441  tmp = g_strdup_printf ("3 - %s", _("Speed"));
442  gtk_label_set_text (GTK_LABEL (get_wg ("label_main_velo")), tmp);
443  g_free (tmp);
444  tmp = g_strdup_printf ("4 - %s", _("Fluidity"));
445  gtk_label_set_text (GTK_LABEL (get_wg ("label_main_fluid")), tmp);
446  g_free (tmp);
447 
448  /* Set version
449  */
450  gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (get_obj ("aboutdialog")), VERSION);
451 
452  /* For remembering the window's position
453  */
454  gtk_widget_show (get_wg ("window_main"));
455  window_restore ("main");
456 
457  /* Altcolor toggle button
458  */
459  if (!main_altcolor_exist ("colors", "altcolor"))
460  main_altcolor_set_boolean ("colors", "altcolor", FALSE);
461  if (main_altcolor_get_boolean ("colors", "altcolor") == TRUE)
462  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (get_wg ("togglebutton_altcolor")), TRUE);
463 
464  /* Run last used module
465  */
466  if (!main_preferences_exist ("interface", "autostart"))
467  main_preferences_set_boolean ("interface", "autostart", FALSE);
468  if (!main_preferences_exist ("interface", "exercise"))
469  main_preferences_set_int ("interface", "exercise", 1);
470  if (main_preferences_get_boolean ("interface", "autostart"))
471  {
472  switch (main_preferences_get_int ("interface", "exercise"))
473  {
474  case TT_BASIC:
475  on_button_basic_clicked (NULL, NULL);
476  break;
477  case TT_ADAPT:
478  on_button_adapt_clicked (NULL, NULL);
479  break;
480  case TT_VELO:
481  on_button_velo_clicked (NULL, NULL);
482  break;
483  case TT_FLUID:
484  on_button_fluid_clicked (NULL, NULL);
485  break;
486  }
487  }
488 
489  /* Set accuracy accumulators
490  */
491  accur_init ();
492 }
493 
494 /*******************************************************************************
495  * Main program
496  */
497 int
498 main (int argc, char *argv[])
499 {
500  gchar *tmp;
501  gboolean success = FALSE;
502  gboolean show_version = FALSE;
503  GOptionContext *opct;
504  GOptionEntry option[] = {
505  {"version", 'v', 0, G_OPTION_ARG_NONE, &show_version, "Version", NULL},
506  {"velotxt", 'x', 0, G_OPTION_ARG_NONE, &velo_txt, "Speed TXT", NULL},
507  {NULL}
508  };
509  GError *gerr = NULL;
510 
511  /* Localization
512  */
513 #ifdef ENABLE_NLS
514  bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
515  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
516  textdomain (GETTEXT_PACKAGE);
517 #endif
518 
519  /* Command-line arguments
520  */
521  opct = g_option_context_new ("\t");
522  g_option_context_set_translation_domain (opct, GETTEXT_PACKAGE);
523  g_option_context_add_main_entries (opct, option, GETTEXT_PACKAGE);
524  g_option_context_add_group (opct, gtk_get_option_group (TRUE));
525  g_setenv ("NO_AT_BRIDGE", "1", FALSE); /* to eliminate annoying accessibility bus warning */
526  if (g_option_context_parse (opct, &argc, &argv, &gerr) == FALSE)
527  {
528  g_printf ("%s\n", gerr->message);
529  g_printf ("klavaro -h\n");
530  return 0;
531  }
532 
533  if (show_version)
534  {
535  g_printf (VERSION"\n");
536  //g_printf (PACKAGE_LOCALE_DIR"\n");
537  return 0;
538  }
539 
540  curl_ok = curl_global_init (CURL_GLOBAL_WIN32) == CURLE_OK ? TRUE : FALSE;
541 
542  main_initialize_global_variables (); /* Here the locale is got. */
543 
544  /* Create all the interface stuff
545  */
546  gui = gtk_builder_new ();
547  gtk_builder_set_translation_domain (gui, NULL);
548 
549  tmp = g_build_filename (main_path_data (), "klavaro.glade", NULL);
550  if (g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
551  success = gtk_builder_add_from_file (gui, tmp, NULL);
552  else
553  g_error ("GUI file not found. Aborting.\n %s", tmp);
554  if (!success)
555  g_error ("GUI file found but couldn't create the GUI. Aborting.");
556  if (!g_module_supported ())
557  g_error ("GUI created but can't connect signals.");
558  g_free (tmp);
559  gtk_builder_connect_signals (gui, NULL);
560 
561  main_window_init (); /* and initialize its parameters */
562 
563  gtk_main ();
564 
565  return 0;
566 }
567 
568 /*******************************************************************************
569  * Quit the application
570  */
571 void
573 {
575  accur_close ();
576  g_rmdir ("tmp/klavaro");
577  if (curl_ok) curl_global_cleanup ();
578  g_print ("\nAdiaux!\n");
579  exit (0);
580 }
void accur_close()
Definition: accuracy.c:619
void accur_init()
Definition: accuracy.c:151
GObject * get_obj(gchar *name)
Definition: auxiliar.c:30
void set_pixmap(gchar *widget, gchar *image)
Definition: auxiliar.c:87
GtkWidget * get_wg(gchar *name)
Definition: auxiliar.c:40
void assert_user_dir()
Definition: auxiliar.c:101
#define _(String)
Definition: auxiliar.h:45
#define textdomain(String)
Definition: auxiliar.h:39
#define dngettext(Domain, Message, Message2, N)
Definition: auxiliar.h:42
#define bindtextdomain(Domain, Directory)
Definition: auxiliar.h:44
G_MODULE_EXPORT void on_button_velo_clicked(GtkButton *button, gpointer user_data)
Definition: callbacks.c:86
G_MODULE_EXPORT void on_button_basic_clicked(GtkButton *button, gpointer user_data)
Definition: callbacks.c:72
G_MODULE_EXPORT void on_button_fluid_clicked(GtkButton *button, gpointer user_data)
Definition: callbacks.c:93
G_MODULE_EXPORT void on_button_adapt_clicked(GtkButton *button, gpointer user_data)
Definition: callbacks.c:79
void callbacks_shield_set(gboolean state)
Definition: callbacks.c:57
void window_restore(gchar *who)
Definition: callbacks.c:1831
void keyb_set_combo_kbd(gchar *cmb_country, gchar *cmb_variant)
Definition: keyboard.c:1049
void keyb_create_virtual_keys()
Definition: keyboard.c:266
void hints_init()
Definition: keyboard.c:1669
gboolean main_velo_txt()
Definition: main.c:91
static void main_window_init()
Definition: main.c:360
void main_preferences_remove(gchar *group, gchar *key)
Definition: main.c:103
static GKeyFile * preferences
Definition: main.c:45
int main(int argc, char *argv[])
Definition: main.c:498
gboolean main_altcolor_exist(gchar *group, gchar *key)
Definition: main.c:145
gint main_preferences_get_int(gchar *group, gchar *key)
Definition: main.c:121
static GKeyFile * altcolor
Definition: main.c:46
gchar * KEYB_EDIT
Definition: main.c:42
gchar * OTHER_DEFAULT
Definition: main.c:43
void main_window_pass_away()
Definition: main.c:572
gchar * main_preferences_get_string(gchar *group, gchar *key)
Definition: main.c:109
static void main_gtkbuilder_translation_workaround()
Definition: main.c:314
static gboolean curl_ok
Definition: main.c:47
static struct @7 path
gchar * KEYB_CUSTOM
Definition: main.c:41
gboolean main_curl_ok()
Definition: main.c:85
void main_preferences_set_boolean(gchar *group, gchar *key, gboolean value)
Definition: main.c:139
static gboolean velo_txt
Definition: main.c:48
void main_preferences_set_int(gchar *group, gchar *key, gint value)
Definition: main.c:127
gchar * main_path_user()
Definition: main.c:61
gboolean main_preferences_exist(gchar *group, gchar *key)
Definition: main.c:97
gchar * score
Definition: main.c:54
void main_preferences_set_string(gchar *group, gchar *key, gchar *value)
Definition: main.c:115
void main_altcolor_set_boolean(gchar *group, gchar *key, gboolean value)
Definition: main.c:164
gboolean main_altcolor_get_boolean(gchar *group, gchar *key)
Definition: main.c:158
static void main_initialize_global_variables()
Definition: main.c:223
gchar * stats
Definition: main.c:52
gchar * main_altcolor_get_string(gchar *group, gchar *key)
Definition: main.c:151
gchar * user
Definition: main.c:51
GtkBuilder * gui
Definition: main.c:39
gchar * main_path_stats()
Definition: main.c:67
gchar * data
Definition: main.c:53
gboolean main_preferences_get_boolean(gchar *group, gchar *key)
Definition: main.c:133
gchar * main_path_data()
Definition: main.c:73
void main_preferences_save()
Definition: main.c:170
gchar * main_path_score()
Definition: main.c:79
#define DIR_PERM
Definition: main.h:33
#define UNIX_OK
Definition: main.h:26
#define PACKAGE_DATA_DIR
Definition: main.h:32
#define PACKAGE_LOCALE_DIR
Definition: main.h:30
void top10_init()
Definition: top10.c:51
void trans_init_language_env()
Definition: translation.c:301
void trans_init_lang_name_code()
Definition: translation.c:148
void trans_set_combo_language()
Definition: translation.c:398
void tutor_init_timers()
Definition: tutor.c:160
@ TT_VELO
Definition: tutor.h:41
@ TT_FLUID
Definition: tutor.h:42
@ TT_BASIC
Definition: tutor.h:39
@ TT_ADAPT
Definition: tutor.h:40