Repository: lutris/lutris

Issue:
Redundant "Runner not installed" dialog
### Bug description

When you run a game without the runner installed, it asks to install it. If you say no, it tells you the runner is not installed, which is *what it just said*. No means no!

### How to Reproduce

Install a game, but then remove the runner. Some runners won't remove- a known bug- so you must use one that will. I used MicroM8.

Now, you have a game with an uninstalled runner. Try to run it. You are promted to install the runner.

Click 'No'; a further dialog appears immediately.

### Expected behavior

I do not think that second dialog should appear at all. The warning is enough.

### Log output

```shell
INFO     2022-04-03 09:50:23,592 [startup.init_lutris:173]:Starting Lutris 0.5.10
WARNING  2022-04-03 09:50:23,609 [libretro.get_libretro_cores:24]:No folder at /home/danj/.local/share/lutris/runners/retroarch/
INFO     2022-04-03 09:50:23,626 [startup.check_driver:57]:Using NVIDIA drivers 510.54 for x86_64
INFO     2022-04-03 09:50:23,626 [startup.check_driver:61]:GPU: Unknown
INFO     2022-04-03 09:50:23,626 [startup.check_driver:77]:GPU: 10DE:2503 196E:1377 (nvidia drivers)
INFO     2022-04-03 09:50:23,668 [startup.update_runtime:213]:Startup complete
DEBUG    2022-04-03 09:50:23,740 [lutriswindow.update_store:437]:Showing 42 games
DEBUG    2022-04-03 09:50:28,543 [grid.on_item_activated:57]:Item activated: 56
ERROR    2022-04-03 09:50:52,202 [game.launch:523]:Game is not launchable
DEBUG    2022-04-03 09:50:55,995 [application.show_window:332]:Showing window PreferencesDialog{}
DEBUG    2022-04-03 09:51:02,068 [application.on_app_window_destroyed:350]:Removed window PreferencesDialog{}
INFO     2022-04-03 09:51:02,528 [application.do_shutdown:885]:Shutting down Lutris
```


### System Information

```shell
[System]
OS:              Pop!_OS 21.10 impish
Arch:            x86_64
Kernel:          5.16.15-76051615-generic
Desktop:         GNOME
Display Server:  x11

[CPU]
Vendor:          AuthenticAMD
Model:           AMD Ryzen 7 5800X 8-Core Processor
Physical cores:  8
Logical cores:   16

[Memory]
RAM:             31.4 GB
Swap:            0.0 GB

[Graphics]
Vendor:          NVIDIA Corporation
OpenGL Renderer: NVIDIA GeForce RTX 3060/PCIe/SSE2
OpenGL Version:  4.6.0 NVIDIA 510.54
OpenGL Core:     4.6.0 NVIDIA 510.54
OpenGL ES:       OpenGL ES 3.2 NVIDIA 510.54
Vulkan:          Supported
```


### Media (optional)

![Screenshot from 2022-04-03 09-50-48](https://user-images.githubusercontent.com/6507403/161431442-6d65a0d9-11d8-45a0-a32e-b4837f671bd9.png)


### Checklist:

- [X] I'm not asking for support with a game or the wine runner.
- [X] I have followed the above mentioned guides and have all the graphics and wine dependencies installed.
- [X] I have checked for existing issues that describe my problem prior to opening this one.
- [X] I understand that improperly formatted bug reports may be closed without explanation.


Discussion:

Resolving patch:
diff --git a/lutris/exceptions.py b/lutris/exceptions.py
--- a/lutris/exceptions.py
+++ b/lutris/exceptions.py
@@ -56,8 +56,9 @@ def wrapper(*args, **kwargs):
             return function(*args, **kwargs)
         except Exception as ex:
             game = args[0]
-            game.state = game.STATE_STOPPED
-            game.emit("game-stop")
-            game.emit("game-error", str(ex))
+            if game.state != game.STATE_STOPPED:
+                game.state = game.STATE_STOPPED
+                game.emit("game-stop")
+            game.emit("game-error", ex)
 
     return wrapper
diff --git a/lutris/game.py b/lutris/game.py
--- a/lutris/game.py
+++ b/lutris/game.py
@@ -49,7 +49,7 @@ class Game(GObject.Object):
     STATE_RUNNING = "running"
 
     __gsignals__ = {
-        "game-error": (GObject.SIGNAL_RUN_FIRST, None, (str, )),
+        "game-error": (GObject.SIGNAL_RUN_FIRST, None, (object, )),
         "game-launch": (GObject.SIGNAL_RUN_FIRST, None, ()),
         "game-start": (GObject.SIGNAL_RUN_FIRST, None, ()),
         "game-started": (GObject.SIGNAL_RUN_FIRST, None, ()),
@@ -295,15 +295,12 @@ def is_launchable(self):
         """Verify that the current game can be launched."""
         if not self.is_installed:
             logger.error("%s (%s) not installed", self, self.id)
-            dialogs.ErrorDialog(_("Tried to launch a game that isn't installed."))
-            return False
+            raise GameConfigError(_("Tried to launch a game that isn't installed."))
         if not self.runner:
-            dialogs.ErrorDialog(_("Invalid game configuration: Missing runner"))
-            return False
+            raise GameConfigError(_("Invalid game configuration: Missing runner"))
         if not self.runner.is_installed():
             installed = self.runner.install_dialog()
             if not installed:
-                dialogs.ErrorDialog(_("Runner not installed."))
                 return False
 
         if self.runner.use_runtime():
@@ -517,6 +514,7 @@ def configure_game(self, prelaunched, error=None):  # noqa: C901
 
         self.start_game()
 
+    @watch_lutris_errors
     def launch(self):
         """Request launching a game. The game may not be installed yet."""
         if not self.is_launchable():
diff --git a/lutris/gui/lutriswindow.py b/lutris/gui/lutriswindow.py
--- a/lutris/gui/lutriswindow.py
+++ b/lutris/gui/lutriswindow.py
@@ -675,8 +675,8 @@ def on_about_clicked(self, *_args):
 
     def on_game_error(self, game, error):
         """Called when a game has sent the 'game-error' signal"""
-        logger.error("%s crashed", game)
-        dialogs.ErrorDialog(error, parent=self)
+        logger.exception("%s has encountered an error: %s", game, error, exc_info=error)
+        dialogs.ErrorDialog(str(error), parent=self)
         return True
 
     @GtkTemplate.Callback


Test patch: