Root/src/linkapp.cpp

1/***************************************************************************
2 * Copyright (C) 2006 by Massimiliano Torromeo *
3 * massimiliano.torromeo@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program 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. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <sys/ioctl.h>
23#include <signal.h>
24#include <unistd.h>
25
26#include <fstream>
27#include <sstream>
28
29#include "linkapp.h"
30#include "menu.h"
31#include "selector.h"
32#include "textmanualdialog.h"
33#include "debug.h"
34
35using namespace std;
36
37LinkApp::LinkApp(GMenu2X *gmenu2x_, InputManager &inputMgr_,
38                 const char* linkfile)
39    : Link(gmenu2x_)
40    , inputMgr(inputMgr_)
41{
42    manual = "";
43    file = linkfile;
44    wrapper = false;
45    dontleave = false;
46    setClock(336);
47    setVolume(-1);
48    //G
49    //setGamma(0);
50    setBacklight(-1);
51    selectordir = "";
52    selectorfilter = "";
53    icon = iconPath = "";
54    selectorbrowser = false;
55    useRamTimings = false;
56
57    string line;
58    ifstream infile (linkfile, ios_base::in);
59    while (getline(infile, line, '\n')) {
60        line = trim(line);
61        if (line=="") continue;
62        if (line[0]=='#') continue;
63
64        string::size_type position = line.find("=");
65        string name = trim(line.substr(0,position));
66        string value = trim(line.substr(position+1));
67        if (name == "title") {
68            title = value;
69        } else if (name == "description") {
70            description = value;
71        } else if (name == "icon") {
72            setIcon(value);
73        } else if (name == "exec") {
74            exec = value;
75        } else if (name == "params") {
76            params = value;
77        } else if (name == "workdir") {
78            workdir = value;
79        } else if (name == "manual") {
80            manual = value;
81        } else if (name == "wrapper") {
82            if (value=="true") wrapper = true;
83        } else if (name == "dontleave") {
84            if (value=="true") dontleave = true;
85        } else if (name == "clock") {
86            setClock( atoi(value.c_str()) );
87        //G
88        } else if (name == "gamma") {
89            setGamma( atoi(value.c_str()) );
90        } else if (name == "backlight") {
91            setBacklight( atoi(value.c_str()) );
92        } else if (name == "volume") {
93            setVolume( atoi(value.c_str()) );
94        } else if (name == "selectordir") {
95            setSelectorDir( value );
96        } else if (name == "selectorbrowser") {
97            if (value=="true") selectorbrowser = true;
98        } else if (name == "useramtimings") {
99            if (value=="true") useRamTimings = true;
100        } else if (name == "selectorfilter") {
101            setSelectorFilter( value );
102        } else if (name == "selectorscreens") {
103            setSelectorScreens( value );
104        } else if (name == "selectoraliases") {
105            setAliasFile( value );
106        } else {
107            WARNING("Unrecognized option: '%s'\n", name.c_str());
108            break;
109        }
110    }
111    infile.close();
112
113    if (iconPath.empty()) searchIcon();
114
115    edited = false;
116}
117
118const string &LinkApp::searchIcon() {
119    string execicon = exec;
120    string::size_type pos = exec.rfind(".");
121    if (pos != string::npos) execicon = exec.substr(0,pos);
122    execicon += ".png";
123    string exectitle = execicon;
124    pos = execicon.rfind("/");
125    if (pos != string::npos)
126        string exectitle = execicon.substr(pos+1,execicon.length());
127
128    if (!gmenu2x->sc.getSkinFilePath("icons/"+exectitle).empty())
129        iconPath = gmenu2x->sc.getSkinFilePath("icons/"+exectitle);
130    else if (fileExists(execicon))
131        iconPath = execicon;
132    else
133        iconPath = gmenu2x->sc.getSkinFilePath("icons/generic.png");
134
135    return iconPath;
136}
137
138int LinkApp::clock() {
139    return iclock;
140}
141
142const string &LinkApp::clockStr(int maxClock) {
143    if (iclock>maxClock) setClock(maxClock);
144    return sclock;
145}
146
147void LinkApp::setClock(int mhz) {
148    iclock = constrain(mhz,200,430);
149    stringstream ss;
150    sclock = "";
151    ss << iclock << "Mhz";
152    ss >> sclock;
153
154    edited = true;
155}
156
157int LinkApp::volume() {
158    return ivolume;
159}
160
161const string &LinkApp::volumeStr() {
162    return svolume;
163}
164
165void LinkApp::setVolume(int vol) {
166    ivolume = constrain(vol,-1,100);
167    stringstream ss;
168    svolume = "";
169    if (ivolume<0)
170        ss << gmenu2x->confInt["globalVolume"];
171    else
172        ss << ivolume;
173    ss >> svolume;
174
175    edited = true;
176}
177
178int LinkApp::backlight()
179{
180    return ibacklight;
181}
182
183const string &LinkApp::backlightStr()
184{
185    return sbacklight;
186}
187
188void LinkApp::setBacklight(int val)
189{
190    ibacklight = constrain(val,-1,100);
191    stringstream ss;
192    sbacklight = "";
193    ss << ibacklight;
194    ss >> sbacklight;
195
196    edited = true;
197}
198//G
199int LinkApp::gamma() {
200    return igamma;
201}
202
203const string &LinkApp::gammaStr() {
204    return sgamma;
205}
206
207void LinkApp::setGamma(int gamma) {
208    igamma = constrain(gamma,0,100);
209    stringstream ss;
210    sgamma = "";
211    ss << igamma;
212    ss >> sgamma;
213
214    edited = true;
215}
216// /G
217
218bool LinkApp::targetExists() {
219#ifndef TARGET_GP2X
220    return true; //For displaying elements during testing on pc
221#endif
222
223    string target = exec;
224    if (!exec.empty() && exec[0]!='/' && !workdir.empty())
225        target = workdir + "/" + exec;
226
227    return fileExists(target);
228}
229
230bool LinkApp::save() {
231    if (!edited) return false;
232
233    ofstream f(file.c_str());
234    if (f.is_open()) {
235        if (title!="" ) f << "title=" << title << endl;
236        if (description!="" ) f << "description=" << description << endl;
237        if (icon!="" ) f << "icon=" << icon << endl;
238        if (exec!="" ) f << "exec=" << exec << endl;
239        if (params!="" ) f << "params=" << params << endl;
240        if (workdir!="" ) f << "workdir=" << workdir << endl;
241        if (manual!="" ) f << "manual=" << manual << endl;
242        if (iclock!=0 ) f << "clock=" << iclock << endl;
243        if (useRamTimings ) f << "useramtimings=true" << endl;
244        if (ivolume>0 ) f << "volume=" << ivolume << endl;
245        //G
246        if (igamma!=0 ) f << "gamma=" << igamma << endl;
247        if (ibacklight!=0 ) f << "backlight=" << ibacklight << endl;
248        if (selectordir!="" ) f << "selectordir=" << selectordir << endl;
249        if (selectorbrowser ) f << "selectorbrowser=true" << endl;
250        if (selectorfilter!="" ) f << "selectorfilter=" << selectorfilter << endl;
251        if (selectorscreens!="") f << "selectorscreens=" << selectorscreens << endl;
252        if (aliasfile!="" ) f << "selectoraliases=" << aliasfile << endl;
253        if (wrapper ) f << "wrapper=true" << endl;
254        if (dontleave ) f << "dontleave=true" << endl;
255        f.close();
256        sync();
257        return true;
258    } else
259        ERROR("Error while opening the file '%s' for write.\n", file.c_str());
260    return false;
261}
262
263void LinkApp::drawRun() {
264    //Darkened background
265    gmenu2x->s->box(0, 0, gmenu2x->resX, gmenu2x->resY, 0,0,0,150);
266
267    string text = gmenu2x->tr.translate("Launching $1",getTitle().c_str(),NULL);
268    int textW = gmenu2x->font->getTextWidth(text);
269    int boxW = 62+textW;
270    int halfBoxW = boxW/2;
271
272    //outer box
273    gmenu2x->s->box(gmenu2x->halfX-2-halfBoxW, gmenu2x->halfY-23, halfBoxW*2+5, 47, gmenu2x->skinConfColors[COLOR_MESSAGE_BOX_BG]);
274    //inner rectangle
275    gmenu2x->s->rectangle(gmenu2x->halfX-halfBoxW, gmenu2x->halfY-21, boxW, 42, gmenu2x->skinConfColors[COLOR_MESSAGE_BOX_BORDER]);
276
277    int x = gmenu2x->halfX+10-halfBoxW;
278    /*if (getIcon()!="")
279        gmenu2x->sc[getIcon()]->blit(gmenu2x->s,x,104);
280    else
281        gmenu2x->sc["icons/generic.png"]->blit(gmenu2x->s,x,104);*/
282    gmenu2x->sc[getIconPath()]->blit(gmenu2x->s,x,gmenu2x->halfY-16);
283    gmenu2x->s->write( gmenu2x->font, text, x+42, gmenu2x->halfY+1, ASFont::HAlignLeft, ASFont::VAlignMiddle );
284    gmenu2x->s->flip();
285}
286
287void LinkApp::run() {
288    if (selectordir!="")
289        selector();
290    else
291        launch();
292}
293
294void LinkApp::showManual() {
295    if (manual=="" || !fileExists(manual)) return;
296
297    // Png manuals
298    string ext8 = manual.substr(manual.size()-8,8);
299    if (ext8==".man.png" || ext8==".man.bmp" || ext8==".man.jpg" || manual.substr(manual.size()-9,9)==".man.jpeg") {
300        //Raise the clock to speed-up the loading of the manual
301        gmenu2x->setClock(336);
302
303        Surface pngman(manual);
304        // Note: Copy constructor converts to display format.
305        Surface bg(Surface(gmenu2x->confStr["wallpaper"]));
306        stringstream ss;
307        string pageStatus;
308
309        bool close = false, repaint = true;
310        int page=0, pagecount=pngman.raw->w/320;
311
312        ss << pagecount;
313        string spagecount;
314        ss >> spagecount;
315
316        //Lower the clock
317        gmenu2x->setClock(gmenu2x->confInt["menuClock"]);
318
319        while (!close) {
320            if (repaint) {
321                bg.blit(gmenu2x->s, 0, 0);
322                pngman.blit(gmenu2x->s, -page*320, 0);
323
324                gmenu2x->drawBottomBar();
325                gmenu2x->drawButton(gmenu2x->s, "x", gmenu2x->tr["Exit"],
326                gmenu2x->drawButton(gmenu2x->s, "right", gmenu2x->tr["Change page"],
327                gmenu2x->drawButton(gmenu2x->s, "left", "", 5)-10));
328
329                ss.clear();
330                ss << page+1;
331                ss >> pageStatus;
332                pageStatus = gmenu2x->tr["Page"]+": "+pageStatus+"/"+spagecount;
333                gmenu2x->s->write(gmenu2x->font, pageStatus, 310, 230, ASFont::HAlignRight, ASFont::VAlignMiddle);
334
335                gmenu2x->s->flip();
336                repaint = false;
337            }
338
339            switch(inputMgr.waitForPressedButton()) {
340                case MANUAL:
341                case CLEAR:
342                case SETTINGS:
343                    close = true;
344                    break;
345                case LEFT:
346                    if (page > 0) {
347                        page--;
348                        repaint = true;
349                    }
350                    break;
351                case RIGHT:
352                    if (page < pagecount-1) {
353                        page++;
354                        repaint=true;
355                    }
356                    break;
357                default:
358                    break;
359            }
360        }
361        return;
362    }
363
364    // Txt manuals
365    if (manual.substr(manual.size()-8,8)==".man.txt") {
366        vector<string> txtman;
367
368        string line;
369        ifstream infile(manual.c_str(), ios_base::in);
370        if (infile.is_open()) {
371            gmenu2x->setClock(336);
372            while (getline(infile, line, '\n')) txtman.push_back(line);
373            infile.close();
374
375            TextManualDialog tmd(gmenu2x, getTitle(), getIconPath(), &txtman);
376            gmenu2x->setClock(gmenu2x->confInt["menuClock"]);
377            tmd.exec();
378        }
379
380        return;
381    }
382
383    //Readmes
384    vector<string> readme;
385
386    string line;
387    ifstream infile(manual.c_str(), ios_base::in);
388    if (infile.is_open()) {
389        gmenu2x->setClock(336);
390        while (getline(infile, line, '\n')) readme.push_back(line);
391        infile.close();
392
393        TextDialog td(gmenu2x, getTitle(), "ReadMe", getIconPath(), &readme);
394        gmenu2x->setClock(gmenu2x->confInt["menuClock"]);
395        td.exec();
396    }
397}
398
399void LinkApp::selector(int startSelection, const string &selectorDir) {
400    //Run selector interface
401    Selector sel(gmenu2x, this, selectorDir);
402    int selection = sel.exec(startSelection);
403    if (selection!=-1) {
404        gmenu2x->writeTmp(selection, sel.getDir());
405        launch(sel.getFile(), sel.getDir());
406    }
407}
408
409void LinkApp::launch(const string &selectedFile, const string &selectedDir) {
410    drawRun();
411    save();
412#ifndef TARGET_GP2X
413    //delay for testing
414    SDL_Delay(1000);
415#endif
416
417    //Set correct working directory
418    string wd = workdir;
419    if (wd=="") {
420        string::size_type pos = exec.rfind("/");
421        if (pos!=string::npos)
422            wd = exec.substr(0,pos);
423    }
424    if (!wd.empty()) {
425        if (wd[0]!='/') wd = gmenu2x->getExePath() + wd;
426        chdir(wd.c_str());
427    }
428
429    //selectedFile
430    if (selectedFile!="") {
431        string selectedFileExtension;
432        string selectedFileName;
433        string dir;
434        string::size_type i = selectedFile.rfind(".");
435        if (i != string::npos) {
436            selectedFileExtension = selectedFile.substr(i,selectedFile.length());
437            selectedFileName = selectedFile.substr(0,i);
438        }
439
440        if (selectedDir=="")
441            dir = getSelectorDir();
442        else
443            dir = selectedDir;
444        if (params=="") {
445            params = cmdclean(dir+selectedFile);
446        } else {
447            string origParams = params;
448            params = strreplace(params,"[selFullPath]",cmdclean(dir+selectedFile));
449            params = strreplace(params,"[selPath]",cmdclean(dir));
450            params = strreplace(params,"[selFile]",cmdclean(selectedFileName));
451            params = strreplace(params,"[selExt]",cmdclean(selectedFileExtension));
452            if (params == origParams) params += " " + cmdclean(dir+selectedFile);
453        }
454    }
455
456    if (useRamTimings)
457        gmenu2x->applyRamTimings();
458    if (volume()>=0)
459        gmenu2x->setVolume(volume());
460
461    INFO("Executing '%s' (%s %s)\n", title.c_str(), exec.c_str(), params.c_str());
462
463    //check if we have to quit
464    string command = cmdclean(exec);
465
466    // Check to see if permissions are desirable
467    struct stat fstat;
468    if( stat( command.c_str(), &fstat ) == 0 ) {
469        struct stat newstat = fstat;
470        if( S_IRUSR != ( fstat.st_mode & S_IRUSR ) )
471            newstat.st_mode |= S_IRUSR;
472        if( S_IXUSR != ( fstat.st_mode & S_IXUSR ) )
473            newstat.st_mode |= S_IXUSR;
474        if( fstat.st_mode != newstat.st_mode )
475            chmod( command.c_str(), newstat.st_mode );
476    } // else, well.. we are no worse off :)
477
478    if (params!="") command += " " + params;
479    if (gmenu2x->confInt["outputLogs"]) command += " &> " + cmdclean(gmenu2x->getHome()) + "/log.txt";
480    if (wrapper) command += "; sync & cd "+cmdclean(gmenu2x->getExePath())+"; exec ./gmenu2x";
481    if (dontleave) {
482        system(command.c_str());
483    } else {
484        if (gmenu2x->confInt["saveSelection"] && (gmenu2x->confInt["section"]!=gmenu2x->menu->selSectionIndex() || gmenu2x->confInt["link"]!=gmenu2x->menu->selLinkIndex()))
485            gmenu2x->writeConfig();
486        if (gmenu2x->fwType == "open2x" && gmenu2x->savedVolumeMode != gmenu2x->volumeMode)
487            gmenu2x->writeConfigOpen2x();
488        if (selectedFile=="")
489            gmenu2x->writeTmp();
490             gmenu2x->quit();
491        if (clock()!=gmenu2x->confInt["menuClock"])
492            gmenu2x->setClock(clock());
493        //if (gamma()!=0 && gamma()!=gmenu2x->confInt["gamma"])
494        // gmenu2x->setGamma(gamma());
495        if((backlight() != 0) && (backlight() != gmenu2x->confInt["backlight"]))
496            gmenu2x->setBacklight(backlight());
497
498        /* Make the terminal we're connected to (via stdin/stdout) our
499                 contolling terminal again. Else many console programs are
500                 not going to work correctly. Actually this would not be
501                 necessary, if SDL correctly restored terminal state after
502                 SDL_Quit(). */
503        int pid = setsid();
504        ioctl(1, TIOCSCTTY, STDOUT_FILENO);
505
506        int pgid = tcgetpgrp(STDOUT_FILENO);
507        signal(SIGTTOU, SIG_IGN);
508        tcsetpgrp(STDOUT_FILENO, pgid);
509
510        execlp("/bin/sh","/bin/sh","-c",command.c_str(),NULL);
511        //if execution continues then something went wrong and as we already called SDL_Quit we cannot continue
512        //try relaunching gmenu2x
513        chdir(gmenu2x->getExePath().c_str());
514        execlp("./gmenu2x", "./gmenu2x", NULL);
515    }
516
517
518    chdir(gmenu2x->getExePath().c_str());
519}
520
521const string &LinkApp::getExec() {
522    return exec;
523}
524
525void LinkApp::setExec(const string &exec) {
526    this->exec = exec;
527    edited = true;
528}
529
530const string &LinkApp::getParams() {
531    return params;
532}
533
534void LinkApp::setParams(const string &params) {
535    this->params = params;
536    edited = true;
537}
538
539const string &LinkApp::getWorkdir() {
540    return workdir;
541}
542
543void LinkApp::setWorkdir(const string &workdir) {
544    this->workdir = workdir;
545    edited = true;
546}
547
548const string &LinkApp::getManual() {
549    return manual;
550}
551
552void LinkApp::setManual(const string &manual) {
553    this->manual = manual;
554    edited = true;
555}
556
557const string &LinkApp::getSelectorDir() {
558    return selectordir;
559}
560
561void LinkApp::setSelectorDir(const string &selectordir) {
562    this->selectordir = selectordir;
563    if (this->selectordir!="" && this->selectordir[this->selectordir.length()-1]!='/') this->selectordir += "/";
564    edited = true;
565}
566
567bool LinkApp::getSelectorBrowser() {
568    return selectorbrowser;
569}
570
571void LinkApp::setSelectorBrowser(bool value) {
572    selectorbrowser = value;
573    edited = true;
574}
575
576bool LinkApp::getUseRamTimings() {
577    return useRamTimings;
578}
579
580void LinkApp::setUseRamTimings(bool value) {
581    useRamTimings = value;
582    edited = true;
583}
584
585const string &LinkApp::getSelectorFilter() {
586    return selectorfilter;
587}
588
589void LinkApp::setSelectorFilter(const string &selectorfilter) {
590    this->selectorfilter = selectorfilter;
591    edited = true;
592}
593
594const string &LinkApp::getSelectorScreens() {
595    return selectorscreens;
596}
597
598void LinkApp::setSelectorScreens(const string &selectorscreens) {
599    this->selectorscreens = selectorscreens;
600    edited = true;
601}
602
603const string &LinkApp::getAliasFile() {
604    return aliasfile;
605}
606
607void LinkApp::setAliasFile(const string &aliasfile) {
608    if (fileExists(aliasfile)) {
609        this->aliasfile = aliasfile;
610        edited = true;
611    }
612}
613
614void LinkApp::renameFile(const string &name) {
615    file = name;
616}
617

Archive Download this file



interactive