We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Menubar / Appmenu inconsistencies X11 vs Wayland, Gnome shell
## Expected Behavior
All menu items are visible, on a menubar (or hamburger menu equivalent) - something like:
![Screenshot from 2020-04-27 12-51-16](https://user-images.githubusercontent.com/421383/80324622-d8599980-8885-11ea-8f8f-e2133a783779.png)

## Current Behavior
<!--- If you're describing a bug, what currently happens? -->
The Appmenu is deprecated in latest GTK style guide.  
Currently it is not consistently shown.  Its visibility can be turned off, and apps need to be
able to show it some other way.


859a80226b8dfa7529e41ebb21e29df2ff61e2b4

The other application menus also sometimes don't show up.

Behaviour varies depending on whether X11 or Wayland is being used.


## Steps to reproduce
<!--- Provide a set of steps describing how to reproduce this bug. If you have a live example, provide the link below -->
Gnome appmenu enabled

`GDK_BACKEND=wayland python -m box`
![Screenshot from 2020-04-27 12-43-45](https://user-images.githubusercontent.com/421383/80324391-c7f4ef00-8884-11ea-961d-2ca09f74b90e.png)
Note that with wayland, the name and icon in the appmenu are also wrong (x11 OK)

`GDK_BACKEND=x11 python -m box`
![Screenshot from 2020-04-27 12-43-27](https://user-images.githubusercontent.com/421383/80324392-c9261c00-8884-11ea-9bb4-adbc5300f84e.png)

Gnome appmenu disabled
`GDK_BACKEND=wayland python -m box`
![Screenshot from 2020-04-27 12-42-45](https://user-images.githubusercontent.com/421383/80324393-c9261c00-8884-11ea-92cd-f7b58dd77938.png)

`GDK_BACKEND=x11 python -m box`
![Screenshot from 2020-04-27 12-42-14](https://user-images.githubusercontent.com/421383/80324394-c9beb280-8884-11ea-8fbb-0787f4403a8a.png)


## Your Environment
<!--- Provide details on your current environment you found the bug in -->

* Python Version (list the specific version number)
3.7.3
* Operating System and Version (select from the following and list the specific version number; if your OS is not listed, list that as well)

  - [ ] macOS - version:
  - [x] Linux - Debian 10
  - [ ] Windows - version:
  - [ ] Other - name:  - version:

* Toga Version (list the specific version number or git hash)
2020-04-26
859a80226b8dfa7529e41ebb21e29df2ff61e2b4

* Toga Target (the type of app you are trying to generate)

  - [ ] android
  - [ ] cocoa
  - [ ] django
  - [x] gtk
  - [ ] iOS
  - [ ] tvOS
  - [ ] watchOS
  - [ ] winforms
  - [ ] win32
  - [ ] Other (please specify)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/gtk/toga_gtk/app.py`
Content:
```
1 import asyncio
2 import os
3 import os.path
4 import signal
5 import sys
6 from urllib.parse import unquote, urlparse
7 
8 import gbulb
9 import toga
10 from toga import App as toga_App
11 from toga.command import GROUP_BREAK, SECTION_BREAK, Command
12 
13 from .keys import gtk_accel
14 from .libs import Gio, GLib, Gtk
15 from .window import Window
16 
17 
18 def gtk_menu_item_activate(cmd):
19     """Convert a GTK menu item activation into a command invocation"""
20     def _handler(action, data):
21         cmd.action(cmd)
22     return _handler
23 
24 
25 class MainWindow(Window):
26     _IMPL_CLASS = Gtk.ApplicationWindow
27 
28     def create(self):
29         super().create()
30         self.native.set_role("MainWindow")
31         self.native.set_icon(toga_App.app.icon._impl.native_72.get_pixbuf())
32 
33     def set_app(self, app):
34         super().set_app(app)
35 
36         # The GTK docs list set_wmclass() as deprecated (and "pointless")
37         # but it's the only way I've found that actually sets the
38         # Application name to something other than '__main__.py'.
39         self.native.set_wmclass(app.interface.name, app.interface.name)
40 
41     def on_close(self, *args):
42         pass
43 
44 
45 class App:
46     """
47     Todo:
48         * Creation of Menus is not working.
49         * Disabling of menu items is not working.
50         * App Icon is not showing up
51     """
52     def __init__(self, interface):
53         self.interface = interface
54         self.interface._impl = self
55 
56         gbulb.install(gtk=True)
57         self.loop = asyncio.get_event_loop()
58 
59         self.create()
60 
61     def create(self):
62         # Stimulate the build of the app
63         self.native = Gtk.Application(
64             application_id=self.interface.app_id,
65             flags=Gio.ApplicationFlags.FLAGS_NONE
66         )
67 
68         # Connect the GTK signal that will cause app startup to occur
69         self.native.connect('startup', self.gtk_startup)
70         self.native.connect('activate', self.gtk_activate)
71         # self.native.connect('shutdown', self.shutdown)
72 
73         self.actions = None
74 
75     def gtk_startup(self, data=None):
76         self.interface.commands.add(
77             Command(None, 'About ' + self.interface.name, group=toga.Group.APP),
78             Command(None, 'Preferences', group=toga.Group.APP),
79             # Quit should always be the last item, in a section on it's own
80             Command(
81                 lambda widget, data: self.exit(),
82                 'Quit ' + self.interface.name,
83                 shortcut=toga.Key.MOD_1 + 'q',
84                 group=toga.Group.APP,
85                 section=sys.maxsize
86             ),
87             Command(None, 'Visit homepage', group=toga.Group.HELP)
88         )
89         self._create_app_commands()
90 
91         self.interface.startup()
92 
93         # Create the lookup table of menu items,
94         # then force the creation of the menus.
95         self._actions = {}
96         self.create_menus()
97         # self.interface.main_window._impl.create_toolbar()
98 
99     def _create_app_commands(self):
100         # No extra menus
101         pass
102 
103     def gtk_activate(self, data=None):
104         pass
105 
106     def create_menus(self):
107         # Only create the menu if the menu item index has been created.
108         if hasattr(self, '_actions'):
109             self._actions = {}
110             menubar = Gio.Menu()
111             label = None
112             submenu = None
113             section = None
114             for cmd in self.interface.commands:
115                 if cmd == GROUP_BREAK:
116                     if section:
117                         submenu.append_section(None, section)
118 
119                     if label == '*':
120                         self.native.set_app_menu(submenu)
121                     else:
122                         menubar.append_submenu(label, submenu)
123 
124                     label = None
125                     submenu = None
126                     section = None
127                 elif cmd == SECTION_BREAK:
128                     submenu.append_section(None, section)
129                     section = None
130 
131                 else:
132                     if submenu is None:
133                         label = cmd.group.label
134                         submenu = Gio.Menu()
135 
136                     if section is None:
137                         section = Gio.Menu()
138 
139                     try:
140                         action = self._actions[cmd]
141                     except KeyError:
142                         cmd_id = "command-%s" % id(cmd)
143                         action = Gio.SimpleAction.new(cmd_id, None)
144                         if cmd.action:
145                             action.connect("activate", gtk_menu_item_activate(cmd))
146 
147                         cmd._impl.native.append(action)
148                         cmd._impl.set_enabled(cmd.enabled)
149                         self._actions[cmd] = action
150                         self.native.add_action(action)
151 
152                     item = Gio.MenuItem.new(cmd.label, 'app.' + cmd_id)
153                     if cmd.shortcut:
154                         item.set_attribute_value('accel', GLib.Variant('s', gtk_accel(cmd.shortcut)))
155 
156                     section.append_item(item)
157 
158             if section:
159                 submenu.append_section(None, section)
160 
161             if submenu:
162                 if label == '*':
163                     self.native.set_app_menu(submenu)
164                 else:
165                     menubar.append_submenu(label, submenu)
166 
167             # Set the menu for the app.
168             self.native.set_menubar(menubar)
169 
170     def main_loop(self):
171         # Modify signal handlers to make sure Ctrl-C is caught and handled.
172         signal.signal(signal.SIGINT, signal.SIG_DFL)
173 
174         self.loop.run_forever(application=self.native)
175 
176     def set_main_window(self, window):
177         pass
178 
179     def exit(self):
180         self.native.quit()
181 
182     def set_on_exit(self, value):
183         pass
184 
185     def current_window(self):
186         return self.native.get_active_window()._impl
187 
188     def enter_full_screen(self, windows):
189         for window in windows:
190             window._impl.set_full_screen(True)
191 
192     def exit_full_screen(self, windows):
193         for window in windows:
194             window._impl.set_full_screen(False)
195 
196     def show_cursor(self):
197         self.interface.factory.not_implemented('App.show_cursor()')
198 
199     def hide_cursor(self):
200         self.interface.factory.not_implemented('App.hide_cursor()')
201 
202     def add_background_task(self, handler):
203         self.interface.factory.not_implemented('App.add_background_task()')
204 
205 
206 class DocumentApp(App):
207     def _create_app_commands(self):
208         self.interface.commands.add(
209             toga.Command(
210                 self.open_file,
211                 label='Open...',
212                 shortcut=toga.Key.MOD_1 + 'o',
213                 group=toga.Group.FILE,
214                 section=0
215             ),
216         )
217 
218     def gtk_startup(self, data=None):
219         super().gtk_startup(data=data)
220 
221         try:
222             # Look for a filename specified on the command line
223             file_name = os.path.abspath(sys.argv[1])
224         except IndexError:
225             # Nothing on the command line; open a file dialog instead.
226             # TODO: This causes a blank window to be shown.
227             # Is there a way to open a file dialog without having a window?
228             m = toga.Window()
229             file_name = m.select_folder_dialog(self.interface.name, None, False)[0]
230 
231         self.open_document(file_name)
232 
233     def open_file(self, widget, **kwargs):
234         # TODO: This causes a blank window to be shown.
235         # Is there a way to open a file dialog without having a window?
236         m = toga.Window()
237         file_name = m.select_folder_dialog(self.interface.name, None, False)[0]
238 
239         self.open_document(file_name)
240 
241     def open_document(self, fileURL):
242         """Open a new document in this app.
243 
244         Args:
245             fileURL (str): The URL/path to the file to add as a document.
246         """
247         # Convert the fileURL to a file path.
248         fileURL = fileURL.rstrip('/')
249         path = unquote(urlparse(fileURL).path)
250         extension = os.path.splitext(path)[1][1:]
251 
252         # Create the document instance
253         DocType = self.interface.document_types[extension]
254         document = DocType(fileURL, self.interface)
255         self.interface._documents.append(document)
256 
257         document.show()
258
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/gtk/toga_gtk/app.py b/src/gtk/toga_gtk/app.py
--- a/src/gtk/toga_gtk/app.py
+++ b/src/gtk/toga_gtk/app.py
@@ -73,12 +73,13 @@
         self.actions = None
 
     def gtk_startup(self, data=None):
+        # Set up the default commands for the interface.
         self.interface.commands.add(
-            Command(None, 'About ' + self.interface.name, group=toga.Group.APP),
+            Command(None, 'About ' + self.interface.name, group=toga.Group.HELP),
             Command(None, 'Preferences', group=toga.Group.APP),
             # Quit should always be the last item, in a section on it's own
             Command(
-                lambda widget, data: self.exit(),
+                lambda widget: self.exit(),
                 'Quit ' + self.interface.name,
                 shortcut=toga.Key.MOD_1 + 'q',
                 group=toga.Group.APP,
@@ -94,7 +95,14 @@
         # then force the creation of the menus.
         self._actions = {}
         self.create_menus()
-        # self.interface.main_window._impl.create_toolbar()
+
+        # Now that we have menus, make the app take responsibility for
+        # showing the menubar.
+        # This is required because of inconsistencies in how the Gnome
+        # shell operates on different windowing environments;
+        # see #872 for details.
+        settings = Gtk.Settings.get_default()
+        settings.set_property("gtk-shell-shows-menubar", False)
 
     def _create_app_commands(self):
         # No extra menus
@@ -117,9 +125,8 @@
                         submenu.append_section(None, section)
 
                     if label == '*':
-                        self.native.set_app_menu(submenu)
-                    else:
-                        menubar.append_submenu(label, submenu)
+                        label = self.interface.name
+                    menubar.append_submenu(label, submenu)
 
                     label = None
                     submenu = None
@@ -160,9 +167,8 @@
 
             if submenu:
                 if label == '*':
-                    self.native.set_app_menu(submenu)
-                else:
-                    menubar.append_submenu(label, submenu)
+                    label = self.interface.name
+                menubar.append_submenu(label, submenu)
 
             # Set the menu for the app.
             self.native.set_menubar(menubar)

{"golden_diff": "diff --git a/src/gtk/toga_gtk/app.py b/src/gtk/toga_gtk/app.py\n--- a/src/gtk/toga_gtk/app.py\n+++ b/src/gtk/toga_gtk/app.py\n@@ -73,12 +73,13 @@\n         self.actions = None\n \n     def gtk_startup(self, data=None):\n+        # Set up the default commands for the interface.\n         self.interface.commands.add(\n-            Command(None, 'About ' + self.interface.name, group=toga.Group.APP),\n+            Command(None, 'About ' + self.interface.name, group=toga.Group.HELP),\n             Command(None, 'Preferences', group=toga.Group.APP),\n             # Quit should always be the last item, in a section on it's own\n             Command(\n-                lambda widget, data: self.exit(),\n+                lambda widget: self.exit(),\n                 'Quit ' + self.interface.name,\n                 shortcut=toga.Key.MOD_1 + 'q',\n                 group=toga.Group.APP,\n@@ -94,7 +95,14 @@\n         # then force the creation of the menus.\n         self._actions = {}\n         self.create_menus()\n-        # self.interface.main_window._impl.create_toolbar()\n+\n+        # Now that we have menus, make the app take responsibility for\n+        # showing the menubar.\n+        # This is required because of inconsistencies in how the Gnome\n+        # shell operates on different windowing environments;\n+        # see #872 for details.\n+        settings = Gtk.Settings.get_default()\n+        settings.set_property(\"gtk-shell-shows-menubar\", False)\n \n     def _create_app_commands(self):\n         # No extra menus\n@@ -117,9 +125,8 @@\n                         submenu.append_section(None, section)\n \n                     if label == '*':\n-                        self.native.set_app_menu(submenu)\n-                    else:\n-                        menubar.append_submenu(label, submenu)\n+                        label = self.interface.name\n+                    menubar.append_submenu(label, submenu)\n \n                     label = None\n                     submenu = None\n@@ -160,9 +167,8 @@\n \n             if submenu:\n                 if label == '*':\n-                    self.native.set_app_menu(submenu)\n-                else:\n-                    menubar.append_submenu(label, submenu)\n+                    label = self.interface.name\n+                menubar.append_submenu(label, submenu)\n \n             # Set the menu for the app.\n             self.native.set_menubar(menubar)\n", "issue": "Menubar / Appmenu inconsistencies X11 vs Wayland, Gnome shell\n## Expected Behavior\r\nAll menu items are visible, on a menubar (or hamburger menu equivalent) - something like:\r\n![Screenshot from 2020-04-27 12-51-16](https://user-images.githubusercontent.com/421383/80324622-d8599980-8885-11ea-8f8f-e2133a783779.png)\r\n\r\n## Current Behavior\r\n<!--- If you're describing a bug, what currently happens? -->\r\nThe Appmenu is deprecated in latest GTK style guide.  \r\nCurrently it is not consistently shown.  Its visibility can be turned off, and apps need to be\r\nable to show it some other way.\r\n\r\n\r\n859a80226b8dfa7529e41ebb21e29df2ff61e2b4\r\n\r\nThe other application menus also sometimes don't show up.\r\n\r\nBehaviour varies depending on whether X11 or Wayland is being used.\r\n\r\n\r\n## Steps to reproduce\r\n<!--- Provide a set of steps describing how to reproduce this bug. If you have a live example, provide the link below -->\r\nGnome appmenu enabled\r\n\r\n`GDK_BACKEND=wayland python -m box`\r\n![Screenshot from 2020-04-27 12-43-45](https://user-images.githubusercontent.com/421383/80324391-c7f4ef00-8884-11ea-961d-2ca09f74b90e.png)\r\nNote that with wayland, the name and icon in the appmenu are also wrong (x11 OK)\r\n\r\n`GDK_BACKEND=x11 python -m box`\r\n![Screenshot from 2020-04-27 12-43-27](https://user-images.githubusercontent.com/421383/80324392-c9261c00-8884-11ea-9bb4-adbc5300f84e.png)\r\n\r\nGnome appmenu disabled\r\n`GDK_BACKEND=wayland python -m box`\r\n![Screenshot from 2020-04-27 12-42-45](https://user-images.githubusercontent.com/421383/80324393-c9261c00-8884-11ea-92cd-f7b58dd77938.png)\r\n\r\n`GDK_BACKEND=x11 python -m box`\r\n![Screenshot from 2020-04-27 12-42-14](https://user-images.githubusercontent.com/421383/80324394-c9beb280-8884-11ea-8fbb-0787f4403a8a.png)\r\n\r\n\r\n## Your Environment\r\n<!--- Provide details on your current environment you found the bug in -->\r\n\r\n* Python Version (list the specific version number)\r\n3.7.3\r\n* Operating System and Version (select from the following and list the specific version number; if your OS is not listed, list that as well)\r\n\r\n  - [ ] macOS - version:\r\n  - [x] Linux - Debian 10\r\n  - [ ] Windows - version:\r\n  - [ ] Other - name:  - version:\r\n\r\n* Toga Version (list the specific version number or git hash)\r\n2020-04-26\r\n859a80226b8dfa7529e41ebb21e29df2ff61e2b4\r\n\r\n* Toga Target (the type of app you are trying to generate)\r\n\r\n  - [ ] android\r\n  - [ ] cocoa\r\n  - [ ] django\r\n  - [x] gtk\r\n  - [ ] iOS\r\n  - [ ] tvOS\r\n  - [ ] watchOS\r\n  - [ ] winforms\r\n  - [ ] win32\r\n  - [ ] Other (please specify)\r\n\n", "before_files": [{"content": "import asyncio\nimport os\nimport os.path\nimport signal\nimport sys\nfrom urllib.parse import unquote, urlparse\n\nimport gbulb\nimport toga\nfrom toga import App as toga_App\nfrom toga.command import GROUP_BREAK, SECTION_BREAK, Command\n\nfrom .keys import gtk_accel\nfrom .libs import Gio, GLib, Gtk\nfrom .window import Window\n\n\ndef gtk_menu_item_activate(cmd):\n    \"\"\"Convert a GTK menu item activation into a command invocation\"\"\"\n    def _handler(action, data):\n        cmd.action(cmd)\n    return _handler\n\n\nclass MainWindow(Window):\n    _IMPL_CLASS = Gtk.ApplicationWindow\n\n    def create(self):\n        super().create()\n        self.native.set_role(\"MainWindow\")\n        self.native.set_icon(toga_App.app.icon._impl.native_72.get_pixbuf())\n\n    def set_app(self, app):\n        super().set_app(app)\n\n        # The GTK docs list set_wmclass() as deprecated (and \"pointless\")\n        # but it's the only way I've found that actually sets the\n        # Application name to something other than '__main__.py'.\n        self.native.set_wmclass(app.interface.name, app.interface.name)\n\n    def on_close(self, *args):\n        pass\n\n\nclass App:\n    \"\"\"\n    Todo:\n        * Creation of Menus is not working.\n        * Disabling of menu items is not working.\n        * App Icon is not showing up\n    \"\"\"\n    def __init__(self, interface):\n        self.interface = interface\n        self.interface._impl = self\n\n        gbulb.install(gtk=True)\n        self.loop = asyncio.get_event_loop()\n\n        self.create()\n\n    def create(self):\n        # Stimulate the build of the app\n        self.native = Gtk.Application(\n            application_id=self.interface.app_id,\n            flags=Gio.ApplicationFlags.FLAGS_NONE\n        )\n\n        # Connect the GTK signal that will cause app startup to occur\n        self.native.connect('startup', self.gtk_startup)\n        self.native.connect('activate', self.gtk_activate)\n        # self.native.connect('shutdown', self.shutdown)\n\n        self.actions = None\n\n    def gtk_startup(self, data=None):\n        self.interface.commands.add(\n            Command(None, 'About ' + self.interface.name, group=toga.Group.APP),\n            Command(None, 'Preferences', group=toga.Group.APP),\n            # Quit should always be the last item, in a section on it's own\n            Command(\n                lambda widget, data: self.exit(),\n                'Quit ' + self.interface.name,\n                shortcut=toga.Key.MOD_1 + 'q',\n                group=toga.Group.APP,\n                section=sys.maxsize\n            ),\n            Command(None, 'Visit homepage', group=toga.Group.HELP)\n        )\n        self._create_app_commands()\n\n        self.interface.startup()\n\n        # Create the lookup table of menu items,\n        # then force the creation of the menus.\n        self._actions = {}\n        self.create_menus()\n        # self.interface.main_window._impl.create_toolbar()\n\n    def _create_app_commands(self):\n        # No extra menus\n        pass\n\n    def gtk_activate(self, data=None):\n        pass\n\n    def create_menus(self):\n        # Only create the menu if the menu item index has been created.\n        if hasattr(self, '_actions'):\n            self._actions = {}\n            menubar = Gio.Menu()\n            label = None\n            submenu = None\n            section = None\n            for cmd in self.interface.commands:\n                if cmd == GROUP_BREAK:\n                    if section:\n                        submenu.append_section(None, section)\n\n                    if label == '*':\n                        self.native.set_app_menu(submenu)\n                    else:\n                        menubar.append_submenu(label, submenu)\n\n                    label = None\n                    submenu = None\n                    section = None\n                elif cmd == SECTION_BREAK:\n                    submenu.append_section(None, section)\n                    section = None\n\n                else:\n                    if submenu is None:\n                        label = cmd.group.label\n                        submenu = Gio.Menu()\n\n                    if section is None:\n                        section = Gio.Menu()\n\n                    try:\n                        action = self._actions[cmd]\n                    except KeyError:\n                        cmd_id = \"command-%s\" % id(cmd)\n                        action = Gio.SimpleAction.new(cmd_id, None)\n                        if cmd.action:\n                            action.connect(\"activate\", gtk_menu_item_activate(cmd))\n\n                        cmd._impl.native.append(action)\n                        cmd._impl.set_enabled(cmd.enabled)\n                        self._actions[cmd] = action\n                        self.native.add_action(action)\n\n                    item = Gio.MenuItem.new(cmd.label, 'app.' + cmd_id)\n                    if cmd.shortcut:\n                        item.set_attribute_value('accel', GLib.Variant('s', gtk_accel(cmd.shortcut)))\n\n                    section.append_item(item)\n\n            if section:\n                submenu.append_section(None, section)\n\n            if submenu:\n                if label == '*':\n                    self.native.set_app_menu(submenu)\n                else:\n                    menubar.append_submenu(label, submenu)\n\n            # Set the menu for the app.\n            self.native.set_menubar(menubar)\n\n    def main_loop(self):\n        # Modify signal handlers to make sure Ctrl-C is caught and handled.\n        signal.signal(signal.SIGINT, signal.SIG_DFL)\n\n        self.loop.run_forever(application=self.native)\n\n    def set_main_window(self, window):\n        pass\n\n    def exit(self):\n        self.native.quit()\n\n    def set_on_exit(self, value):\n        pass\n\n    def current_window(self):\n        return self.native.get_active_window()._impl\n\n    def enter_full_screen(self, windows):\n        for window in windows:\n            window._impl.set_full_screen(True)\n\n    def exit_full_screen(self, windows):\n        for window in windows:\n            window._impl.set_full_screen(False)\n\n    def show_cursor(self):\n        self.interface.factory.not_implemented('App.show_cursor()')\n\n    def hide_cursor(self):\n        self.interface.factory.not_implemented('App.hide_cursor()')\n\n    def add_background_task(self, handler):\n        self.interface.factory.not_implemented('App.add_background_task()')\n\n\nclass DocumentApp(App):\n    def _create_app_commands(self):\n        self.interface.commands.add(\n            toga.Command(\n                self.open_file,\n                label='Open...',\n                shortcut=toga.Key.MOD_1 + 'o',\n                group=toga.Group.FILE,\n                section=0\n            ),\n        )\n\n    def gtk_startup(self, data=None):\n        super().gtk_startup(data=data)\n\n        try:\n            # Look for a filename specified on the command line\n            file_name = os.path.abspath(sys.argv[1])\n        except IndexError:\n            # Nothing on the command line; open a file dialog instead.\n            # TODO: This causes a blank window to be shown.\n            # Is there a way to open a file dialog without having a window?\n            m = toga.Window()\n            file_name = m.select_folder_dialog(self.interface.name, None, False)[0]\n\n        self.open_document(file_name)\n\n    def open_file(self, widget, **kwargs):\n        # TODO: This causes a blank window to be shown.\n        # Is there a way to open a file dialog without having a window?\n        m = toga.Window()\n        file_name = m.select_folder_dialog(self.interface.name, None, False)[0]\n\n        self.open_document(file_name)\n\n    def open_document(self, fileURL):\n        \"\"\"Open a new document in this app.\n\n        Args:\n            fileURL (str): The URL/path to the file to add as a document.\n        \"\"\"\n        # Convert the fileURL to a file path.\n        fileURL = fileURL.rstrip('/')\n        path = unquote(urlparse(fileURL).path)\n        extension = os.path.splitext(path)[1][1:]\n\n        # Create the document instance\n        DocType = self.interface.document_types[extension]\n        document = DocType(fileURL, self.interface)\n        self.interface._documents.append(document)\n\n        document.show()\n", "path": "src/gtk/toga_gtk/app.py"}], "after_files": [{"content": "import asyncio\nimport os\nimport os.path\nimport signal\nimport sys\nfrom urllib.parse import unquote, urlparse\n\nimport gbulb\nimport toga\nfrom toga import App as toga_App\nfrom toga.command import GROUP_BREAK, SECTION_BREAK, Command\n\nfrom .keys import gtk_accel\nfrom .libs import Gio, GLib, Gtk\nfrom .window import Window\n\n\ndef gtk_menu_item_activate(cmd):\n    \"\"\"Convert a GTK menu item activation into a command invocation\"\"\"\n    def _handler(action, data):\n        cmd.action(cmd)\n    return _handler\n\n\nclass MainWindow(Window):\n    _IMPL_CLASS = Gtk.ApplicationWindow\n\n    def create(self):\n        super().create()\n        self.native.set_role(\"MainWindow\")\n        self.native.set_icon(toga_App.app.icon._impl.native_72.get_pixbuf())\n\n    def set_app(self, app):\n        super().set_app(app)\n\n        # The GTK docs list set_wmclass() as deprecated (and \"pointless\")\n        # but it's the only way I've found that actually sets the\n        # Application name to something other than '__main__.py'.\n        self.native.set_wmclass(app.interface.name, app.interface.name)\n\n    def on_close(self, *args):\n        pass\n\n\nclass App:\n    \"\"\"\n    Todo:\n        * Creation of Menus is not working.\n        * Disabling of menu items is not working.\n        * App Icon is not showing up\n    \"\"\"\n    def __init__(self, interface):\n        self.interface = interface\n        self.interface._impl = self\n\n        gbulb.install(gtk=True)\n        self.loop = asyncio.get_event_loop()\n\n        self.create()\n\n    def create(self):\n        # Stimulate the build of the app\n        self.native = Gtk.Application(\n            application_id=self.interface.app_id,\n            flags=Gio.ApplicationFlags.FLAGS_NONE\n        )\n\n        # Connect the GTK signal that will cause app startup to occur\n        self.native.connect('startup', self.gtk_startup)\n        self.native.connect('activate', self.gtk_activate)\n        # self.native.connect('shutdown', self.shutdown)\n\n        self.actions = None\n\n    def gtk_startup(self, data=None):\n        # Set up the default commands for the interface.\n        self.interface.commands.add(\n            Command(None, 'About ' + self.interface.name, group=toga.Group.HELP),\n            Command(None, 'Preferences', group=toga.Group.APP),\n            # Quit should always be the last item, in a section on it's own\n            Command(\n                lambda widget: self.exit(),\n                'Quit ' + self.interface.name,\n                shortcut=toga.Key.MOD_1 + 'q',\n                group=toga.Group.APP,\n                section=sys.maxsize\n            ),\n            Command(None, 'Visit homepage', group=toga.Group.HELP)\n        )\n        self._create_app_commands()\n\n        self.interface.startup()\n\n        # Create the lookup table of menu items,\n        # then force the creation of the menus.\n        self._actions = {}\n        self.create_menus()\n\n        # Now that we have menus, make the app take responsibility for\n        # showing the menubar.\n        # This is required because of inconsistencies in how the Gnome\n        # shell operates on different windowing environments;\n        # see #872 for details.\n        settings = Gtk.Settings.get_default()\n        settings.set_property(\"gtk-shell-shows-menubar\", False)\n\n    def _create_app_commands(self):\n        # No extra menus\n        pass\n\n    def gtk_activate(self, data=None):\n        pass\n\n    def create_menus(self):\n        # Only create the menu if the menu item index has been created.\n        if hasattr(self, '_actions'):\n            self._actions = {}\n            menubar = Gio.Menu()\n            label = None\n            submenu = None\n            section = None\n            for cmd in self.interface.commands:\n                if cmd == GROUP_BREAK:\n                    if section:\n                        submenu.append_section(None, section)\n\n                    if label == '*':\n                        label = self.interface.name\n                    menubar.append_submenu(label, submenu)\n\n                    label = None\n                    submenu = None\n                    section = None\n                elif cmd == SECTION_BREAK:\n                    submenu.append_section(None, section)\n                    section = None\n\n                else:\n                    if submenu is None:\n                        label = cmd.group.label\n                        submenu = Gio.Menu()\n\n                    if section is None:\n                        section = Gio.Menu()\n\n                    try:\n                        action = self._actions[cmd]\n                    except KeyError:\n                        cmd_id = \"command-%s\" % id(cmd)\n                        action = Gio.SimpleAction.new(cmd_id, None)\n                        if cmd.action:\n                            action.connect(\"activate\", gtk_menu_item_activate(cmd))\n\n                        cmd._impl.native.append(action)\n                        cmd._impl.set_enabled(cmd.enabled)\n                        self._actions[cmd] = action\n                        self.native.add_action(action)\n\n                    item = Gio.MenuItem.new(cmd.label, 'app.' + cmd_id)\n                    if cmd.shortcut:\n                        item.set_attribute_value('accel', GLib.Variant('s', gtk_accel(cmd.shortcut)))\n\n                    section.append_item(item)\n\n            if section:\n                submenu.append_section(None, section)\n\n            if submenu:\n                if label == '*':\n                    label = self.interface.name\n                menubar.append_submenu(label, submenu)\n\n            # Set the menu for the app.\n            self.native.set_menubar(menubar)\n\n    def main_loop(self):\n        # Modify signal handlers to make sure Ctrl-C is caught and handled.\n        signal.signal(signal.SIGINT, signal.SIG_DFL)\n\n        self.loop.run_forever(application=self.native)\n\n    def set_main_window(self, window):\n        pass\n\n    def exit(self):\n        self.native.quit()\n\n    def set_on_exit(self, value):\n        pass\n\n    def current_window(self):\n        return self.native.get_active_window()._impl\n\n    def enter_full_screen(self, windows):\n        for window in windows:\n            window._impl.set_full_screen(True)\n\n    def exit_full_screen(self, windows):\n        for window in windows:\n            window._impl.set_full_screen(False)\n\n    def show_cursor(self):\n        self.interface.factory.not_implemented('App.show_cursor()')\n\n    def hide_cursor(self):\n        self.interface.factory.not_implemented('App.hide_cursor()')\n\n    def add_background_task(self, handler):\n        self.interface.factory.not_implemented('App.add_background_task()')\n\n\nclass DocumentApp(App):\n    def _create_app_commands(self):\n        self.interface.commands.add(\n            toga.Command(\n                self.open_file,\n                label='Open...',\n                shortcut=toga.Key.MOD_1 + 'o',\n                group=toga.Group.FILE,\n                section=0\n            ),\n        )\n\n    def gtk_startup(self, data=None):\n        super().gtk_startup(data=data)\n\n        try:\n            # Look for a filename specified on the command line\n            file_name = os.path.abspath(sys.argv[1])\n        except IndexError:\n            # Nothing on the command line; open a file dialog instead.\n            # TODO: This causes a blank window to be shown.\n            # Is there a way to open a file dialog without having a window?\n            m = toga.Window()\n            file_name = m.select_folder_dialog(self.interface.name, None, False)[0]\n\n        self.open_document(file_name)\n\n    def open_file(self, widget, **kwargs):\n        # TODO: This causes a blank window to be shown.\n        # Is there a way to open a file dialog without having a window?\n        m = toga.Window()\n        file_name = m.select_folder_dialog(self.interface.name, None, False)[0]\n\n        self.open_document(file_name)\n\n    def open_document(self, fileURL):\n        \"\"\"Open a new document in this app.\n\n        Args:\n            fileURL (str): The URL/path to the file to add as a document.\n        \"\"\"\n        # Convert the fileURL to a file path.\n        fileURL = fileURL.rstrip('/')\n        path = unquote(urlparse(fileURL).path)\n        extension = os.path.splitext(path)[1][1:]\n\n        # Create the document instance\n        DocType = self.interface.document_types[extension]\n        document = DocType(fileURL, self.interface)\n        self.interface._documents.append(document)\n\n        document.show()\n", "path": "src/gtk/toga_gtk/app.py"}]}