1 #include "application.moc"
2 Application application;
3 
4 #include "init.cpp"
5 #include "qb.cpp"
6 
initPaths(const char * basename)7 void Application::initPaths(const char *basename) {
8   char temp[PATH_MAX];
9 
10   if(realpath(basename, temp)) {
11     //remove program name
12     strtr(temp, "\\", "/");
13     for(signed i = strlen(temp) - 1; i >= 0; i--) {
14       if(temp[i] == '/') {
15         temp[i] = 0;
16         break;
17       }
18     }
19 
20     if(strend(temp, "/") == false) strcat(temp, "/");
21     config().path.base = temp;
22   } else {
23     config().path.base = "";
24   }
25 
26   if(userpath(temp)) {
27     strtr(temp, "\\", "/");
28     if(strend(temp, "/") == false) strcat(temp, "/");
29     config().path.user = temp;
30   } else {
31     config().path.user = "";
32   }
33 
34   char cwd[PATH_MAX];
35   config().path.startup = getcwd(cwd);
36 }
37 
locateFile(string & filename,bool createDataDirectory)38 void Application::locateFile(string &filename, bool createDataDirectory) {
39   //first, check if file exists in executable directory (single-user mode)
40   string temp = string() << config().path.base << filename;
41 
42   if(file::exists(temp) == false) {
43     //if not, use user data path (multi-user mode)
44     temp = config().path.user;
45     temp << ".bsnes";
46     if(createDataDirectory) mkdir(temp);  //ensure directory exists
47     temp << "/" << filename;
48   }
49 
50   filename = temp;
51 }
52 
main(int & argc,char ** argv)53 int Application::main(int &argc, char **argv) {
54   app = new App(argc, argv);
55   #if !defined(PLATFORM_WIN)
56   //Windows port uses 256x256 icon from resource file
57   app->setWindowIcon(QIcon(":/bsnes.png"));
58   #endif
59 
60   initargs(argc, argv);  //ensure argv[]s are in UTF-8 format
61   initPaths(argv[0]);
62   locateFile(configFilename = "bsnes.cfg", true);
63   locateFile(styleSheetFilename = "style.qss", false);
64 
65   string customStylesheet;
66   if(customStylesheet.readfile(styleSheetFilename) == true) {
67     app->setStyleSheet((const char*)customStylesheet);
68   } else {
69     app->setStyleSheet(defaultStylesheet);
70   }
71 
72   config().load(configFilename);
73   mapper().bind();
74   init();
75   SNES::system.init(&interface);
76   mainWindow->system_loadSpecial_superGameBoy->setVisible(SNES::supergameboy.opened());
77 
78   if(argc == 2) {
79     //if valid file was specified on the command-line, attempt to load it now
80     cartridge.loadNormal(argv[1]);
81   }
82 
83   timer = new QTimer(this);
84   connect(timer, SIGNAL(timeout()), this, SLOT(run()));
85   timer->start(0);
86   app->exec();
87 
88   //QbWindow::hide() saves window geometry for next run
89   for(unsigned i = 0; i < windowList.size(); i++) {
90     windowList[i]->hide();
91   }
92 
93   cartridge.unload();
94   config().save(configFilename);
95   return 0;
96 }
97 
run()98 void Application::run() {
99   if(terminate == true) {
100     timer->stop();
101     app->quit();
102     return;
103   }
104 
105   QApplication::processEvents();
106   utility.updateSystemState();
107   mapper().poll();
108 
109   if(config().input.focusPolicy == Configuration::Input::FocusPolicyPauseEmulation) {
110     bool active = mainWindow->isActive();
111     if(!autopause && !active) {
112       autopause = true;
113       audio.clear();
114     } else if(autopause && active) {
115       autopause = false;
116     }
117   } else {
118     autopause = false;
119   }
120 
121   if(SNES::cartridge.loaded() && !pause && !autopause && (!debug || debugrun)) {
122     SNES::system.run();
123     #if defined(DEBUGGER)
124     if(SNES::debugger.break_event != SNES::Debugger::None) {
125       debug = true;
126       debugrun = false;
127       debugger->synchronize();
128       debugger->event();
129       SNES::debugger.break_event = SNES::Debugger::None;
130     }
131     #endif
132   } else {
133     usleep(20 * 1000);
134   }
135 
136   clock_t currentTime = clock();
137   autosaveTime += currentTime - clockTime;
138   screensaverTime += currentTime - clockTime;
139   clockTime = currentTime;
140 
141   if(autosaveTime >= CLOCKS_PER_SEC * 60) {
142     //auto-save RAM once per minute in case of emulator crash
143     autosaveTime = 0;
144     if(config().system.autoSaveMemory == true) cartridge.saveMemory();
145   }
146 
147   if(screensaverTime >= CLOCKS_PER_SEC * 30) {
148     //supress screen saver every 30 seconds so it will not trigger during gameplay
149     screensaverTime = 0;
150     supressScreenSaver();
151   }
152 }
153 
Application()154 Application::Application() : timer(0) {
155   terminate = false;
156   power     = false;
157   pause     = false;
158   autopause = false;
159   debug     = false;
160   debugrun  = false;
161 
162   clockTime       = clock();
163   autosaveTime    = 0;
164   screensaverTime = 0;
165 }
166 
~Application()167 Application::~Application() {
168   delete timer;
169 
170   //deleting (QApplication)app will segfault the application upon exit
171   //delete app;
172 }
173