bootmanager.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #include <QHBoxLayout>
  2. #include <QKeyEvent>
  3. #include "common/common.h"
  4. #include "bootmanager.hxx"
  5. #include "core/core.h"
  6. #include "core/loader.h"
  7. #include "video_core/video_core.h"
  8. #include "version.h"
  9. #define APP_NAME "citra"
  10. #define APP_VERSION "0.1-" VERSION
  11. #define APP_TITLE APP_NAME " " APP_VERSION
  12. #define COPYRIGHT "Copyright (C) 2013-2014 Citra Team"
  13. EmuThread::EmuThread(GRenderWindow* render_window) : exec_cpu_step(false), cpu_running(false), render_window(render_window)
  14. {
  15. }
  16. void EmuThread::SetFilename(const char* filename)
  17. {
  18. strcpy(this->filename, filename);
  19. }
  20. void EmuThread::run()
  21. {
  22. while (true)
  23. {
  24. for (int tight_loop = 0; tight_loop < 10000; ++tight_loop)
  25. {
  26. if (cpu_running || exec_cpu_step)
  27. {
  28. if (exec_cpu_step)
  29. exec_cpu_step = false;
  30. Core::SingleStep();
  31. if (!cpu_running)
  32. emit CPUStepped();
  33. }
  34. }
  35. }
  36. Core::Stop();
  37. }
  38. void EmuThread::Stop()
  39. {
  40. if (!isRunning())
  41. {
  42. INFO_LOG(MASTER_LOG, "EmuThread::Stop called while emu thread wasn't running, returning...");
  43. return;
  44. }
  45. //core::g_state = core::SYS_DIE;
  46. wait(1000);
  47. if (isRunning())
  48. {
  49. WARN_LOG(MASTER_LOG, "EmuThread still running, terminating...");
  50. terminate();
  51. wait(1000);
  52. if (isRunning())
  53. WARN_LOG(MASTER_LOG, "EmuThread STILL running, something is wrong here...");
  54. }
  55. INFO_LOG(MASTER_LOG, "EmuThread stopped");
  56. }
  57. // This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context.
  58. // The corresponding functionality is handled in EmuThread instead
  59. class GGLWidgetInternal : public QGLWidget
  60. {
  61. public:
  62. GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent) : QGLWidget(parent)
  63. {
  64. doneCurrent();
  65. parent_ = parent;
  66. }
  67. void paintEvent(QPaintEvent* ev)
  68. {
  69. // Apparently, Windows doesn't display anything if we don't call this here.
  70. // TODO: Breaks linux though because we aren't calling doneCurrent() ... -.-
  71. // makeCurrent();
  72. }
  73. void resizeEvent(QResizeEvent* ev) {
  74. parent_->SetClientAreaWidth(size().width());
  75. parent_->SetClientAreaHeight(size().height());
  76. }
  77. private:
  78. GRenderWindow* parent_;
  79. };
  80. EmuThread& GRenderWindow::GetEmuThread()
  81. {
  82. return emu_thread;
  83. }
  84. GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this)
  85. {
  86. // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose
  87. QGLFormat fmt;
  88. fmt.setProfile(QGLFormat::CoreProfile);
  89. fmt.setVersion(4,1);
  90. fmt.setSampleBuffers(true);
  91. fmt.setSamples(4);
  92. child = new GGLWidgetInternal(fmt, this);
  93. QBoxLayout* layout = new QHBoxLayout(this);
  94. resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
  95. layout->addWidget(child);
  96. layout->setMargin(0);
  97. setLayout(layout);
  98. BackupGeometry();
  99. }
  100. GRenderWindow::~GRenderWindow()
  101. {
  102. emu_thread.Stop();
  103. }
  104. void GRenderWindow::SwapBuffers()
  105. {
  106. child->makeCurrent(); // TODO: Not necessary?
  107. child->swapBuffers();
  108. }
  109. void GRenderWindow::closeEvent(QCloseEvent* event)
  110. {
  111. emu_thread.Stop();
  112. QWidget::closeEvent(event);
  113. }
  114. void GRenderWindow::MakeCurrent()
  115. {
  116. child->makeCurrent();
  117. }
  118. void GRenderWindow::DoneCurrent()
  119. {
  120. child->doneCurrent();
  121. }
  122. void GRenderWindow::PollEvents() {
  123. // TODO(ShizZy): Does this belong here? This is a reasonable place to update the window title
  124. // from the main thread, but this should probably be in an event handler...
  125. /*
  126. static char title[128];
  127. sprintf(title, "%s (FPS: %02.02f)", window_title_.c_str(),
  128. video_core::g_renderer->current_fps());
  129. setWindowTitle(title);
  130. */
  131. }
  132. void GRenderWindow::BackupGeometry()
  133. {
  134. geometry = ((QGLWidget*)this)->saveGeometry();
  135. }
  136. void GRenderWindow::RestoreGeometry()
  137. {
  138. // We don't want to back up the geometry here (obviously)
  139. QWidget::restoreGeometry(geometry);
  140. }
  141. void GRenderWindow::restoreGeometry(const QByteArray& geometry)
  142. {
  143. // Make sure users of this class don't need to deal with backing up the geometry themselves
  144. QWidget::restoreGeometry(geometry);
  145. BackupGeometry();
  146. }
  147. QByteArray GRenderWindow::saveGeometry()
  148. {
  149. // If we are a top-level widget, store the current geometry
  150. // otherwise, store the last backup
  151. if (parent() == NULL)
  152. return ((QGLWidget*)this)->saveGeometry();
  153. else
  154. return geometry;
  155. }
  156. void GRenderWindow::keyPressEvent(QKeyEvent* event)
  157. {
  158. /*
  159. bool key_processed = false;
  160. for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel)
  161. if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED))
  162. key_processed = true;
  163. if (!key_processed)
  164. QWidget::keyPressEvent(event);
  165. */
  166. }
  167. void GRenderWindow::keyReleaseEvent(QKeyEvent* event)
  168. {
  169. /*
  170. bool key_processed = false;
  171. for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel)
  172. if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::RELEASED))
  173. key_processed = true;
  174. if (!key_processed)
  175. QWidget::keyPressEvent(event);
  176. */
  177. }