openMSX
VisibleSurface.cc
Go to the documentation of this file.
1 #include "VisibleSurface.hh"
2 #include "InitException.hh"
3 #include "Icon.hh"
4 #include "Display.hh"
5 #include "RenderSettings.hh"
6 #include "SDLSurfacePtr.hh"
7 #include "FloatSetting.hh"
8 #include "BooleanSetting.hh"
9 #include "Event.hh"
10 #include "EventDistributor.hh"
11 #include "InputEventGenerator.hh"
12 #include "PNG.hh"
13 #include "FileContext.hh"
14 #include "CliComm.hh"
15 #include "build-info.hh"
16 #include <cassert>
17 
18 namespace openmsx {
19 
21  Display& display_,
22  RTScheduler& rtScheduler,
23  EventDistributor& eventDistributor_,
24  InputEventGenerator& inputEventGenerator_,
25  CliComm& cliComm_)
26  : RTSchedulable(rtScheduler)
27  , display(display_)
28  , eventDistributor(eventDistributor_)
29  , inputEventGenerator(inputEventGenerator_)
30  , cliComm(cliComm_)
31 {
32  auto& renderSettings = display.getRenderSettings();
33 
34  inputEventGenerator_.getGrabInput().attach(*this);
35  renderSettings.getPointerHideDelaySetting().attach(*this);
36  renderSettings.getFullScreenSetting().attach(*this);
37  eventDistributor.registerEventListener(
39  eventDistributor.registerEventListener(
41  eventDistributor.registerEventListener(
43 
44  updateCursor();
45 }
46 
47 // TODO: The video subsystem is not de-inited on errors.
48 // While it would be consistent to do so, doing it in this class is
49 // not ideal since the init doesn't happen here.
50 void VisibleSurface::createSurface(int width, int height, unsigned flags)
51 {
52  if (getDisplay().getRenderSettings().getFullScreen()) {
53  flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
54  }
55 
56  assert(!window);
57  window.reset(SDL_CreateWindow(
58  display.getWindowTitle().c_str(),
59  SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
60  width, height,
61  flags));
62  if (!window) {
63  std::string err = SDL_GetError();
64  throw InitException("Could not create window: ", err);
65  }
66 
68 
69  renderer.reset(SDL_CreateRenderer(window.get(), -1, 0));
70  if (!renderer) {
71  std::string err = SDL_GetError();
72  throw InitException("Could not create renderer: " + err);
73  }
74  SDL_RenderSetLogicalSize(renderer.get(), width, height);
75  setSDLRenderer(renderer.get());
76 
77  surface.reset(SDL_CreateRGBSurface(
78  0, width, height, 32,
79  0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000));
80  if (!surface) {
81  std::string err = SDL_GetError();
82  throw InitException("Could not create surface: " + err);
83  }
85 
86  texture.reset(SDL_CreateTexture(
87  renderer.get(), SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING,
88  width, height));
89  if (!texture) {
90  std::string err = SDL_GetError();
91  throw InitException("Could not create texture: " + err);
92  }
93 
94  // prefer linear filtering (instead of nearest neighbour)
95  SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
96 
97  // set icon
98  if (OPENMSX_SET_WINDOW_ICON) {
99  SDLSurfacePtr iconSurf;
100  // always use 32x32 icon on Windows, for some reason you get badly scaled icons there
101 #ifndef _WIN32
102  try {
103  iconSurf = PNG::load(preferSystemFileContext().resolve("icons/openMSX-logo-256.png"), true);
104  } catch (MSXException& e) {
105  cliComm.printWarning(
106  "Falling back to built in 32x32 icon, because failed to load icon: ",
107  e.getMessage());
108 #endif
109  iconSurf.reset(SDL_CreateRGBSurfaceFrom(
110  const_cast<char*>(openMSX_icon.pixel_data),
114  OPENMSX_BIGENDIAN ? 0xFF000000 : 0x000000FF,
115  OPENMSX_BIGENDIAN ? 0x00FF0000 : 0x0000FF00,
116  OPENMSX_BIGENDIAN ? 0x0000FF00 : 0x00FF0000,
117  OPENMSX_BIGENDIAN ? 0x000000FF : 0xFF000000));
118 #ifndef _WIN32
119  }
120 #endif
121  SDL_SetColorKey(iconSurf.get(), SDL_TRUE, 0);
122  SDL_SetWindowIcon(window.get(), iconSurf.get());
123  }
124 }
125 
127 {
128  eventDistributor.unregisterEventListener(
130  eventDistributor.unregisterEventListener(
132  eventDistributor.unregisterEventListener(
134  inputEventGenerator.getGrabInput().detach(*this);
135  auto& renderSettings = display.getRenderSettings();
136  renderSettings.getPointerHideDelaySetting().detach(*this);
137  renderSettings.getFullScreenSetting().detach(*this);
138 }
139 
141 {
142  assert(window);
143  SDL_SetWindowTitle(window.get(), display.getWindowTitle().c_str());
144 }
145 
146 bool VisibleSurface::setFullScreen(bool fullscreen)
147 {
148  auto flags = SDL_GetWindowFlags(window.get());
149  // Note: SDL_WINDOW_FULLSCREEN_DESKTOP also has the SDL_WINDOW_FULLSCREEN
150  // bit set.
151  bool currentState = (flags & SDL_WINDOW_FULLSCREEN) != 0;
152  if (currentState == fullscreen) {
153  // already wanted stated
154  return true;
155  }
156 
157  // in win32, toggling full screen requires opening a new SDL screen
158  // in Linux calling the SDL_WM_ToggleFullScreen usually works fine
159  // We now always create a new screen to make the code on both OSes
160  // more similar (we had a windows-only bug because of this difference)
161  return false;
162 
163  /*
164  // try to toggle full screen
165  SDL_Surface* surf = getSDLSurface();
166  SDL_WM_ToggleFullScreen(surf);
167  bool newState = (surf->flags & SDL_FULLSCREEN) != 0;
168  return newState == fullscreen;
169  */
170 }
171 
172 void VisibleSurface::update(const Setting& /*setting*/)
173 {
174  updateCursor();
175 }
176 
177 void VisibleSurface::executeRT()
178 {
179  // timer expired, hide cursor
180  SDL_ShowCursor(SDL_DISABLE);
181 }
182 
183 int VisibleSurface::signalEvent(const std::shared_ptr<const Event>& event)
184 {
185  EventType type = event->getType();
186  assert((type == OPENMSX_MOUSE_MOTION_EVENT) ||
187  (type == OPENMSX_MOUSE_BUTTON_UP_EVENT) ||
189  (void)type;
190  updateCursor();
191  return 0;
192 }
193 
194 void VisibleSurface::updateCursor()
195 {
196  cancelRT();
197  auto& renderSettings = display.getRenderSettings();
198  if (renderSettings.getFullScreen() ||
199  inputEventGenerator.getGrabInput().getBoolean()) {
200  // always hide cursor in fullscreen or grabinput mode
201  SDL_ShowCursor(SDL_DISABLE);
202  return;
203  }
204  float delay = renderSettings.getPointerHideDelay();
205  if (delay == 0.0f) {
206  SDL_ShowCursor(SDL_DISABLE);
207  } else {
208  SDL_ShowCursor(SDL_ENABLE);
209  if (delay > 0.0f) {
210  scheduleRT(int(delay * 1e6f)); // delay in s, schedule in us
211  }
212  }
213 }
214 
215 } // namespace openmsx
unsigned height
Definition: Icon.hh:9
const std::string & getMessage() const &
Definition: MSXException.hh:23
Represents the output window/screen of openMSX.
Definition: Display.hh:31
std::string getWindowTitle()
Definition: Display.cc:222
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
FileContext preferSystemFileContext()
Definition: FileContext.cc:154
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
SDL_Surface * get()
RenderSettings & getRenderSettings()
Definition: Display.hh:44
void reset(SDL_Surface *surface_=nullptr)
Wrapper around a SDL_Surface.
SDLSurfacePtr load(const std::string &filename, bool want32bpp)
Load the given PNG file in a SDL_Surface.
Definition: PNG.cc:92
Display & getDisplay() const
void attach(Observer< T > &observer)
Definition: Subject.hh:45
const char * pixel_data
Definition: Icon.hh:11
OpenMSX_Icon openMSX_icon
Definition: Icon.cc:17
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
unsigned bytes_per_pixel
Definition: Icon.hh:10
EventType
Definition: Event.hh:10
bool setFullScreen(bool fullscreen)
void scheduleRT(uint64_t delta)
BooleanSetting & getGrabInput()
Input Grab on or off.
Thrown when a subsystem initialisation fails.
void detach(Observer< T > &observer)
Definition: Subject.hh:51
void setSDLRenderer(SDL_Renderer *r)
void createSurface(int width, int height, unsigned flags)
FloatSetting & getPointerHideDelaySetting()
The amount of time until the pointer is hidden in the openMSX window.
VisibleSurface(Display &display, RTScheduler &rtScheduler, EventDistributor &eventDistributor, InputEventGenerator &inputEventGenerator, CliComm &cliComm)
void setSDLSurface(SDL_Surface *surface_)
void printWarning(string_view message)
Definition: CliComm.cc:20
unsigned width
Definition: Icon.hh:8