[gnome-games/wip/abhinavsingh/gamepad-reassign: 24/24] Add gamepad reassignment
- From: Abhinav Singh <abhinavsingh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games/wip/abhinavsingh/gamepad-reassign: 24/24] Add gamepad reassignment
- Date: Mon, 31 Jul 2017 07:46:29 +0000 (UTC)
commit 5ad3abbfee002799dac677ef95eec1e255168f31
Author: theawless <theawless gmail com>
Date: Mon Jul 31 13:15:52 2017 +0530
Add gamepad reassignment
data/Makefile.am | 2 +
data/org.gnome.Games.gresource.xml | 2 +
data/ui/controller-popover.ui | 31 ++++++++++++
data/ui/controller-reassigner.ui | 70 ++++++++++++++++++++++++++
data/ui/display-header-bar.ui | 25 +++++++++
src/Makefile.am | 3 +
src/command/command-runner.vala | 4 ++
src/core/controller-set.vala | 53 ++++++++++++++++++++
src/core/runner.vala | 1 +
src/dummy/dummy-runner.vala | 4 ++
src/retro/retro-input-manager.vala | 95 +++++++++++++++++-------------------
src/retro/retro-runner.vala | 6 ++
src/ui/application-window.vala | 2 +
src/ui/controller-popover.vala | 78 +++++++++++++++++++++++++++++
src/ui/controller-reassigner.vala | 82 +++++++++++++++++++++++++++++++
src/ui/display-header-bar.vala | 14 +++++
16 files changed, 421 insertions(+), 51 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index fff2a95..a48c201 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -41,6 +41,8 @@ EXTRA_DIST = \
ui/gamepad-mapper.ui \
ui/gamepad-tester.ui \
ui/game-icon-view.ui \
+ ui/controller-popover.ui \
+ ui/controller-reassigner.ui \
ui/media-menu-button.ui \
ui/media-selector.ui \
ui/preferences-page-controllers.ui \
diff --git a/data/org.gnome.Games.gresource.xml b/data/org.gnome.Games.gresource.xml
index b8ba7b5..06a29ab 100644
--- a/data/org.gnome.Games.gresource.xml
+++ b/data/org.gnome.Games.gresource.xml
@@ -20,6 +20,8 @@
<file preprocess="xml-stripblanks">ui/gamepad-mapper.ui</file>
<file preprocess="xml-stripblanks">ui/gamepad-tester.ui</file>
<file preprocess="xml-stripblanks">ui/game-icon-view.ui</file>
+ <file preprocess="xml-stripblanks">ui/controller-popover.ui</file>
+ <file preprocess="xml-stripblanks">ui/controller-reassigner.ui</file>
<file preprocess="xml-stripblanks">ui/media-menu-button.ui</file>
<file preprocess="xml-stripblanks">ui/media-selector.ui</file>
<file preprocess="xml-stripblanks">ui/preferences-page-controllers.ui</file>
diff --git a/data/ui/controller-popover.ui b/data/ui/controller-popover.ui
new file mode 100644
index 0000000..762f57f
--- /dev/null
+++ b/data/ui/controller-popover.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.16"/>
+ <template class="GamesControllerPopover" parent="GtkPopover">
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="margin-top">6</property>
+ <property name="margin-bottom">6</property>
+ <property name="margin-start">6</property>
+ <property name="margin-end">6</property>
+ <property name="margin">6</property>
+ <property name="spacing">12</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkListBox" id="controllers_list_box">
+ <property name="visible">True</property>
+ <property name="selection_mode">none</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="reassign_button">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Reassign</property>
+ <signal name="clicked" handler="on_reassign_clicked"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/controller-reassigner.ui b/data/ui/controller-reassigner.ui
new file mode 100644
index 0000000..ee5f805
--- /dev/null
+++ b/data/ui/controller-reassigner.ui
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GamesControllerReassigner" parent="GtkDialog">
+ <property name="destroy-with-parent">True</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkInfoBar" id="info_bar">
+ <property name="visible">True</property>
+ <child internal-child="content_area">
+ <object class="GtkBox">
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Set up the order of the gamepads</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="margin-top">12</property>
+ <property name="margin-bottom">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <child>
+ <object class="GtkListBox" id="controllers_list_box">
+ <property name="visible">True</property>
+ <property name="selection_mode">none</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="action">
+ <object class="GtkButton" id="button_apply">
+ <property name="visible">True</property>
+ <property name="can-default">True</property>
+ <property name="label" translatable="yes">Apply</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </child>
+ <child type="action">
+ <object class="GtkButton" id="button_cancel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Cancel</property>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="apply" default="true">button_apply</action-widget>
+ <action-widget response="cancel">button_cancel</action-widget>
+ </action-widgets>
+ </template>
+</interface>
diff --git a/data/ui/display-header-bar.ui b/data/ui/display-header-bar.ui
index aae8f8d..90547b6 100644
--- a/data/ui/display-header-bar.ui
+++ b/data/ui/display-header-bar.ui
@@ -92,5 +92,30 @@
<property name="pack-type">end</property>
</packing>
</child>
+ <child>
+ <object class="GtkMenuButton" id="controller_button">
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <property name="use-underline">True</property>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-controller">
+ <property name="accessible-name" translatable="yes">controller</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage" id="controller_image">
+ <property name="visible">True</property>
+ <property name="icon-name">input-gaming-symbolic</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
</template>
</interface>
diff --git a/src/Makefile.am b/src/Makefile.am
index 645eb45..edab034 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -64,6 +64,7 @@ gnome_games_SOURCES = \
core/game-collection.vala \
core/game-uri-adapter.vala \
core/icon.vala \
+ core/controller-set.vala \
core/input-capabilities.vala \
core/media.vala \
core/media-info.vala \
@@ -153,6 +154,8 @@ gnome_games_SOURCES = \
ui/game-icon-view.vala \
ui/game-thumbnail.vala \
ui/gamepad-view-configuration.vala \
+ ui/controller-popover.vala \
+ ui/controller-reassigner.vala \
ui/media-selector.vala \
ui/media-menu-button.vala \
ui/preferences-page.vala \
diff --git a/src/command/command-runner.vala b/src/command/command-runner.vala
index e8b8612..2306c27 100644
--- a/src/command/command-runner.vala
+++ b/src/command/command-runner.vala
@@ -17,6 +17,10 @@ public class Games.CommandRunner : Object, Runner {
get { return null; }
}
+ internal ControllerSet? controller_set {
+ get { return null; }
+ }
+
private string[] args;
private bool watch_child;
diff --git a/src/core/controller-set.vala b/src/core/controller-set.vala
new file mode 100644
index 0000000..eee90ca
--- /dev/null
+++ b/src/core/controller-set.vala
@@ -0,0 +1,53 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+private class Games.ControllerSet : Object {
+ public signal void changed ();
+ public signal void reset ();
+
+ public bool has_multiple_inputs {
+ get {
+ return has_keyboard && gamepads.length > 0
+ || gamepads.length > 1;
+ }
+ }
+
+ public bool has_keyboard {
+ get { return keyboard_port != uint.MAX; }
+ }
+
+ public bool has_gamepads {
+ get { return gamepads.length > 0; }
+ }
+
+ public uint first_unplugged_port {
+ get {
+ uint i = 0;
+ while (gamepads.contains (i) || i == keyboard_port) {
+ i++;
+ }
+ return i;
+ }
+ }
+
+ public uint keyboard_port { set; get; }
+ public HashTable<uint, Gamepad?> gamepads { set; get; }
+
+ construct {
+ keyboard_port = uint.MAX;
+ gamepads = new HashTable<uint, Gamepad?> (GLib.direct_hash, GLib.direct_equal);
+ notify["gamepads"].connect (() => changed ());
+ notify["keyboard-port"].connect (() => changed ());
+ }
+
+ public void add_gamepad (uint port, Gamepad gamepad) {
+ gamepads.insert (port, gamepad);
+
+ changed ();
+ }
+
+ public void remove_gamepad (uint port) {
+ gamepads.remove (port);
+
+ changed ();
+ }
+}
diff --git a/src/core/runner.vala b/src/core/runner.vala
index 25d79b8..0daec18 100644
--- a/src/core/runner.vala
+++ b/src/core/runner.vala
@@ -7,6 +7,7 @@ public interface Games.Runner : Object {
public abstract bool can_quit_safely { get; }
public abstract bool can_resume { get; }
public abstract MediaSet? media_set { get; }
+ internal abstract ControllerSet? controller_set { get; }
public abstract bool check_is_valid (out string error_message) throws Error;
public abstract Gtk.Widget get_display ();
diff --git a/src/dummy/dummy-runner.vala b/src/dummy/dummy-runner.vala
index ce18b22..b6f7528 100644
--- a/src/dummy/dummy-runner.vala
+++ b/src/dummy/dummy-runner.vala
@@ -17,6 +17,10 @@ private class Games.DummyRunner : Object, Runner {
get { return null; }
}
+ internal ControllerSet? controller_set {
+ get { return null; }
+ }
+
public bool check_is_valid (out string error_message) throws Error {
return true;
}
diff --git a/src/retro/retro-input-manager.vala b/src/retro/retro-input-manager.vala
index 26fdc52..79cacf2 100644
--- a/src/retro/retro-input-manager.vala
+++ b/src/retro/retro-input-manager.vala
@@ -1,80 +1,73 @@
// This file is part of GNOME Games. License: GPL-3.0+.
private class Games.RetroInputManager : Retro.InputDeviceManager, Retro.Rumble {
+ public ControllerSet controller_set { set; get; }
+
private Retro.VirtualGamepad keyboard;
private GamepadMonitor gamepad_monitor;
- private Retro.InputDevice?[] input_devices;
- private int keyboard_port;
private bool present_analog_sticks;
+ construct {
+ controller_set = new ControllerSet ();
+ controller_set.reset.connect (reset);
+
+ gamepad_monitor = GamepadMonitor.get_instance ();
+ gamepad_monitor.gamepad_plugged.connect (add_gamepad);
+ }
+
public RetroInputManager (Gtk.Widget widget, bool present_analog_sticks) {
this.present_analog_sticks = present_analog_sticks;
+ // Assumption: keyboard always exists.
keyboard = new Retro.VirtualGamepad (widget);
set_keyboard (widget);
+ controller_set.keyboard_port = 0;
- gamepad_monitor = GamepadMonitor.get_instance ();
- gamepad_monitor.foreach_gamepad ((gamepad) => {
- var port = input_devices.length;
- var retro_gamepad = new RetroGamepad (gamepad, present_analog_sticks);
- input_devices += retro_gamepad;
- set_controller_device (port, retro_gamepad);
- gamepad.unplugged.connect (() => handle_gamepad_unplugged (port));
+ gamepad_monitor.foreach_gamepad (add_gamepad);
+ }
+
+ private void reset () {
+ foreach_controller ((port, controller) => {
+ remove_controller_device (port);
});
- keyboard_port = input_devices.length;
- input_devices += keyboard;
- set_controller_device (keyboard_port, keyboard);
- gamepad_monitor.gamepad_plugged.connect (handle_gamepad_plugged);
+ if (controller_set.has_gamepads) {
+ controller_set.gamepads.foreach ((port, gamepad) => {
+ var retro_gamepad = new RetroGamepad (gamepad, present_analog_sticks);
+ set_controller_device (port, retro_gamepad);
+ });
+ }
+ if (controller_set.has_keyboard)
+ set_controller_device (controller_set.keyboard_port, keyboard);
}
- private void handle_gamepad_plugged (Gamepad gamepad) {
- // Plug this gamepad to the port where the keyboard was plugged as a last resort
- var port = keyboard_port;
+ private void add_gamepad (Gamepad gamepad) {
+ // Plug this gamepad to the port where the keyboard was plugged
+ var port = controller_set.keyboard_port;
+ controller_set.add_gamepad (port, gamepad);
var retro_gamepad = new RetroGamepad (gamepad, present_analog_sticks);
- input_devices[port] = retro_gamepad;
set_controller_device (port, retro_gamepad);
- gamepad.unplugged.connect (() => handle_gamepad_unplugged (port));
-
- // Assign keyboard to another unplugged port if exists and return
- for (var i = keyboard_port; i < input_devices.length; i++) {
- if (input_devices[i] == null) {
- // Found an unplugged port and so assigning keyboard to it
- keyboard_port = i;
- input_devices[keyboard_port] = keyboard;
- set_controller_device (keyboard_port, keyboard);
-
- return;
- }
- }
+ gamepad.unplugged.connect (() => remove_gamepad (port));
- // Now it means that there is no unplugged port so append keyboard to ports
- keyboard_port = input_devices.length;
- input_devices += keyboard;
- set_controller_device (keyboard_port, keyboard);
+ // Assign keyboard to first unplugged port
+ controller_set.keyboard_port = controller_set.first_unplugged_port;
+ set_controller_device (controller_set.keyboard_port, keyboard);
}
- private void handle_gamepad_unplugged (int port) {
- if (keyboard_port > port) {
- // Remove the controller and shift keyboard to "lesser" port
- input_devices[keyboard_port] = null;
- remove_controller_device (keyboard_port);
- keyboard_port = port;
- input_devices[keyboard_port] = keyboard;
- set_controller_device (keyboard_port, keyboard);
- }
- else {
- // Just remove the controller as no need to shift keyboard
- input_devices[port] = null;
- remove_controller_device (port);
+ private void remove_gamepad (uint port) {
+ controller_set.remove_gamepad (port);
+ remove_controller_device (port);
+
+ if (controller_set.has_keyboard && controller_set.keyboard_port > port) {
+ // Shift keyboard to lesser port
+ remove_controller_device (controller_set.keyboard_port);
+ controller_set.keyboard_port = port;
+ set_controller_device (controller_set.keyboard_port, keyboard);
}
}
private bool set_rumble_state (uint port, Retro.RumbleEffect effect, uint16 strength) {
- if (port > input_devices.length)
- return false;
-
- if (input_devices[port] == null || input_devices[port] == keyboard)
+ if (controller_set.gamepads.contains (port))
return false;
// TODO Transmit the rumble signal to the gamepad.
diff --git a/src/retro/retro-runner.vala b/src/retro/retro-runner.vala
index adeec2d..3e2c0b9 100644
--- a/src/retro/retro-runner.vala
+++ b/src/retro/retro-runner.vala
@@ -34,6 +34,10 @@ public class Games.RetroRunner : Object, Runner {
get { return _media_set; }
}
+ internal ControllerSet? controller_set {
+ get { return input_manager.controller_set; }
+ }
+
private Retro.Core core;
private Retro.CairoDisplay video;
private Retro.PaPlayer audio;
@@ -71,6 +75,8 @@ public class Games.RetroRunner : Object, Runner {
private bool is_ready;
private bool should_save;
+ private Binding controller_set_binding;
+
public RetroRunner (RetroCoreSource core_source, Uri uri, Uid uid, Title game_title) {
is_initialized = false;
is_ready = false;
diff --git a/src/ui/application-window.vala b/src/ui/application-window.vala
index 4c157ef..bfaeb9e 100644
--- a/src/ui/application-window.vala
+++ b/src/ui/application-window.vala
@@ -254,6 +254,8 @@ private class Games.ApplicationWindow : Gtk.ApplicationWindow {
display_box.runner = runner;
display_header_bar.media_set = runner.media_set;
display_box.header_bar.media_set = runner.media_set;
+ display_header_bar.controller_set = runner.controller_set;
+ display_box.header_bar.controller_set = runner.controller_set;
is_fullscreen = settings.get_boolean ("fullscreen") && runner.can_fullscreen;
diff --git a/src/ui/controller-popover.vala b/src/ui/controller-popover.vala
new file mode 100644
index 0000000..f0da512
--- /dev/null
+++ b/src/ui/controller-popover.vala
@@ -0,0 +1,78 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+[GtkTemplate (ui = "/org/gnome/Games/ui/controller-popover.ui")]
+private class Games.ControllerPopover : Gtk.Popover {
+ [GtkChild]
+ private Gtk.ListBox controllers_list_box;
+ [GtkChild]
+ private Gtk.Button reassign_button;
+
+ private ControllerSet _controller_set;
+ public ControllerSet controller_set {
+ set {
+ _controller_set = value;
+
+ reset_inputs ();
+ if (controller_set != null)
+ controller_set.changed.connect (reset_inputs);
+ }
+ get { return _controller_set; }
+ }
+
+ private void reset_inputs () {
+ reassign_button.sensitive = controller_set != null && controller_set.has_multiple_inputs;
+
+ remove_inputs ();
+ update_inputs ();
+ }
+
+ private void update_inputs () {
+ if (controller_set == null)
+ return;
+
+ if (controller_set.has_gamepads) {
+ controller_set.gamepads.foreach ((port, gamepad) => {
+ add_input (gamepad.name, port);
+ });
+ }
+ if (controller_set.has_keyboard)
+ add_input (_("Keyboard"), controller_set.keyboard_port);
+ }
+
+ private void add_input (string label, uint port) {
+ var position = (int) port;
+ var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
+ box.pack_start (new Gtk.Label (label), true, true);
+ box.pack_end (new Gtk.Label (position.to_string ()), false, false);
+ box.margin = 6;
+ box.show_all ();
+ controllers_list_box.insert (box, position);
+ }
+
+ private void remove_inputs () {
+ controllers_list_box.foreach ((child) => child.destroy ());
+ }
+
+ [GtkCallback]
+ private void on_reassign_clicked () {
+ popdown ();
+
+ var controller_reassigner = new ControllerReassigner ();
+ controller_reassigner.set_transient_for ((Gtk.Window) get_toplevel ());
+ controller_reassigner.response.connect ((response) => {
+ switch (response) {
+ case Gtk.ResponseType.APPLY:
+ controller_set.gamepads = controller_reassigner.controller_set.gamepads;
+ controller_set.keyboard_port =
controller_reassigner.controller_set.keyboard_port;
+ controller_set.reset ();
+
+ break;
+ default:
+ break;
+ }
+
+ controller_reassigner.destroy ();
+ });
+ controller_reassigner.show ();
+ }
+}
diff --git a/src/ui/controller-reassigner.vala b/src/ui/controller-reassigner.vala
new file mode 100644
index 0000000..c8a8780
--- /dev/null
+++ b/src/ui/controller-reassigner.vala
@@ -0,0 +1,82 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+[GtkTemplate (ui = "/org/gnome/Games/ui/controller-reassigner.ui")]
+private class Games.ControllerReassigner : Gtk.Dialog {
+ public ControllerSet controller_set { private set; get; }
+
+ [GtkChild]
+ private Gtk.ListBox controllers_list_box;
+
+ private uint current_port;
+ private GamepadMonitor gamepad_monitor;
+
+ private ulong key_release_event_handler_id;
+ private HashTable<Gamepad, ulong> gamepad_button_press_event_handler_ids;
+
+ construct {
+ use_header_bar = 1;
+
+ controller_set = new ControllerSet ();
+ controller_set.changed.connect (reset_inputs);
+ current_port = 0;
+ gamepad_monitor = GamepadMonitor.get_instance ();
+ gamepad_button_press_event_handler_ids = new HashTable<Gamepad, uint> (GLib.int_hash,
GLib.int_equal);
+
+ events |= Gdk.EventMask.KEY_RELEASE_MASK;
+ key_release_event_handler_id = key_release_event.connect (keyboard_event);
+ }
+
+ public ControllerReassigner () {
+ gamepad_monitor.foreach_gamepad ((gamepad) => {
+ var gamepad_button_press_event_handler_id = gamepad.button_press_event.connect (() =>
gamepad_event (gamepad));
+ gamepad_button_press_event_handler_ids[gamepad] =
gamepad_button_press_event_handler_id;
+ });
+ }
+
+ private void reset_inputs () {
+ remove_inputs ();
+ update_inputs ();
+ }
+
+ private void update_inputs () {
+ if (controller_set == null)
+ return;
+
+ if (controller_set.has_gamepads) {
+ controller_set.gamepads.foreach ((port, gamepad) => {
+ add_input (gamepad.name, port);
+ });
+ }
+ if (controller_set.has_keyboard)
+ add_input (_("Keyboard"), controller_set.keyboard_port);
+ }
+
+ private void add_input (string label, uint port) {
+ var position = (int) port;
+ var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
+ box.pack_start (new Gtk.Label (label), true, true);
+ box.pack_end (new Gtk.Label (position.to_string ()), false, false);
+ box.margin = 6;
+ box.show_all ();
+ controllers_list_box.insert (box, position);
+ }
+
+ private void remove_inputs () {
+ controllers_list_box.foreach ((child) => child.destroy ());
+ }
+
+ private bool keyboard_event () {
+ disconnect (key_release_event_handler_id);
+
+ controller_set.keyboard_port = current_port++;
+
+ return false;
+ }
+
+ private void gamepad_event (Gamepad gamepad) {
+ gamepad.disconnect (gamepad_button_press_event_handler_ids[gamepad]);
+ gamepad_button_press_event_handler_ids.remove (gamepad);
+
+ controller_set.add_gamepad (current_port++, gamepad);
+ }
+}
diff --git a/src/ui/display-header-bar.vala b/src/ui/display-header-bar.vala
index 5fa6749..8481480 100644
--- a/src/ui/display-header-bar.vala
+++ b/src/ui/display-header-bar.vala
@@ -6,6 +6,8 @@ private class Games.DisplayHeaderBar : Gtk.HeaderBar {
[GtkChild]
private MediaMenuButton media_button;
+ [GtkChild]
+ private Gtk.MenuButton controller_button;
public string game_title {
set { title = value; }
@@ -21,7 +23,15 @@ private class Games.DisplayHeaderBar : Gtk.HeaderBar {
}
}
+ public ControllerSet? controller_set {
+ set {
+ controller_popover.controller_set = value;
+ controller_button.visible = value != null;
+ }
+ }
+
private MediaSelector media_selector;
+ private ControllerPopover controller_popover;
[GtkChild]
private Gtk.Button fullscreen;
@@ -34,6 +44,10 @@ private class Games.DisplayHeaderBar : Gtk.HeaderBar {
construct {
settings = new Settings ("org.gnome.Games");
+ controller_popover = new ControllerPopover ();
+ controller_popover.set_relative_to (controller_button);
+ controller_button.set_popover (controller_popover);
+
media_selector = new MediaSelector ();
media_selector.set_relative_to (media_button);
media_button.set_popover (media_selector);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]