GtkHostUIHandler.cs
1 using Gtk; 2 using Ryujinx.HLE.HOS.Applets; 3 using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; 4 using Ryujinx.HLE.UI; 5 using Ryujinx.UI.Widgets; 6 using System; 7 using System.Threading; 8 9 namespace Ryujinx.UI.Applet 10 { 11 internal class GtkHostUIHandler : IHostUIHandler 12 { 13 private readonly Window _parent; 14 15 public IHostUITheme HostUITheme { get; } 16 17 public GtkHostUIHandler(Window parent) 18 { 19 _parent = parent; 20 21 HostUITheme = new GtkHostUITheme(parent); 22 } 23 24 public bool DisplayMessageDialog(ControllerAppletUIArgs args) 25 { 26 string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}"; 27 28 string message = $"Application requests <b>{playerCount}</b> player(s) with:\n\n" 29 + $"<tt><b>TYPES:</b> {args.SupportedStyles}</tt>\n\n" 30 + $"<tt><b>PLAYERS:</b> {string.Join(", ", args.SupportedPlayers)}</tt>\n\n" 31 + (args.IsDocked ? "Docked mode set. <tt>Handheld</tt> is also invalid.\n\n" : "") 32 + "<i>Please reconfigure Input now and then press OK.</i>"; 33 34 return DisplayMessageDialog("Controller Applet", message); 35 } 36 37 public bool DisplayMessageDialog(string title, string message) 38 { 39 ManualResetEvent dialogCloseEvent = new(false); 40 41 bool okPressed = false; 42 43 Application.Invoke(delegate 44 { 45 MessageDialog msgDialog = null; 46 47 try 48 { 49 msgDialog = new MessageDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null) 50 { 51 Title = title, 52 Text = message, 53 UseMarkup = true, 54 }; 55 56 msgDialog.SetDefaultSize(400, 0); 57 58 msgDialog.Response += (object o, ResponseArgs args) => 59 { 60 if (args.ResponseId == ResponseType.Ok) 61 { 62 okPressed = true; 63 } 64 65 dialogCloseEvent.Set(); 66 msgDialog?.Dispose(); 67 }; 68 69 msgDialog.Show(); 70 } 71 catch (Exception ex) 72 { 73 GtkDialog.CreateErrorDialog($"Error displaying Message Dialog: {ex}"); 74 75 dialogCloseEvent.Set(); 76 } 77 }); 78 79 dialogCloseEvent.WaitOne(); 80 81 return okPressed; 82 } 83 84 public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText) 85 { 86 ManualResetEvent dialogCloseEvent = new(false); 87 88 bool okPressed = false; 89 bool error = false; 90 string inputText = args.InitialText ?? ""; 91 92 Application.Invoke(delegate 93 { 94 try 95 { 96 var swkbdDialog = new SwkbdAppletDialog(_parent) 97 { 98 Title = "Software Keyboard", 99 Text = args.HeaderText, 100 SecondaryText = args.SubtitleText, 101 }; 102 103 swkbdDialog.InputEntry.Text = inputText; 104 swkbdDialog.InputEntry.PlaceholderText = args.GuideText; 105 swkbdDialog.OkButton.Label = args.SubmitText; 106 107 swkbdDialog.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax); 108 swkbdDialog.SetInputValidation(args.KeyboardMode); 109 110 ((MainWindow)_parent).RendererWidget.NpadManager.BlockInputUpdates(); 111 112 if (swkbdDialog.Run() == (int)ResponseType.Ok) 113 { 114 inputText = swkbdDialog.InputEntry.Text; 115 okPressed = true; 116 } 117 118 swkbdDialog.Dispose(); 119 } 120 catch (Exception ex) 121 { 122 error = true; 123 124 GtkDialog.CreateErrorDialog($"Error displaying Software Keyboard: {ex}"); 125 } 126 finally 127 { 128 dialogCloseEvent.Set(); 129 } 130 }); 131 132 dialogCloseEvent.WaitOne(); 133 ((MainWindow)_parent).RendererWidget.NpadManager.UnblockInputUpdates(); 134 135 userText = error ? null : inputText; 136 137 return error || okPressed; 138 } 139 140 public void ExecuteProgram(HLE.Switch device, ProgramSpecifyKind kind, ulong value) 141 { 142 device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value); 143 ((MainWindow)_parent).RendererWidget?.Exit(); 144 } 145 146 public bool DisplayErrorAppletDialog(string title, string message, string[] buttons) 147 { 148 ManualResetEvent dialogCloseEvent = new(false); 149 150 bool showDetails = false; 151 152 Application.Invoke(delegate 153 { 154 try 155 { 156 ErrorAppletDialog msgDialog = new(_parent, DialogFlags.DestroyWithParent, MessageType.Error, buttons) 157 { 158 Title = title, 159 Text = message, 160 UseMarkup = true, 161 WindowPosition = WindowPosition.CenterAlways, 162 }; 163 164 msgDialog.SetDefaultSize(400, 0); 165 166 msgDialog.Response += (object o, ResponseArgs args) => 167 { 168 if (buttons != null) 169 { 170 if (buttons.Length > 1) 171 { 172 if (args.ResponseId != (ResponseType)(buttons.Length - 1)) 173 { 174 showDetails = true; 175 } 176 } 177 } 178 179 dialogCloseEvent.Set(); 180 msgDialog?.Dispose(); 181 }; 182 183 msgDialog.Show(); 184 } 185 catch (Exception ex) 186 { 187 GtkDialog.CreateErrorDialog($"Error displaying ErrorApplet Dialog: {ex}"); 188 189 dialogCloseEvent.Set(); 190 } 191 }); 192 193 dialogCloseEvent.WaitOne(); 194 195 return showDetails; 196 } 197 198 public IDynamicTextInputHandler CreateDynamicTextInputHandler() 199 { 200 return new GtkDynamicTextInputHandler(_parent); 201 } 202 } 203 }