1 /*
2 
3     eboard - chess client
4     http://www.bergo.eng.br/eboard
5     https://github.com/fbergo/eboard
6     Copyright (C) 2000-2016 Felipe Bergo
7     fbergo/at/gmail/dot/com
8 
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 
23 */
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #ifdef HAVE_STRINGS_H
32 #include <strings.h>
33 #endif
34 
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <time.h>
40 
41 #include "util.h"
42 #include "tstring.h"
43 #include "global.h"
44 #include "help.h"
45 #include "mainwindow.h"
46 #include "eboard.h"
47 #include "widgetproxy.h"
48 
49 #include "xpm/gnupiece.xpm"
50 
51 namespace Help {
52 
AboutDialog()53   AboutDialog::AboutDialog() : ModalDialog(N_("About eboard")) {
54     GtkWidget *v,*hb,*label,*bhb,*hs,*ok,*gnup;
55     GtkStyle *style;
56     GdkPixmap *gnud;
57     GdkBitmap *gnub;
58     char z[1024];
59 
60     v=gtk_vbox_new(FALSE,4);
61     gtk_container_add(GTK_CONTAINER(widget),v);
62 
63     hb=gtk_hbox_new(FALSE,4);
64     gtk_box_pack_start(GTK_BOX(v),hb,TRUE,TRUE,0);
65 
66     style=gtk_widget_get_style(widget);
67     gnud=gdk_pixmap_create_from_xpm_d(widget->window,&gnub,
68 				      &style->bg[GTK_STATE_NORMAL],
69 				      (gchar **)gnupiece_xpm);
70     gnup=gtk_pixmap_new(gnud,gnub);
71 
72     gtk_box_pack_start(GTK_BOX(hb),gnup,FALSE,TRUE,4);
73 
74     snprintf(z,1024,
75 	    _("eboard version %s\n"\
76 	      "(c) 2000-%d Felipe Bergo\n"\
77 	      "<fbergo@gmail.com>\n"\
78 	      "https://github.com/fbergo/eboard\n\n"\
79 	      "This program is free software; you can redistribute\n"\
80 	      "it and/or modify it under the terms of the GNU General\n"\
81 	      "Public License as published by the Free Software\n"\
82 	      "Foundation; either version 2 of the License, or\n"\
83 	      "(at your option) any later version.\n"),
84 	    global.Version, 2016);
85 
86     label=gtk_label_new(z);
87     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
88     gtk_box_pack_start(GTK_BOX(hb),label,TRUE,TRUE,4);
89 
90     hs=gtk_hseparator_new();
91     gtk_box_pack_start(GTK_BOX(v),hs,FALSE,FALSE,4);
92 
93     bhb=gtk_hbutton_box_new();
94     gtk_button_box_set_layout(GTK_BUTTON_BOX(bhb), GTK_BUTTONBOX_END);
95     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bhb), 5);
96 
97     gtk_box_pack_start(GTK_BOX(v),bhb,FALSE,FALSE,4);
98 
99     ok=gtk_button_new_with_label(_("Close"));
100     GTK_WIDGET_SET_FLAGS(ok,GTK_CAN_DEFAULT);
101     gtk_box_pack_start(GTK_BOX(bhb),ok,TRUE,TRUE,0);
102 
103     gtk_widget_grab_default(ok);
104     Gtk::show(ok,bhb,hs,label,gnup,hb,v,NULL);
105     setDismiss(GTK_OBJECT(ok),"clicked");
106   }
107 
KeysDialog()108   KeysDialog::KeysDialog() : ModalDialog(N_("Help: Keys")) {
109     GtkWidget *v,*label,*lbs,*bhb,*hs,*ok;
110     char z[1024];
111     int i;
112     list<string> s[3];
113     list<string>::iterator lsi;
114     vector<string> t;
115 
116     v=gtk_vbox_new(FALSE,4);
117     gtk_container_add(GTK_CONTAINER(widget),v);
118 
119     // changed this code to allow new commands to be added without losing
120     // the translations of the existing ones (1.1.2) -- Felipe
121     t.push_back(_("Anywhere:"));
122 
123     s[0].push_back(_("F3: Go to previous pane."));
124     s[0].push_back(_("F4: Go to next pane."));
125     s[0].push_back(_("F5: Go to the main board pane."));
126     s[0].push_back(_("F6: Go to the console pane."));
127     s[0].push_back(_("F7: Go to the seek graph pane (if available)."));
128     s[0].push_back(_("F8: Toggle shortcut bar visibility."));
129     s[0].push_back(_("Page Up/Page Down: Scroll the text console."));
130     s[0].push_back(_("Ctrl+Left: Backward 1 halfmove."));
131     s[0].push_back(_("Ctrl+Right: Forward 1 halfmove."));
132     s[0].push_back(_("Ctrl+F: Find upwards (main console buffer)."));
133     s[0].push_back(_("Ctrl+G: Find previous."));
134     s[0].push_back(_("Ctrl+T: Toggle timestamps."));
135 
136     t.push_back(_("Input Box:"));
137 
138     s[1].push_back(_("Up/Down: move thru input history."));
139     s[1].push_back(_("Enter: send text line."));
140     s[1].push_back(_("ESC: switch chat/command mode."));
141 
142     t.push_back(_("Syntaxisms:"));
143 
144     s[2].push_back(_(".. entering %prefix text will set a chat prefix."));
145     s[2].push_back(_(".. entering %do scriptname runs scriptname."));
146 
147     z[0] = 0;
148     for(i=0;i<3;i++) {
149       strcat(z, t[i].c_str());
150       strcat(z, "\n");
151       for(lsi=s[i].begin();lsi!=s[i].end();lsi++) {
152 	strcat(z, (*lsi).c_str());
153 	strcat(z, "\n");
154       }
155       strcat(z, "\n");
156     }
157 
158     label=gtk_label_new(z);
159     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
160     lbs = scrollBox(label);
161     gtk_box_pack_start(GTK_BOX(v),lbs,TRUE,TRUE,4);
162 
163     hs=gtk_hseparator_new();
164     gtk_box_pack_start(GTK_BOX(v),hs,FALSE,FALSE,4);
165 
166     bhb=gtk_hbutton_box_new();
167     gtk_button_box_set_layout(GTK_BUTTON_BOX(bhb), GTK_BUTTONBOX_END);
168     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bhb), 5);
169 
170     gtk_box_pack_start(GTK_BOX(v),bhb,FALSE,FALSE,4);
171 
172     ok=gtk_button_new_with_label(_("Close"));
173     GTK_WIDGET_SET_FLAGS(ok,GTK_CAN_DEFAULT);
174     gtk_box_pack_start(GTK_BOX(bhb),ok,TRUE,TRUE,0);
175 
176     gtk_widget_grab_default(ok);
177     gtk_window_set_default_size(GTK_WINDOW(widget),450, 500);
178     Gtk::show(ok,bhb,hs,label,v,NULL);
179     setDismiss(GTK_OBJECT(ok),"clicked");
180   }
181 
DebugDialog()182   DebugDialog::DebugDialog() : ModalDialog(N_("Help: Debug Info")) {
183     GtkWidget *v,*label,*hs,*bhb,*ok,*txt;
184     char z[2048],y[256],x[256],w[256];
185     struct stat s;
186     EboardFileFinder eff;
187 
188     v=gtk_vbox_new(FALSE,4);
189     gtk_container_add(GTK_CONTAINER(widget),v);
190 
191     z[0]=0;
192 
193     // gtk
194     snprintf(y,256,"GTK+ version %d.%d.%d\n",
195 	     gtk_major_version,
196 	     gtk_minor_version,
197 	     gtk_micro_version);
198     g_strlcat(z,y,2048);
199 
200     // gcc (c++) if any
201     snprintf(y,256,"GCC says:  %s\n",
202 	     grabOutput("c++ --version 2>&1"));
203     g_strlcat(z,y,2048);
204 
205     // perl
206     snprintf(y,256,"Perl says:  %s\n",
207 	     grabOutput("perl -v | grep ^This"));
208     g_strlcat(z,y,2048);
209 
210     // expect
211     snprintf(y,256,"expect says:  %s\n",
212 	    grabOutput("expect -d -c exit 2>&1"));
213     g_strlcat(z,y,2048);
214 
215     // kernel
216     snprintf(y,256,"kernel info: %s\n",
217 	     grabOutput("uname -srm"));
218     g_strlcat(z,y,2048);
219 
220     // timeseal
221     snprintf(x,256,"timeseal.%s",global.SystemType);
222     if (!eff.find(x,y)) strcpy(y,x);
223 
224     if (lstat(y,&s)==0) {
225       snprintf(w,256,"Found %s\n",y); strcpy(x,w);
226       snprintf(w,256,"Size %lu bytes, Last Modified %s",
227 	       s.st_size, ctime(&(s.st_mtime)) );
228       g_strlcat(x,w,256);
229       snprintf(w,256,"Mode %.4o. (seems it i%s enough to be run by eboard)\n",
230 	       s.st_mode,
231 	       ( S_ISREG(s.st_mode)
232 		 &&
233 		 (
234 		  ( S_IXUSR&s.st_mode && s.st_uid==getuid() )
235 		  ||
236 		  ( S_IXGRP&s.st_mode && s.st_gid==getgid() )
237 		  ||
238 		  ( S_IXOTH&s.st_mode )
239 		  )
240 		 ) ? "s" : "s NOT"
241 	       );
242       g_strlcat(x,w,256);
243 
244     } else {
245       snprintf(x,256,"%s Not Found (errno %d)",y,errno);
246     }
247 
248     snprintf(y,256,"\nFICS timeseal:\n%s\n",x);
249     g_strlcat(z,y,2048);
250 
251     label=gtk_label_new(z);
252     gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
253     gtk_box_pack_start(GTK_BOX(v),label,TRUE,TRUE,4);
254 
255     hs=gtk_hseparator_new();
256     gtk_box_pack_start(GTK_BOX(v),hs,FALSE,FALSE,4);
257 
258     bhb=gtk_hbutton_box_new();
259     gtk_button_box_set_layout(GTK_BUTTON_BOX(bhb), GTK_BUTTONBOX_END);
260     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bhb), 5);
261 
262     gtk_box_pack_start(GTK_BOX(v),bhb,FALSE,FALSE,4);
263 
264     ok=gtk_button_new_with_label(_("Close"));
265     txt=gtk_button_new_with_label(_("Write to Console"));
266     GTK_WIDGET_SET_FLAGS(ok,GTK_CAN_DEFAULT);
267     GTK_WIDGET_SET_FLAGS(txt,GTK_CAN_DEFAULT);
268     gtk_box_pack_start(GTK_BOX(bhb),txt,TRUE,TRUE,0);
269     gtk_box_pack_start(GTK_BOX(bhb),ok,TRUE,TRUE,0);
270 
271     gtk_widget_grab_default(ok);
272 
273     Gtk::show(ok,txt,bhb,hs,label,v,NULL);
274     setDismiss(GTK_OBJECT(ok),"clicked");
275 
276     gtk_signal_connect(GTK_OBJECT(txt),"clicked",
277 		       GTK_SIGNAL_FUNC(debugdlg_writecons),
278 		       (gpointer) this);
279 
280     strcpy(pipedata,z);
281   }
282 
grabOutput(const char * cmdline)283   char * DebugDialog::grabOutput(const char *cmdline) {
284     FILE *f;
285     bool ok = false;
286     char *c;
287     f=popen(cmdline,"r");
288     if (f) {
289       if (fgets(pipedata,127,f))
290 	ok=true;
291       pclose(f);
292     }
293     if (!ok)
294       strcpy(pipedata,"unable to retrieve");
295     else
296       while( (c=strchr(pipedata,'\n'))!=NULL)
297 	*c=0;
298     return pipedata;
299   }
300 
debugdlg_writecons(GtkWidget * w,gpointer data)301   void debugdlg_writecons(GtkWidget *w, gpointer data) {
302     DebugDialog *me;
303     tstring t;
304     string *c;
305     char z[512];
306 
307     me = (DebugDialog *) data;
308     t.set(me->pipedata);
309     global.output->append("=== START DEBUG INFO ===",0xc0ff00);
310     while( (c=t.token("\n")) != 0) {
311       memset(z,0,512);
312       c->copy(z,511);
313       global.output->append(z, global.Colors.TextBright);
314     }
315     global.output->append("=== END DEBUG INFO ===",0xc0ff00);
316   }
317 
318 
GettingStarted()319   GettingStarted::GettingStarted() : NonModalDialog(N_("Help: Getting Started ")) {
320     GtkWidget *v, *ts, *bhb, *ok, *fr;
321 
322     gtk_window_set_default_size(GTK_WINDOW(widget),620,560);
323     v=gtk_vbox_new(FALSE,4);
324     gtk_container_add(GTK_CONTAINER(widget),v);
325 
326     fr = gtk_frame_new(NULL);
327     gtk_frame_set_shadow_type(GTK_FRAME(fr),GTK_SHADOW_ETCHED_IN);
328     gtk_box_pack_start(GTK_BOX(v),fr,TRUE,TRUE,0);
329 
330 
331     text=gtk_text_view_new();
332     g_object_set(G_OBJECT(text),"cursor-visible",FALSE,NULL);
333     ts = scrollBox(text);
334     gtk_container_add(GTK_CONTAINER(fr),ts);
335 
336     bhb=gtk_hbutton_box_new();
337     gtk_button_box_set_layout(GTK_BUTTON_BOX(bhb), GTK_BUTTONBOX_END);
338     gtk_button_box_set_spacing(GTK_BUTTON_BOX(bhb), 5);
339 
340     gtk_box_pack_start(GTK_BOX(v),bhb,FALSE,FALSE,4);
341 
342     ok=gtk_button_new_with_label(_("Close"));
343     GTK_WIDGET_SET_FLAGS(ok,GTK_CAN_DEFAULT);
344     gtk_box_pack_start(GTK_BOX(bhb),ok,TRUE,TRUE,0);
345 
346     gtk_widget_grab_default(ok);
347 
348     Gtk::show(ok,bhb,text,fr,v,NULL);
349     setDismiss(GTK_OBJECT(ok),"clicked");
350 
351     compose();
352     gtk_text_view_set_editable(GTK_TEXT_VIEW(text),FALSE);
353   }
354 
compose()355   void GettingStarted::compose() {
356     char *T,*p,*q;
357     GtkTextBuffer *tb;
358     GtkTextIter iter;
359     GtkTextTag *tag[6];
360 
361     // codes: #L# large #M# medium  #S# small  #B# blue  #K# black
362 
363     T=_("#L#Getting Started\n"\
364       "#M#Common Tasks in eboard\n\n"\
365       "Playing against the computer\n"\
366       "#S#eboard does not \"play chess\" itself, but rather is works as interface to programs that do,\n"\
367       "called \"engines\", which don't have a graphical interface themselves. You need an engine to\n"\
368       "play against the computer. GNU Chess, Crafty and Sjeng are chess engines that are available at\n"\
369       "no cost.\n"\
370       "Once you have one of them installed, open the #B#Peer#K# menu, then the #B#Play against\n"\
371       "engine#K# submenu, and select the appropriate option depending on which engine you have\n"\
372       "installed.\n\n"\
373       "#M#Playing Chess on the Internet\n"\
374       "#S#Eboard supports the FICS protocol. FICS runs at freechess.org, but other servers, such as\n"\
375       "US Chess Live, use FICS's software and should work with eboard too. ICC is not supported.\n"\
376       "To connect to FICS, open the #B#Peer#K# menu, click #B#Connect to FICS#K#. To connect to\n"\
377       "other servers, open the #B#Peer#K# menu, click #B#Connect to Other Server...#K#.\n"\
378       "While you can login as guest on FICS, you'll enjoy it better as a registered user. Registration\n"\
379       "is done through FICS's site at #B#http://www.freechess.org#K#, and it's free.\n\n"\
380       "#M#Browsing PGN Games\n"\
381       "#S#PGN is the most common file format to store chess games. It can store moves and comments\n"\
382       "(annotations). To open this kind of file within eboard, open the #B#Windows#K# menu, click\n"\
383       "#B#Games on Client#K#. In the Local Game List dialog, click #B#Load PGN...#K#. To browse a\n"\
384       "game, #B#select it#K# and click #B#Display#K#. A new tab will be created in the main window\n"\
385       "with the game."\
386       "#L#");
387 
388     tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
389     tag[0] = gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(tb),"tag0",
390 					"font","Sans 10",
391 					"foreground","#000000",
392 					"justification",GTK_JUSTIFY_LEFT,
393 					"editable",FALSE,
394 					"weight",PANGO_WEIGHT_NORMAL,
395 					"wrap-mode",GTK_WRAP_WORD,
396 					NULL);
397     tag[1] = gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(tb),"tag1",
398 					"font","Sans 12",
399 					"foreground","#000000",
400 					"justification",GTK_JUSTIFY_LEFT,
401 					"editable",FALSE,
402 					"weight",PANGO_WEIGHT_BOLD,
403 					"wrap-mode",GTK_WRAP_WORD,
404 					NULL);
405     tag[2] = gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(tb),"tag2",
406 					"font","Sans 16",
407 					"foreground","#000000",
408 					"justification",GTK_JUSTIFY_LEFT,
409 					"editable",FALSE,
410 					"weight",PANGO_WEIGHT_BOLD,
411 					"wrap-mode",GTK_WRAP_WORD,
412 					NULL);
413     tag[3] = gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(tb),"tag3",
414 					"font","Sans 10",
415 					"foreground","#0000ff",
416 					"justification",GTK_JUSTIFY_LEFT,
417 					"editable",FALSE,
418 					"weight",PANGO_WEIGHT_NORMAL,
419 					"wrap-mode",GTK_WRAP_WORD,
420 					NULL);
421     tag[4] = gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(tb),"tag4",
422 					"font","Sans 12",
423 					"foreground","#0000ff",
424 					"justification",GTK_JUSTIFY_LEFT,
425 					"editable",FALSE,
426 					"weight",PANGO_WEIGHT_BOLD,
427 					"wrap-mode",GTK_WRAP_WORD,
428 					NULL);
429     tag[5] = gtk_text_buffer_create_tag(GTK_TEXT_BUFFER(tb),"tag5",
430 					"font","Sans 16",
431 					"foreground","#0000ff",
432 					"justification",GTK_JUSTIFY_LEFT,
433 					"editable",FALSE,
434 					"weight",PANGO_WEIGHT_BOLD,
435 					"wrap-mode",GTK_WRAP_WORD,
436 					NULL);
437 
438 
439     int ctag = 0, tval[2] = {0,0};
440     q  = T;
441     for(p=T;*p;p++) {
442 
443       if (*p=='#') {
444 	if (p-q) {
445 	  gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(tb),&iter);
446 	  gtk_text_buffer_insert_with_tags(GTK_TEXT_BUFFER(tb),&iter,q,p-q,tag[ctag],NULL);
447 	}
448 	q = p + 3;
449 
450 	switch(p[1]) {
451 	case 'L': tval[0]=2; break;
452 	case 'M': tval[0]=1; break;
453 	case 'S': tval[0]=0; break;
454 	case 'B': tval[1]=1; break;
455 	case 'K': tval[1]=0; break;
456 	}
457 	ctag = 3*tval[1] + tval[0];
458 	p += 3;
459       }
460 
461     }
462 
463   }
464 
465 } // namespace Help
466 
467