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 <iostream>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <dirent.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #include <time.h>
36 #include <signal.h>
37 #include <dlfcn.h>
38
39 #define GLOBAL_CC 1
40
41 #include "global.h"
42 #include "text.h"
43 #include "config.h"
44
45 #include "chess.h"
46 #include "tstring.h"
47 #include "notebook.h"
48 #include "board.h"
49 #include "quickbar.h"
50 #include "pieces.h"
51 #include "eboard.h"
52
53
54 /* Global variables needed to cleanly close the driver */
55 extern int (*dgtnixClose)();
56 extern bool DgtInit;
57 extern void *dgtnix_dll_handle;
58 Global global;
59
60 // stream ops
61
operator <<(ostream & s,WindowGeometry w)62 ostream & operator<<(ostream &s, WindowGeometry w) {
63 s << '(' << w.X << ',' << w.Y << ',';
64 s << w.W << ',' << w.H << ')';
65 return(s);
66 }
67
operator <<(ostream & s,Desktop d)68 ostream & operator<<(ostream &s, Desktop d) {
69 s << d.wMain << ',' << d.wGames << ',' << d.wLocal << ',';
70 s << d.wAds << ',' << d.PanePosition ;
71 return(s);
72 }
73
operator <<(ostream & s,TimeControl tc)74 ostream & operator<<(ostream &s, TimeControl tc) {
75 TimeControl x;
76 x = tc;
77 if (x.mode == TC_SPM) x.value[1] = 0;
78 if (x.mode == TC_NONE) x.value[0] = x.value[1] = 0;
79 s << '/' << ((int)(x.mode)) << '/' << x.value[0];
80 s << '/' << x.value[1];
81 return(s);
82 }
83
operator <<(ostream & s,EngineBookmark b)84 ostream & operator<<(ostream &s, EngineBookmark b) {
85 s << b.caption << '^';
86 if (b.directory.empty()) s << "NULL"; else s << b.directory;
87 s << '^';
88 if (b.cmdline.empty()) s << "NULL"; else s << b.cmdline;
89 s << '^' << b.humanwhite << '^' << b.timecontrol << '^';
90 s << b.maxply << '^' << b.think << '^';
91 s << b.proto << '^' << ((int)b.mode);
92 return(s);
93 }
94
operator <<(ostream & s,TerminalColor t)95 ostream & operator<<(ostream &s, TerminalColor t) {
96 s.setf(ios::hex,ios::basefield);
97 s << t.TextDefault << ',';
98 s << t.TextBright << ',';
99 s << t.PrivateTell << ',';
100 s << t.NewsNotify << ',';
101 s << t.Mamer << ',';
102 s << t.KibitzWhisper << ',';
103 s << t.Shouts << ',';
104 s << t.Seeks << ',';
105 s << t.ChannelTell << ',';
106 s << t.Engine << ',';
107 s << t.Background;
108 s.setf(ios::dec,ios::basefield);
109 return(s);
110 }
111
Global()112 Global::Global() {
113 int i;
114
115 input=0;
116 output=0;
117 network=0;
118 status=0;
119 protocol=0;
120 chandler=0;
121 promotion=0;
122 ebook=0;
123 skgraph2=0;
124 inputhistory=0;
125 bmlistener=0;
126 qbcontainer=0;
127 quickbar=0;
128 killbox=0;
129 lowernotebook=0;
130 mainpaned=0;
131 bugpane=0;
132 pieceset=0;
133 toplevelwidget=0;
134
135 LastScratch = 0;
136
137 Quitting=0;
138 Version=VERSION;
139 SelfInputColor = 0xc0c0ff;
140
141 HilightLastMove=0;
142 AnimateMoves=0;
143 Premove=1;
144
145 PasswordMode = 0;
146
147 TabPos=0;
148
149 CommLog=0;
150 DebugLog=0;
151 PauseLog=0;
152
153 MainLevel=0;
154 QuitPending=0;
155
156 ScrollBack=1000;
157 FicsAutoLogin=1;
158 BeepWhenOppMoves=0;
159 EnableSounds=0;
160 PopupSecondaryGames=1;
161 SmartDiscard=0;
162 ShowCoordinates=0;
163
164 PlainSquares=0;
165 LightSqColor=0xe7cf93;
166 DarkSqColor=0x9e8661;
167
168 ShowTimestamp = 0;
169 ShowRating=1;
170 SpecialChars = 3;
171 MsecThreshold = 60;
172 MsecDigits = 3;
173
174 UseVectorPieces=0;
175 CheckLegality=0;
176 DrawHouseStock=1;
177
178 AppendPlayed=0;
179 AppendObserved=0;
180 strcpy(AppendFile,"~/.eboard/mygames.pgn");
181
182 IcsSeekGraph=1;
183 HideSeeks=0;
184
185 SplitChannels=0;
186 ChannelsToConsoleToo=0;
187
188 SmootherAnimation=0;
189
190 // chess machine had this and FICS admins didn't like it
191 // if you turn it on, you may be committing abuse.
192 // I'm not going to delete the code. I'm just removing the
193 // user-friendly controls from the config dialog and setting
194 // the defaults to safe values.
195
196 IcsAllObPlayed = 0;
197 IcsAllObObserved = 0;
198
199 ShowQuickbar=1;
200 LowTimeWarningLimit=5;
201 RetrieveChannelNames=1;
202
203 sndevents[1].Pitch=650;
204 sndevents[1].Duration=350;
205
206 sndevents[2].Pitch=900;
207 sndevents[2].Duration=80;
208
209 sndevents[3].Pitch=444;
210 sndevents[3].Duration=40;
211 sndevents[3].Count=3;
212
213 sndevents[4].Pitch=740;
214 sndevents[4].Duration=120;
215
216 for(i=5;i<N_SOUND_EVENTS;i++) {
217 sndevents[i].Pitch=610;
218 sndevents[i].Duration=60;
219 sndevents[i].enabled=false;
220 }
221
222 strcpy(ClockFont,DEFAULT_FONT_CLOK);
223 strcpy(PlayerFont,DEFAULT_FONT_PLYR);
224 strcpy(InfoFont,DEFAULT_FONT_INFO);
225 strcpy(ConsoleFont,DEFAULT_FONT_CONS);
226 strcpy(SeekFont,DEFAULT_FONT_SEEK);
227
228 memset(P2PName,0,64);
229 env.User.copy(P2PName,63);
230
231 RCKeys.push_back("HilightLastMove"); //0
232 RCKeys.push_back("AnimateMoves");
233 RCKeys.push_back("Premove"); //2
234 RCKeys.push_back("PieceSet");
235 RCKeys.push_back("TabPos"); //4
236 RCKeys.push_back("ClockFont");
237 RCKeys.push_back("PlayerFont"); //6
238 RCKeys.push_back("InfoFont");
239 RCKeys.push_back("PlainSquares"); //8
240 RCKeys.push_back("LightSqColor");
241 RCKeys.push_back("DarkSqColor"); //10
242 RCKeys.push_back("Host");
243 RCKeys.push_back("Antialias"); //12 [deprecated]
244 RCKeys.push_back("ShowRating");
245 RCKeys.push_back("ScrollBack"); //14
246 RCKeys.push_back("FicsAutoLogin");
247 RCKeys.push_back("BeepOpp"); //16
248 RCKeys.push_back("SoundEvent");
249 RCKeys.push_back("EnableSounds"); //18
250 RCKeys.push_back("VectorPieces");
251 RCKeys.push_back("CheckLegality"); //20
252 RCKeys.push_back("AppendPlayed");
253 RCKeys.push_back("AppendObserved"); //22
254 RCKeys.push_back("AppendFile");
255 RCKeys.push_back("ConsoleFont"); //24
256 RCKeys.push_back("SeekGraph");
257 RCKeys.push_back("HideSeeks"); //26
258 RCKeys.push_back("SplitChannels");
259 RCKeys.push_back("ChSplitAndCons"); //28
260 RCKeys.push_back("DrawHouseStock");
261 RCKeys.push_back("SquareSet"); //30
262 RCKeys.push_back("PopupSecondaryGames");
263 RCKeys.push_back("SmartDiscard"); //32
264 RCKeys.push_back("ShowCoordinates");
265 RCKeys.push_back("TerminalColors"); //34
266 RCKeys.push_back("DesktopState");
267 RCKeys.push_back("DesktopStateDC"); //36
268 RCKeys.push_back("ShowQuickbar");
269 RCKeys.push_back("QuickbarButton"); //38
270 RCKeys.push_back("LowTimeWarningLimit");
271 RCKeys.push_back("RetrieveChannelNames"); //40
272 RCKeys.push_back("SmootherAnimation");
273 RCKeys.push_back("EngineBookmark"); // 42
274 RCKeys.push_back("SeekFont");
275 RCKeys.push_back("IcsAllObPlayed"); // 44
276 RCKeys.push_back("IcsAllObObserved");
277 RCKeys.push_back("P2PName"); // 46
278 RCKeys.push_back("ShowTimestamp");
279 RCKeys.push_back("SpecialChars");// 48
280 RCKeys.push_back("JSCAxis"); // [deprecated]
281 RCKeys.push_back("JSBAxis"); // 50 [deprecated]
282 RCKeys.push_back("JSMButton"); // [deprecated]
283 RCKeys.push_back("JSNTButton"); // 52 // [deprecated]
284 RCKeys.push_back("JSPTButton"); // [deprecated]
285 RCKeys.push_back("JSMode"); // 54 // [deprecated]
286 RCKeys.push_back("JSSpeed"); // [deprecated]
287 RCKeys.push_back("MsecThreshold"); // 56
288 RCKeys.push_back("MsecDigits");
289
290 PopupHelp = false;
291 }
292
dropQuickbarButtons()293 void Global::dropQuickbarButtons() {
294 unsigned int i;
295 for(i=0;i<QuickbarButtons.size();i++)
296 delete(QuickbarButtons[i]);
297 QuickbarButtons.clear();
298 }
299
clearDupes(ChessGame * cg)300 void Global::clearDupes(ChessGame *cg) {
301 list<ChessGame *>::iterator gi;
302 for(gi=GameList.begin();gi!=GameList.end();gi++)
303 if ( (*(*gi)) == cg->GameNumber )
304 renumberGame(*gi,nextFreeGameId(8000));
305 }
306
deleteGame(ChessGame * cg)307 void Global::deleteGame(ChessGame *cg) {
308 list<ChessGame *>::iterator gi;
309 for(gi=GameList.begin();gi!=GameList.end();gi++)
310 if ( (*gi) == cg ) {
311 GameList.erase(gi);
312 return;
313 }
314 }
315
appendGame(ChessGame * cg,bool RenumberDupes)316 void Global::appendGame(ChessGame *cg,bool RenumberDupes) {
317 if (RenumberDupes) clearDupes(cg);
318 GameList.push_back(cg);
319 }
prependGame(ChessGame * cg,bool RenumberDupes)320 void Global::prependGame(ChessGame *cg, bool RenumberDupes) {
321 if (RenumberDupes) clearDupes(cg);
322 GameList.push_front(cg);
323 }
324
renumberGame(ChessGame * cg,int id)325 void Global::renumberGame(ChessGame *cg,int id) {
326 int oldid;
327 oldid=cg->GameNumber;
328 cg->GameNumber=id;
329 // renumber notebook references
330 if (ebook) ebook->renumberPage(oldid,id);
331 }
332
removeBoard(Board * b)333 void Global::removeBoard(Board *b) {
334 for(BLi=BoardList.begin();BLi!=BoardList.end();BLi++)
335 if ( (*BLi) == b ) {
336 BoardList.erase(BLi);
337 return;
338 }
339 // cerr << "<Global::removeBoard> ** board not found\n";
340 }
341
effectiveLegalityChecking()342 bool Global::effectiveLegalityChecking() {
343 if (CheckLegality) return true;
344
345 if (protocol != NULL)
346 return(protocol->requiresLegalityChecking());
347
348 return false;
349 }
350
statOS()351 void Global::statOS() {
352 FILE *p;
353 p=popen("uname -s","r");
354 if (!p) p=popen("/bin/uname -s","r");
355 if (!p) p=popen("/sbin/uname -s","r");
356 if (!p) p=popen("/usr/bin/uname -s","r");
357 if (!p) p=popen("/usr/sbin/uname -s","r");
358 if (!p) { strcpy(SystemType,"unknown"); return; }
359 SystemType[63]=0;
360 fgets(SystemType,64,p);
361 pclose(p);
362 if (SystemType[strlen(SystemType)-1]=='\n')
363 SystemType[strlen(SystemType)-1]=0;
364 }
365
ensureDirectories()366 void Global::ensureDirectories() {
367 char z[256];
368 DIR *tdir;
369
370 if (env.Home.empty()) {
371 cerr << _("[eboard] ** no $HOME") << endl;
372 return;
373 } else if (strlen(env.Home.c_str()) > 230) {
374 cerr << _("[eboard] ** $HOME is too long") << endl;
375 return;
376 }
377 snprintf(z,256,"%s/.eboard",env.Home.c_str());
378
379 tdir=opendir(z);
380 if (tdir==NULL)
381 PopupHelp = true;
382 else
383 closedir(tdir);
384
385 if (createDir(z)) return;
386 snprintf(z,256,"%s/.eboard/craftylog",env.Home.c_str());
387 createDir(z);
388 snprintf(z,256,"%s/.eboard/eng-out",env.Home.c_str());
389 createDir(z);
390 snprintf(z,256,"%s/.eboard/scripts",env.Home.c_str());
391 createDir(z);
392 }
393
createDir(char * z)394 int Global::createDir(char *z) {
395 DIR *tdir;
396 tdir=opendir(z);
397 if (tdir)
398 closedir(tdir);
399 else
400 if (mkdir(z,0755)) {
401 cerr << _("[eboard] ** failed to create directory ") << z << endl;
402 return -1;
403 }
404 return 0;
405 }
406
readRC()407 void Global::readRC() {
408 tstring t;
409 string *p;
410 char line[512],rev[128];
411
412 static const char *sep=" \n\t,:\r^";
413 static const char *sep2="\n\t,:\r";
414 static const char *sep3=" \n\t:\r";
415 static const char *sep4=",\n\r";
416 static const char *sep5="\n\t:\r";
417
418 HostBookmark *hbm;
419 EngineBookmark *ebm;
420 int i,j;
421 QButton *qb;
422
423 if (env.Config.empty())
424 return;
425
426 ifstream rc(env.Config.c_str());
427
428 if (!rc)
429 return;
430
431 memset(rev,0,128);
432 rev['R']=0;
433 rev['L']=1;
434 rev['T']=2;
435 rev['B']=3;
436
437 t.setChomp(true);
438
439 memset(line,0,512);
440 while(rc.getline(line,511,'\n')) {
441 t.set(line);
442 memset(line,0,512);
443
444 p=t.token(sep);
445 if (!p) continue;
446 if (p->at(0)=='#') continue;
447
448 for(j=0;j<=57;j++) {
449 if (! p->compare(RCKeys[j]) ) {
450 switch(j) {
451 case 0: HilightLastMove =t.tokenvalue(sep); break;
452 case 1: AnimateMoves =t.tokenvalue(sep); break;
453 case 2: Premove =t.tokenvalue(sep); break;
454 case 3: setPieceSet(*(t.token(sep3)),true,true); break;
455 case 4: p=t.token(sep); TabPos=rev[p->at(0)]; break;
456 case 5: p=t.token(sep2); memset(ClockFont,0,96);
457 p->copy(ClockFont,95); break;
458 case 6: p=t.token(sep2); memset(PlayerFont,0,96);
459 p->copy(PlayerFont,95); break;
460 case 7: p=t.token(sep2); memset(InfoFont,0,96);
461 p->copy(InfoFont,95); break;
462 case 8: PlainSquares =t.tokenvalue(sep); break;
463 case 9: LightSqColor =t.tokenvalue(sep,16); break;
464 case 10: DarkSqColor =t.tokenvalue(sep,16); break;
465 case 11: hbm=new HostBookmark();
466 p=t.token(sep4); p->copy(hbm->host,128);
467 hbm->port=t.tokenvalue(sep4);
468 p=t.token(sep4); p->copy(hbm->protocol,64);
469 HostHistory.push_back(hbm);
470 break;
471 case 12: break; // deprecated (antialias)
472 case 13: ShowRating =t.tokenvalue(sep); break;
473 case 14: ScrollBack =t.tokenvalue(sep); break;
474 case 15: FicsAutoLogin =t.tokenvalue(sep); break;
475 case 16: BeepWhenOppMoves=t.tokenvalue(sep); break;
476 case 17: i=t.tokenvalue(sep);
477 if (i < N_SOUND_EVENTS) sndevents[i].read(t);
478 break;
479 case 18: EnableSounds =t.tokenvalue(sep); break;
480 case 19: UseVectorPieces =t.tokenvalue(sep); break;
481 case 20: CheckLegality =t.tokenvalue(sep); break;
482 case 21: AppendPlayed =t.tokenvalue(sep); break;
483 case 22: AppendObserved =t.tokenvalue(sep); break;
484 case 23: p=t.token(sep); memset(AppendFile,0,128);
485 p->copy(AppendFile,127); break;
486 case 24: p=t.token(sep2); memset(ConsoleFont,0,96);
487 p->copy(ConsoleFont,95); break;
488 case 25: IcsSeekGraph =t.tokenvalue(sep); break;
489 case 26: HideSeeks =t.tokenvalue(sep); break;
490 case 27: SplitChannels =t.tokenvalue(sep); break;
491 case 28: ChannelsToConsoleToo=t.tokenvalue(sep); break;
492 case 29: DrawHouseStock =t.tokenvalue(sep); break;
493 case 30: p=t.token(sep3);
494 if (p->compare(pieceset->getSquareName()))
495 setPieceSet(*p,false,true);
496 break;
497 case 31: PopupSecondaryGames =t.tokenvalue(sep); break;
498 case 32: SmartDiscard =t.tokenvalue(sep); break;
499 case 33: ShowCoordinates =t.tokenvalue(sep); break;
500 case 34: Colors.read(t); break;
501 case 35: Desk.read(t); break;
502 case 36: Desk.readConsole(t); break;
503 case 37: ShowQuickbar =t.tokenvalue(sep); break;
504 case 38: qb=new QButton(); qb->icon=t.tokenvalue(sep5);
505 qb->caption=*(t.token(sep5)); qb->command=*(t.token(sep5));
506 QuickbarButtons.push_back(qb);
507 break;
508 case 39: LowTimeWarningLimit =t.tokenvalue(sep); break;
509 case 40: RetrieveChannelNames=t.tokenvalue(sep); break;
510 case 41: SmootherAnimation =t.tokenvalue(sep); break;
511 case 42: ebm=new EngineBookmark(); ebm->read(t);
512 EnginePresets.push_back(ebm); break;
513 case 43: p=t.token(sep2); memset(SeekFont,0,96);
514 p->copy(SeekFont,95); break;
515 // default: cerr << "ignored [" << (*p) << "]\n";
516 case 44: IcsAllObPlayed =t.tokenvalue(sep); break;
517 case 45: IcsAllObObserved =t.tokenvalue(sep); break;
518 case 46: p=t.token(sep2); memset(P2PName,0,64);
519 p->copy(P2PName,63); break;
520 case 47: ShowTimestamp =t.tokenvalue(sep); break;
521 case 48: SpecialChars =t.tokenvalue(sep); break;
522 case 49:
523 case 50:
524 case 51:
525 case 52:
526 case 53:
527 case 54:
528 case 55:
529 // 49-55: deprecated joystick-related keys
530 break;
531 case 56: MsecThreshold = t.tokenvalue(sep); break;
532 case 57: MsecDigits = t.tokenvalue(sep); break;
533 } // switch
534 } // compare
535 } // for j 0..57
536 } // while getline
537
538 rc.close();
539 }
540
writeRC()541 void Global::writeRC() {
542
543 string div;
544
545 list<HostBookmark *>::iterator bi;
546 list<EngineBookmark *>::iterator ei;
547 static const char *tabpos="RLTB";
548 unsigned int i;
549
550 if (env.Config.empty())
551 return;
552
553 div="::";
554
555 ofstream rc(env.Config.c_str());
556 if (!rc)
557 return;
558
559 rc << RCKeys[0] << div << HilightLastMove << endl;
560 rc << RCKeys[1] << div << AnimateMoves << endl;
561 rc << RCKeys[2] << div << Premove << endl;
562 rc << RCKeys[3] << div << pieceset->getName() << endl;
563 rc << RCKeys[4] << div << tabpos[TabPos%4] << endl;
564 rc << RCKeys[5] << div << ClockFont << endl;
565 rc << RCKeys[6] << div << PlayerFont << endl;
566 rc << RCKeys[7] << div << InfoFont << endl;
567 rc << RCKeys[8] << div << PlainSquares << endl;
568
569 rc.setf(ios::hex, ios::basefield);
570 rc << RCKeys[9] << div << LightSqColor << endl;
571 rc << RCKeys[10] << div << DarkSqColor << endl;
572 rc.setf(ios::dec, ios::basefield);
573
574 for(bi=HostHistory.begin();bi!=HostHistory.end();bi++)
575 rc << RCKeys[11] << ',' << (*bi)->host << ',' <<
576 (*bi)->port << ',' << (*bi)->protocol << endl;
577
578 // 12: antialias deprecated
579 rc << RCKeys[13] << div << ShowRating << endl;
580 rc << RCKeys[14] << div << ScrollBack << endl;
581 rc << RCKeys[15] << div << FicsAutoLogin<< endl;
582 rc << RCKeys[16] << div << BeepWhenOppMoves << endl;
583
584 for(i=0;i< N_SOUND_EVENTS;i++)
585 rc << RCKeys[17] << div << i << ',' << sndevents[i] << endl;
586
587 rc << RCKeys[18] << div << EnableSounds << endl;
588 rc << RCKeys[19] << div << UseVectorPieces << endl;
589 rc << RCKeys[20] << div << CheckLegality << endl;
590 rc << RCKeys[21] << div << AppendPlayed << endl;
591 rc << RCKeys[22] << div << AppendObserved << endl;
592 rc << RCKeys[23] << div << AppendFile << endl;
593
594 rc << RCKeys[24] << div << ConsoleFont << endl;
595 rc << RCKeys[25] << div << IcsSeekGraph << endl;
596 rc << RCKeys[26] << div << HideSeeks << endl;
597 rc << RCKeys[27] << div << SplitChannels << endl;
598 rc << RCKeys[28] << div << ChannelsToConsoleToo << endl;
599 rc << RCKeys[29] << div << DrawHouseStock << endl;
600 rc << RCKeys[30] << div << pieceset->getSquareName() << endl;
601 rc << RCKeys[31] << div << PopupSecondaryGames << endl;
602 rc << RCKeys[32] << div << SmartDiscard << endl;
603 rc << RCKeys[33] << div << ShowCoordinates << endl;
604
605 rc << RCKeys[34] << div << Colors << endl;
606 rc << RCKeys[35] << div << Desk << endl;
607
608 Desk.writeConsoles(rc,RCKeys[36]);
609
610 rc << RCKeys[37] << div << ShowQuickbar << endl;
611
612 for(i=0;i<QuickbarButtons.size();i++)
613 rc << RCKeys[38] << div << (*QuickbarButtons[i]) << endl;
614
615 rc << RCKeys[39] << div << LowTimeWarningLimit << endl;
616 rc << RCKeys[40] << div << RetrieveChannelNames << endl;
617 rc << RCKeys[41] << div << SmootherAnimation << endl;
618
619 for(ei=EnginePresets.begin();ei!=EnginePresets.end();ei++)
620 rc << RCKeys[42] << '^' << (*(*ei)) << endl;
621
622 rc << RCKeys[43] << div << SeekFont << endl;
623
624 rc << RCKeys[44] << div << IcsAllObPlayed << endl;
625 rc << RCKeys[45] << div << IcsAllObObserved << endl;
626 rc << RCKeys[46] << div << P2PName << endl;
627 rc << RCKeys[47] << div << ShowTimestamp << endl;
628 rc << RCKeys[48] << div << SpecialChars << endl;
629
630 // 49-55: deprecated (joystick)
631
632 rc << RCKeys[56] << div << MsecThreshold << endl;
633 rc << RCKeys[57] << div << MsecDigits << endl;
634
635 rc.close();
636 }
637
getGame(int num)638 ChessGame * Global::getGame(int num) {
639 list<ChessGame *>::iterator gi;
640 for(gi=GameList.begin();gi!=GameList.end();gi++)
641 if ( (*(*gi)) == num )
642 return(*gi);
643 return NULL;
644 }
645
nextFreeGameId(int base)646 int Global::nextFreeGameId(int base) {
647 int v;
648 for(v=base;getGame(v)!=0;v++) ;
649 return v;
650 }
651
WrappedMainIteration()652 void Global::WrappedMainIteration() {
653 MainLevel++;
654 gtk_main_iteration();
655 MainLevel--;
656 if ((!MainLevel)&&(QuitPending))
657 Global::WrappedMainQuit();
658 }
659
WrappedMainQuit()660 void Global::WrappedMainQuit() {
661 if (MainLevel) {
662 QuitPending++;
663 return;
664 }
665 QuitPending=0;
666 signal(SIGCHLD,SIG_DFL); // prevent the crash reported by gcp
667 /* close dgtnix driver and dll */
668 if(DgtInit)
669 {
670 dgtnixClose();
671 dlclose(dgtnix_dll_handle);
672 }
673 gtk_main_quit();
674 }
675
addAgent(NetConnection * ag)676 void Global::addAgent(NetConnection *ag) {
677 Agents.push_back(ag);
678 ag->notifyReadReady(iowatcher);
679 }
680
removeAgent(NetConnection * ag)681 void Global::removeAgent(NetConnection *ag) {
682 list<NetConnection *>::iterator ni;
683 for(ni=Agents.begin();ni!=Agents.end();ni++)
684 if ( (*ni) == ag ) {
685 Agents.erase(ni);
686 return;
687 }
688 }
689
agentBroadcast(char * z)690 void Global::agentBroadcast(char *z) {
691 list<NetConnection *>::iterator ni;
692 if (Agents.empty())
693 return;
694 for(ni=Agents.begin();ni!=Agents.end();ni++)
695 if ((*ni)->isConnected())
696 (*ni)->writeLine(z);
697 }
698
receiveAgentLine(char * dest,int limit)699 int Global::receiveAgentLine(char *dest,int limit) {
700 list<NetConnection *>::iterator ni;
701 global.debug("Global","receiveAgentLine");
702 if (Agents.empty())
703 return 0;
704 for(ni=Agents.begin();ni!=Agents.end();ni++)
705 if ( (*ni)->isConnected())
706 if ((*ni)->readLine(dest,limit)==0)
707 return 1;
708 return 0;
709 }
710
opponentMoved()711 void Global::opponentMoved() {
712 if (BeepWhenOppMoves && sndevents[0].enabled) {
713 if (AnimateMoves)
714 SoundStack.push(0);
715 else
716 sndevents[0].play();
717 }
718 }
719
720 /*
721 void Global::clearSoundStack() {
722 while(!SoundStack.empty())
723 SoundStack.pop();
724 }
725 */
726
flushSound()727 void Global::flushSound() {
728 if (!SoundStack.empty()) {
729 sndevents[SoundStack.top()].play();
730 SoundStack.pop();
731 }
732 }
733
drawOffered()734 void Global::drawOffered() { playOther(1); }
privatelyTold()735 void Global::privatelyTold() { playOther(2); }
challenged()736 void Global::challenged() { playOther(3); }
timeRunningOut()737 void Global::timeRunningOut() { playOther(4); }
gameWon()738 void Global::gameWon() { playOther(5); }
gameLost()739 void Global::gameLost() { playOther(6); }
gameStarted()740 void Global::gameStarted() { playOther(7); }
gameFinished()741 void Global::gameFinished() { playOther(8); }
742
moveMade()743 void Global::moveMade() {
744 if (EnableSounds && sndevents[9].enabled) {
745 if (AnimateMoves)
746 SoundStack.push(9);
747 else
748 sndevents[9].play();
749 }
750 }
751
playOther(int i)752 void Global::playOther(int i) {
753 if (i>=N_SOUND_EVENTS) return;
754 if (EnableSounds && sndevents[i].enabled)
755 sndevents[i].play();
756 }
757
repaintAllBoards()758 void Global::repaintAllBoards() {
759 respawnPieceSet();
760 }
761
hasSoundFile(string & p)762 bool Global::hasSoundFile(string &p) {
763 int i,j;
764 j=SoundFiles.size();
765 for(i=0;i<j;i++)
766 if ( ! SoundFiles[i].compare(p) )
767 return true;
768 return false;
769 }
770
setPasswordMode(int pm)771 void Global::setPasswordMode(int pm) {
772 list<DetachedConsole *>::iterator i;
773 PasswordMode = pm;
774 for(i=Consoles.begin();i!=Consoles.end();i++)
775 (*i)->setPasswordMode(pm);
776 }
777
debug(const char * klass,const char * method,const char * data)778 void Global::debug(const char *klass,const char *method,const char *data) {
779 char z[256];
780 time_t now;
781 string rm;
782
783 if (!DebugLog)
784 return;
785
786 if (env.Home.empty())
787 return;
788
789 snprintf(z,256,"%s/DEBUG.eboard",env.Home.c_str());
790
791 ofstream f(z,ios::app);
792 if (!f) return;
793
794 rm="+ ";
795 rm+=klass;
796 rm+="::";
797 rm+=method;
798 if (data) { rm+=" ["; rm+=data; rm+=']'; }
799
800 now=time(0);
801 strftime(z,255,"%Y-%b-%d %H:%M:%S",localtime(&now));
802
803 f << z << " [" << ((int) getpid()) << "] " << rm << endl;
804 f.close();
805 }
806
LogAppend(const char * msg)807 void Global::LogAppend(const char *msg) {
808 char z[256];
809 const char *p;
810 static char hexa[17]="0123456789abcdef";
811 time_t now;
812 string s;
813
814 if (env.Home.empty())
815 return;
816
817 if (PauseLog)
818 msg=_("(message obfuscated -- password mode ?)");
819
820 if (CommLog) {
821 snprintf(z,256,"%s/LOG.eboard",env.Home.c_str());
822
823 ofstream f(z,ios::app);
824 if (!f) return;
825
826 for(p=msg;*p;p++)
827 switch(*p) {
828 case '\n': s+="\\n"; break;
829 case '\r': s+="\\r"; break;
830 default:
831 if (*p < 32) {
832 s+="(0x"; s+=hexa[(*p)>>4]; s+=hexa[(*p)&0xf]; s+=')';
833 } else
834 s+=*p;
835 }
836
837 now=time(0);
838 strftime(z,255,"%Y-%b-%d %H:%M:%S",localtime(&now));
839
840 f << z << "[ " << ((int) getpid()) << "] " << s << endl;
841 f.close();
842 }
843 }
844
dumpGames()845 void Global::dumpGames() {
846 cerr.setf(ios::dec,ios::basefield);
847 cerr << " GAME LIST (" << GameList.size() << " elements)\n";
848 cerr << "--------------------------------------------------------------------------\n";
849 for(GLi=GameList.begin();GLi!=GameList.end();GLi++)
850 (*GLi)->dump();
851 cerr << "--------------------------------------------------------------------------\n";
852 }
853
dumpBoards()854 void Global::dumpBoards() {
855 cerr.setf(ios::dec,ios::basefield);
856 cerr << " BOARD LIST (" << BoardList.size() << " elements)\n";
857 cerr << "--------------------------------------------------------------------------\n";
858 for(BLi=BoardList.begin();BLi!=BoardList.end();BLi++)
859 (*BLi)->dump();
860 cerr << "--------------------------------------------------------------------------\n";
861 }
862
dumpPanes()863 void Global::dumpPanes() {
864 cerr.setf(ios::dec,ios::basefield);
865 cerr << " PANE LIST\n";
866 cerr << "--------------------------------------------------------------------------\n";
867 ebook->dump();
868 cerr << "--------------------------------------------------------------------------\n";
869 }
870
addHostBookmark(HostBookmark * hbm)871 void Global::addHostBookmark(HostBookmark *hbm) {
872 list<HostBookmark *>::iterator bi;
873
874 for(bi=HostHistory.begin();bi!=HostHistory.end();bi++)
875 if ( (*(*bi)) == hbm ) {
876 delete hbm;
877 return;
878 }
879 HostHistory.push_front(hbm);
880 if (HostHistory.size() > 16) {
881 delete(HostHistory.back());
882 HostHistory.pop_back();
883 }
884
885 writeRC();
886 if (bmlistener != 0) bmlistener->updateBookmarks();
887 }
888
addEngineBookmark(EngineBookmark * ebm)889 void Global::addEngineBookmark(EngineBookmark *ebm) {
890 list<EngineBookmark *>::iterator ei;
891
892 for(ei=EnginePresets.begin();ei!=EnginePresets.end();ei++)
893 if ( (*(*ei)) == ebm ) {
894 delete ebm;
895 return;
896 }
897
898 EnginePresets.push_front(ebm);
899 if (EnginePresets.size() > 16) {
900 delete(EnginePresets.back());
901 EnginePresets.pop_back();
902 }
903
904 writeRC();
905 if (bmlistener != 0) bmlistener->updateBookmarks();
906 }
907
updateScrollBacks()908 void Global::updateScrollBacks() {
909 output->updateScrollBack();
910 updateChannelScrollBacks();
911 }
912
getNotebook()913 Notebook * Global::getNotebook() {
914 return(ebook);
915 }
916
filter(const char * s)917 const char * Global::filter(const char *s) {
918 int i,j;
919 string t;
920 gunichar uc;
921 const char *c;
922
923 if (SpecialChars==0) return s; // no filtering
924
925 j = strlen(s);
926 for(i=0;i<j;i++)
927 if (s[i] & 0x80 != 0)
928 break;
929 if (i==j) return(s); // ascii-clean, just return it
930
931 for(c=s;*c!=0;c=g_utf8_next_char(c)) {
932 uc = g_utf8_get_char(c);
933 if (uc<128)
934 t.append( 1, (char) uc );
935 else {
936 switch(SpecialChars) {
937 case 1: break; // truncate
938 case 2: t.append(1,'_'); break; // underscores
939 case 3: unicodeNormalize(t,uc); break; // canonical decomposition
940 }
941 }
942 }
943
944 return(strdup(t.c_str()));
945 }
946
unicodeNormalize(string & dest,gunichar src)947 void Global::unicodeNormalize(string &dest, gunichar src) {
948 gunichar *tmp, tmpbuf[16];
949 gsize i,len;
950
951 #if (GLIB_MAJOR_VERSION==2 && GLIB_MINOR_VERSION >= 30)
952 len = g_unichar_fully_decompose(src, FALSE, tmpbuf, 16);
953 tmp = &tmpbuf[0];
954 #else
955 tmp = g_unicode_canonical_decomposition(src, &len);
956 #endif
957
958 for(i=0;i<len;i++) {
959 if (tmp[i] > 128) {
960 switch(tmp[i]) {
961 case 0x300: tmp[i] = '`'; break; // grave
962 case 0xb4: case 0x301: tmp[i] = '\''; break; // acute
963 case 0x302: tmp[i] = '^'; break; // circumflex
964 case 0x303: tmp[i] = '~'; break; // tilde
965 case 0xb8: case 0x327: tmp[i] = ','; break; // cedil
966 case 0x2d9: case 0x307: tmp[i] = '.'; break; // dot above
967 case 0x308: tmp[i] = '\"'; break; // diaeresis
968 case 0x323: tmp[i] = '.'; break; // dot below
969 default:
970 //cout << "not found: " << ((int) tmp[i]) << endl;
971 tmp[i] = '_';
972 }
973 }
974 dest.append( 1, (char) (tmp[i]&0x7f) );
975 }
976
977 #if (!(GLIB_MAJOR_VERSION==2 && GLIB_MINOR_VERSION >= 30))
978 g_free(tmp);
979 #endif
980 }
981
gatherConsoleState()982 void Global::gatherConsoleState() {
983 list<DetachedConsole *>::iterator i;
984
985 // please make Desk.consoles empty before calling this. Thanks.
986
987 for(i=Consoles.begin();i!=Consoles.end();i++)
988 Desk.addConsole(*i);
989 }
990
991 // malloc has the stupid idea of segfaulting when
992 // allocating a word-incomplete size
safeMalloc(int nbytes)993 void * Global::safeMalloc(int nbytes) {
994 return(malloc(nbytes + (nbytes % 4)));
995 }
996
setPieceSet(string & filename,bool chgPieces,bool chgSquares)997 void Global::setPieceSet(string &filename,bool chgPieces,bool chgSquares) {
998 string oldp,olds;
999 PieceSet *oldset=0;
1000
1001 if (pieceset) {
1002 oldp=pieceset->getName();
1003 olds=pieceset->getSquareName();
1004 oldset=pieceset;
1005 } else {
1006 chgPieces=true;
1007 chgSquares=true;
1008 }
1009
1010 pieceset=new PieceSet(chgPieces?filename:oldp,chgSquares?filename:olds);
1011 if (oldset)
1012 delete oldset;
1013
1014 respawnPieceSet();
1015 }
1016
respawnPieceSet()1017 void Global::respawnPieceSet() {
1018 list<PieceChangeListener *>::iterator i;
1019
1020 // notify all objects that use the pieceset
1021 for(i=PieceClients.begin();i!=PieceClients.end();i++)
1022 (*i)->pieceSetChanged();
1023 }
1024
addPieceClient(PieceChangeListener * pcl)1025 void Global::addPieceClient(PieceChangeListener *pcl) {
1026 global.debug("Global","addPieceClient");
1027 PieceClients.push_back(pcl);
1028 }
1029
removePieceClient(PieceChangeListener * pcl)1030 void Global::removePieceClient(PieceChangeListener *pcl) {
1031 list<PieceChangeListener *>::iterator i;
1032
1033 global.debug("Global","removePieceClient");
1034
1035 for(i=PieceClients.begin();
1036 i!=PieceClients.end();
1037 i++)
1038 if ( (*i) == pcl ) {
1039 PieceClients.erase(i);
1040 return;
1041 }
1042 }
1043
1044 // ----------
1045
HostBookmark()1046 HostBookmark::HostBookmark() {
1047 memset(host,0,128);
1048 memset(protocol,0,64);
1049 port=0;
1050 }
1051
operator ==(HostBookmark * hbm)1052 int HostBookmark::operator==(HostBookmark *hbm) {
1053 if (strcmp(host,hbm->host)) return 0;
1054 if (port!=hbm->port) return 0;
1055 if (strcmp(protocol,hbm->protocol)) return 0;
1056 return 1;
1057 }
1058
operator ==(EngineBookmark * ebm)1059 int EngineBookmark::operator==(EngineBookmark *ebm) {
1060 if (humanwhite != ebm->humanwhite) return 0;
1061 if (timecontrol != ebm->timecontrol) return 0;
1062 if (maxply != ebm->maxply) return 0;
1063 if (think != ebm->think) return 0;
1064 if (proto != ebm->proto) return 0;
1065 if (mode != ebm->mode) return 0;
1066 if (directory.compare(ebm->directory)) return 0;
1067 if (cmdline.compare(ebm->cmdline)) return 0;
1068 return 1;
1069 }
1070
read(tstring & t)1071 void EngineBookmark::read(tstring &t) {
1072 static const char *sep="^\n\r";
1073 string *p;
1074
1075 caption = *(t.token(sep));
1076 directory = *(t.token(sep));
1077 cmdline = *(t.token(sep));
1078 humanwhite = t.tokenvalue(sep);
1079
1080 p = t.token(sep);
1081 if (p)
1082 timecontrol.fromSerialization(p->c_str());
1083
1084 maxply = t.tokenvalue(sep);
1085 think = t.tokenvalue(sep);
1086 proto = t.tokenvalue(sep);
1087 mode = (variant) t.tokenvalue(sep);
1088
1089 if (!directory.compare("NULL")) directory.erase();
1090 if (!cmdline.compare("NULL")) cmdline.erase();
1091 }
1092
1093 // -------------------------------- channel splitting
1094
IcsChannel(char * s)1095 IcsChannel::IcsChannel(char *s) {
1096 static const char *sep="\t\r\n";
1097 tstring t;
1098 t.set(s);
1099 number = t.tokenvalue(sep);
1100 name = * (t.token(sep));
1101 }
1102
getChannels(char * ipaddr)1103 void ChannelSplitter::getChannels(char *ipaddr) {
1104 char destname[512], url[512];
1105 struct stat age;
1106 time_t now, d;
1107 pid_t kid;
1108
1109 global.debug("ChannelSplitter","getChannels",ipaddr);
1110 channels.clear();
1111
1112 if (! global.RetrieveChannelNames)
1113 return;
1114
1115 snprintf(destname,512,"/tmp/eboard-chlist-%s-%d.tmp", ipaddr, getuid() );
1116 chlist=destname;
1117
1118 if (stat(destname, &age)==0) {
1119 now=time(0);
1120 d = now - age.st_mtime;
1121 // list expires after 8 hours
1122 if (d < 28800)
1123 goto cs_gc_use_current;
1124 }
1125
1126 snprintf(url,512,"http://www.bergo.eng.br/eboard/ics/%s.txt",ipaddr);
1127
1128 kid=fork();
1129 if (kid==0) {
1130
1131 execlp("wget","wget","-q","-O",destname,url,0);
1132 _exit(0);
1133
1134 } else {
1135
1136 global.zombies.add(kid, this);
1137
1138 }
1139
1140 cs_gc_use_current:
1141 parseChannelList();
1142
1143 }
1144
ZombieNotification(int pid)1145 void ChannelSplitter::ZombieNotification(int pid) {
1146 parseChannelList();
1147 }
1148
parseChannelList()1149 void ChannelSplitter::parseChannelList() {
1150 char s[512];
1151
1152 global.debug("ChannelSplitter","parseChannelList");
1153 channels.clear();
1154
1155 ifstream f(chlist.c_str());
1156 if (!f) {
1157 global.debug("ChannelSplitter","parseChannelList","can't read file");
1158 return;
1159 }
1160
1161 if (memset(s,0,512), f.getline(s,511,'\n')) {
1162
1163 if (strstr(s,"text/ics-channel-list")) {
1164 while( memset(s,0,512), f.getline(s,511,'\n') ) {
1165 if (!isdigit(s[0])) break;
1166 channels.push_back( IcsChannel(s) );
1167 }
1168 }
1169
1170 }
1171
1172 f.close();
1173 }
1174
getChannelTitle(int n)1175 const char * ChannelSplitter::getChannelTitle(int n) {
1176 int i,j;
1177 static char z[128];
1178 j=channels.size();
1179 for(i=0;i<j;i++) {
1180 if (n==channels[i].number) {
1181 snprintf(z,128,"#%d: %s",n,channels[i].name.c_str());
1182 return z;
1183 }
1184 }
1185 snprintf(z,128,"#%d",n);
1186 return z;
1187 }
1188
ensurePane(int ch)1189 void ChannelSplitter::ensurePane(int ch) {
1190 int i,j;
1191 j=panes.size();
1192 for(i=0;i<j;i++)
1193 if (numbers[i]==ch)
1194 return; // already exists
1195 createPane(ch);
1196 }
1197
createPane(int ch)1198 void ChannelSplitter::createPane(int ch) {
1199 Notebook *nb;
1200 Text *op;
1201 char z[64];
1202 nb=getNotebook();
1203 if (!nb) return;
1204 op=new Text();
1205
1206 snprintf(z,64,"%s",getChannelTitle(ch) );
1207
1208 op->show();
1209 nb->addPage(op->widget,z,-200-ch,true);
1210 op->setNotebook(nb,-200-ch);
1211 numbers.push_back(ch);
1212 panes.push_back(op);
1213 }
1214
channelPageUp(int ch)1215 void ChannelSplitter::channelPageUp(int ch) {
1216 int i,j;
1217 j=panes.size();
1218 for(i=0;i<j;i++)
1219 if (numbers[i] == ch) {
1220 panes[i]->pageUp();
1221 return;
1222 }
1223 }
1224
channelPageDown(int ch)1225 void ChannelSplitter::channelPageDown(int ch) {
1226 int i,j;
1227 j=panes.size();
1228 for(i=0;i<j;i++)
1229 if (numbers[i] == ch) {
1230 panes[i]->pageDown();
1231 return;
1232 }
1233 }
1234
appendToChannel(int ch,char * msg,int color,Importance im)1235 void ChannelSplitter::appendToChannel(int ch,char *msg,int color,Importance im) {
1236 int i,j;
1237 ensurePane(ch);
1238 j=panes.size();
1239 for(i=0;i<j;i++)
1240 if (numbers[i]==ch) {
1241 panes[i]->append(msg,color,im);
1242 panes[i]->contentUpdated();
1243 return;
1244 }
1245 }
1246
removeRemovablePage(int n)1247 void ChannelSplitter::removeRemovablePage(int n) {
1248 int rn;
1249 int i,j;
1250 Notebook *nb;
1251
1252 rn= -n;
1253 rn-=200;
1254 nb=getNotebook();
1255
1256 j=panes.size();
1257 for(i=0;i<j;i++)
1258 if (numbers[i]==rn) {
1259 nb->removePage(n);
1260 delete panes[i];
1261 panes.erase(panes.begin() + i);
1262 numbers.erase(numbers.begin() + i);
1263 }
1264 }
1265
updateChannelScrollBacks()1266 void ChannelSplitter::updateChannelScrollBacks() {
1267 int i,j;
1268 j=panes.size();
1269 for(i=0;i<j;i++)
1270 panes[i]->updateScrollBack();
1271 }
1272
updateFont()1273 void ChannelSplitter::updateFont() {
1274 int i,j;
1275 j=panes.size();
1276 for(i=0;i<j;i++)
1277 panes[i]->updateFont();
1278 }
1279
TerminalColor()1280 TerminalColor::TerminalColor() {
1281 TextDefault = 0xeeeeee;
1282 TextBright = 0xffffff;
1283 PrivateTell = 0xffff00;
1284 NewsNotify = 0xff8080;
1285 Mamer = 0xffdd00;
1286 KibitzWhisper = 0xd38fd3;
1287 Shouts = 0xddffdd;
1288 Seeks = 0x80ff80;
1289 ChannelTell = 0x3cd9d1;
1290 Engine = 0xc0ff60;
1291 Background = 0;
1292 }
1293
read(tstring & t)1294 void TerminalColor::read(tstring &t) {
1295 static const char *comma=",:\n\r \t";
1296
1297 TextDefault = t.tokenvalue(comma,16);
1298 TextBright = t.tokenvalue(comma,16);
1299 PrivateTell = t.tokenvalue(comma,16);
1300 NewsNotify = t.tokenvalue(comma,16);
1301 Mamer = t.tokenvalue(comma,16);
1302 KibitzWhisper = t.tokenvalue(comma,16);
1303 Shouts = t.tokenvalue(comma,16);
1304 Seeks = t.tokenvalue(comma,16);
1305 ChannelTell = t.tokenvalue(comma,16);
1306 Engine = t.tokenvalue(comma,16);
1307 Background = t.tokenvalue(comma,16);
1308 }
1309
1310 // ---- desktop saving
1311
WindowGeometry(int a,int b,int c,int d)1312 WindowGeometry::WindowGeometry(int a,int b,int c,int d) {
1313 X=a; Y=b; W=c; H=d;
1314 }
1315
WindowGeometry()1316 WindowGeometry::WindowGeometry() {
1317 setNull();
1318 }
1319
print()1320 void WindowGeometry::print() {
1321 cout << "X,Y,W,H = " << X << "," << Y << "," << W << "," << H << endl;
1322 }
1323
retrieve(GtkWidget * w)1324 void WindowGeometry::retrieve(GtkWidget *w) {
1325 gint a[7];
1326 gdk_window_get_geometry(w->window,a,a+1,a+2,a+3,a+4);
1327 gdk_window_get_origin(w->window,a+5,a+6);
1328 X=a[5]-a[0];
1329 Y=a[6]-a[1];
1330 W=a[2];
1331 H=a[3];
1332 }
1333
isNull()1334 bool WindowGeometry::isNull() {
1335 return( (X==0)&&(Y==0)&&(W==0)&&(H==0) );
1336 }
1337
setNull()1338 void WindowGeometry::setNull() {
1339 X=Y=W=H=0;
1340 }
1341
read(tstring & t)1342 void WindowGeometry::read(tstring &t) {
1343 static const char *sep=":,()\n\t\r ";
1344 X=t.tokenvalue(sep);
1345 Y=t.tokenvalue(sep);
1346 W=t.tokenvalue(sep);
1347 H=t.tokenvalue(sep);
1348 }
1349
1350 // --------
1351
Desktop()1352 Desktop::Desktop() {
1353 clear();
1354 }
1355
clear()1356 void Desktop::clear() {
1357 vector<WindowGeometry *>::iterator i;
1358 vector<string *>::iterator j;
1359
1360 wMain.setNull();
1361 wGames.setNull();
1362 wLocal.setNull();
1363 wAds.setNull();
1364
1365 for(i=consoles.begin();i!=consoles.end();i++)
1366 delete(*i);
1367
1368 for(j=cfilters.begin();j!=cfilters.end();j++)
1369 delete(*j);
1370
1371 consoles.clear();
1372 cfilters.clear();
1373 PanePosition = 0;
1374 }
1375
read(tstring & t)1376 void Desktop::read(tstring &t) {
1377 static const char *sep=":,()\n\t\r ";
1378 wMain.read(t);
1379 wGames.read(t);
1380 wLocal.read(t);
1381 wAds.read(t);
1382 global.Desk.PanePosition = t.tokenvalue(sep);
1383 }
1384
writeConsoles(ostream & s,const char * key)1385 void Desktop::writeConsoles(ostream &s, const char *key) {
1386 int i,j;
1387 j=consoles.size();
1388 for(i=0;i<j;i++) {
1389 s << key << "::" << (*consoles[i]);
1390 s << (*(cfilters[i])) << endl;
1391 }
1392 }
1393
readConsole(tstring & t)1394 void Desktop::readConsole(tstring &t) {
1395 WindowGeometry *wg;
1396 string *p,*s;
1397 static const char *sep="\n\r";
1398
1399 wg=new WindowGeometry();
1400 wg->read(t);
1401
1402 p=t.token(sep);
1403 s=new string();
1404 if (p) (*s)=(*p);
1405
1406 consoles.push_back(wg);
1407 cfilters.push_back(s);
1408 }
1409
addConsole(DetachedConsole * dc)1410 void Desktop::addConsole(DetachedConsole *dc) {
1411 WindowGeometry *wg;
1412 wg=new WindowGeometry();
1413 wg->retrieve(dc->widget);
1414 consoles.push_back(wg);
1415 cfilters.push_back(new string(dc->getFilter()));
1416 }
1417
spawnConsoles(TextSet * ts)1418 void Desktop::spawnConsoles(TextSet *ts) {
1419 int i,j;
1420 char tmp[512];
1421 DetachedConsole *dc;
1422 j=consoles.size();
1423
1424 for(i=0;i<j;i++) {
1425 dc=new DetachedConsole(ts,0);
1426 dc->show();
1427 dc->restorePosition(consoles[i]);
1428 if (cfilters[i]->size()) {
1429 g_strlcpy(tmp,cfilters[i]->c_str(),512);
1430 dc->setFilter(tmp);
1431 }
1432 }
1433 }
1434
1435 // ------- ah, the zombies
1436
ZombieHunter()1437 ZombieHunter::ZombieHunter() {
1438 signal(SIGCHLD,zh_sigchild_handler);
1439 }
1440
~ZombieHunter()1441 ZombieHunter::~ZombieHunter() {
1442 pids.clear();
1443 handlers.clear();
1444 }
1445
add(int pid,SigChildHandler * sigh)1446 void ZombieHunter::add(int pid, SigChildHandler *sigh) {
1447 pids.push_back(pid);
1448 handlers.push_back(sigh);
1449 }
1450
handleSigChild()1451 void ZombieHunter::handleSigChild() {
1452 pid_t epid;
1453 unsigned int i;
1454 int s;
1455
1456 while ( ( epid = waitpid(-1,&s,WNOHANG) ) > 0 ) {
1457 for(i=0;i<pids.size();i++)
1458 if (pids[i] == epid) {
1459 if (handlers[i] != 0) handlers[i]->ZombieNotification(epid);
1460 pids.erase(pids.begin() + i);
1461 handlers.erase(handlers.begin() + i);
1462 break;
1463 }
1464 }
1465 }
1466
zh_sigchild_handler(int sig)1467 void zh_sigchild_handler(int sig) {
1468 if (sig == SIGCHLD)
1469 global.zombies.handleSigChild();
1470 }
1471
Environment()1472 Environment::Environment() {
1473 char *p;
1474
1475 p=getenv("HOME");
1476 if (p) {
1477 Home=p;
1478 } else {
1479 Home.erase();
1480 cerr << _("** eboard ** warning: HOME environment variable not set\n");
1481 }
1482
1483 p=getenv("USER");
1484 if (p) {
1485 User=p;
1486 } else {
1487 User=_("Human");
1488 }
1489
1490 if (!Home.empty()) {
1491 Config=Home;
1492 Config+="/.eboard/eboard.conf";
1493 } else {
1494 Config.erase();
1495 }
1496 }
1497
1498
1499
1500