diff --git a/Ryujinx.HLE/FileSystem/SaveHelper.cs b/Ryujinx.HLE/FileSystem/SaveHelper.cs index 411d13e25..51400458b 100644 --- a/Ryujinx.HLE/FileSystem/SaveHelper.cs +++ b/Ryujinx.HLE/FileSystem/SaveHelper.cs @@ -10,7 +10,7 @@ namespace Ryujinx.HLE.FileSystem public static string GetSavePath(SaveInfo saveMetaData, ServiceCtx context) { string baseSavePath = NandPath; - long currentTitleId = saveMetaData.TitleId; + ulong currentTitleId = saveMetaData.TitleId; switch (saveMetaData.SaveSpaceId) { diff --git a/Ryujinx.HLE/FileSystem/SaveInfo.cs b/Ryujinx.HLE/FileSystem/SaveInfo.cs index db7f6765d..8685e6ca5 100644 --- a/Ryujinx.HLE/FileSystem/SaveInfo.cs +++ b/Ryujinx.HLE/FileSystem/SaveInfo.cs @@ -4,7 +4,7 @@ namespace Ryujinx.HLE.FileSystem { struct SaveInfo { - public long TitleId { get; private set; } + public ulong TitleId { get; private set; } public long SaveId { get; private set; } public UInt128 UserId { get; private set; } @@ -12,7 +12,7 @@ namespace Ryujinx.HLE.FileSystem public SaveSpaceId SaveSpaceId { get; private set; } public SaveInfo( - long titleId, + ulong titleId, long saveId, SaveDataType saveDataType, UInt128 userId, diff --git a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index eed5953f1..e71fc27f3 100644 --- a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -5,7 +5,7 @@ using System.IO; namespace Ryujinx.HLE.FileSystem { - class VirtualFileSystem : IDisposable + public class VirtualFileSystem : IDisposable { public const string BasePath = "RyuFs"; public const string NandPath = "nand"; @@ -60,7 +60,7 @@ namespace Ryujinx.HLE.FileSystem public string GetSystemPath() => MakeDirAndGetFullPath(SystemPath); - public string GetGameSavePath(SaveInfo save, ServiceCtx context) + internal string GetGameSavePath(SaveInfo save, ServiceCtx context) { return MakeDirAndGetFullPath(SaveHelper.GetSavePath(save, context)); } diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index 5873223ef..334cba126 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -94,7 +94,7 @@ namespace Ryujinx.HLE.HOS internal KEvent VsyncEvent { get; private set; } - internal Keyset KeySet { get; private set; } + public Keyset KeySet { get; private set; } private bool _hasStarted; @@ -453,9 +453,7 @@ namespace Ryujinx.HLE.HOS Nacp controlData = new Nacp(controlFile.AsStream()); TitleName = CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title; - TitleID = metaData.Aci0.TitleId.ToString("x16"); - - CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title; + TitleID = metaData.Aci0.TitleId.ToString("x16"); if (string.IsNullOrWhiteSpace(CurrentTitle)) { @@ -551,18 +549,51 @@ namespace Ryujinx.HLE.HOS if (asetVersion == 0) { ulong iconOffset = reader.ReadUInt64(); - ulong iconSize = reader.ReadUInt64(); + ulong iconSize = reader.ReadUInt64(); ulong nacpOffset = reader.ReadUInt64(); - ulong nacpSize = reader.ReadUInt64(); + ulong nacpSize = reader.ReadUInt64(); ulong romfsOffset = reader.ReadUInt64(); - ulong romfsSize = reader.ReadUInt64(); + ulong romfsSize = reader.ReadUInt64(); if (romfsSize != 0) { Device.FileSystem.SetRomFs(new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset)); } + + if (nacpSize != 0) + { + input.Seek(obj.FileSize + (long)nacpOffset, SeekOrigin.Begin); + using (MemoryStream stream = new MemoryStream(reader.ReadBytes((int)nacpSize))) + { + ControlData = new Nacp(stream); + } + + metaData.TitleName = ControlData.Descriptions[(int)State.DesiredTitleLanguage].Title; + + if (string.IsNullOrWhiteSpace(metaData.TitleName)) + { + metaData.TitleName = ControlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title; + } + + metaData.Aci0.TitleId = ControlData.PresenceGroupId; + + if (metaData.Aci0.TitleId == 0) + { + metaData.Aci0.TitleId = ControlData.SaveDataOwnerId; + } + + if (metaData.Aci0.TitleId == 0) + { + metaData.Aci0.TitleId = ControlData.AddOnContentBaseId - 0x1000; + } + + if (metaData.Aci0.TitleId.ToString("x16") == "fffffffffffff000") + { + metaData.Aci0.TitleId = 0000000000000000; + } + } } else { @@ -578,8 +609,8 @@ namespace Ryujinx.HLE.HOS ContentManager.LoadEntries(); - TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16"); - TitleName = metaData.TitleName; + TitleName = CurrentTitle = metaData.TitleName; + TitleID = metaData.Aci0.TitleId.ToString("x16"); ProgramLoader.LoadStaticObjects(this, metaData, new IExecutable[] { staticObject }); } @@ -687,7 +718,9 @@ namespace Ryujinx.HLE.HOS // It's only safe to release resources once all threads // have exited. ThreadCounter.Signal(); - ThreadCounter.Wait(); + //ThreadCounter.Wait(); // FIXME: Uncomment this + // BODY: Right now, guest processes don't exit properly because the logic waits for them to exit. + // BODY: However, this doesn't happen when you close the main window so we need to find a way to make them exit gracefully Scheduler.Dispose(); diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index beb376f64..c6283afd4 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -60,8 +60,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public KProcessCapabilities Capabilities { get; private set; } - public long TitleId { get; private set; } - public long Pid { get; private set; } + public ulong TitleId { get; private set; } + public long Pid { get; private set; } private long _creationTimestamp; private ulong _entrypoint; diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs index ba9f54bf3..7431d7dd2 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs @@ -4,8 +4,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { public string Name { get; private set; } - public int Category { get; private set; } - public long TitleId { get; private set; } + public int Category { get; private set; } + public ulong TitleId { get; private set; } public ulong CodeAddress { get; private set; } public int CodePagesCount { get; private set; } @@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public ProcessCreationInfo( string name, int category, - long titleId, + ulong titleId, ulong codeAddress, int codePagesCount, int mmuFlags, diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs index 094e1935f..6525628f2 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs @@ -285,7 +285,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall break; - case 18: value = process.TitleId; break; + case 18: value = (long)process.TitleId; break; case 20: value = (long)process.UserExceptionContextAddress; break; diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs index 16bfc00e2..ab425cffe 100644 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs @@ -225,7 +225,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv { SaveSpaceId saveSpaceId = (SaveSpaceId)context.RequestData.ReadInt64(); - long titleId = context.RequestData.ReadInt64(); + ulong titleId = context.RequestData.ReadUInt64(); UInt128 userId = context.RequestData.ReadStruct(); diff --git a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs index 36775b078..97fa1d74b 100644 --- a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs +++ b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs @@ -40,8 +40,6 @@ namespace Ryujinx.HLE.HOS.SystemState internal string ActiveAudioOutput { get; private set; } - public bool DiscordIntegrationEnabled { get; set; } - public bool DockedMode { get; set; } public ColorSet ThemeColor { get; set; } diff --git a/Ryujinx.HLE/Loaders/Executables/KernelInitialProcess.cs b/Ryujinx.HLE/Loaders/Executables/KernelInitialProcess.cs index af57cf2d0..d6a1cb66b 100644 --- a/Ryujinx.HLE/Loaders/Executables/KernelInitialProcess.cs +++ b/Ryujinx.HLE/Loaders/Executables/KernelInitialProcess.cs @@ -7,7 +7,7 @@ namespace Ryujinx.HLE.Loaders.Executables { public string Name { get; private set; } - public long TitleId { get; private set; } + public ulong TitleId { get; private set; } public int ProcessCategory { get; private set; } @@ -65,7 +65,7 @@ namespace Ryujinx.HLE.Loaders.Executables Name = ReadString(reader, 12); - TitleId = reader.ReadInt64(); + TitleId = reader.ReadUInt64(); ProcessCategory = reader.ReadInt32(); diff --git a/Ryujinx.HLE/Loaders/Npdm/ACI0.cs b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs index af426bcfc..8350acf72 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ACI0.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs @@ -7,7 +7,7 @@ namespace Ryujinx.HLE.Loaders.Npdm { private const int Aci0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24; - public long TitleId { get; private set; } + public ulong TitleId { get; set; } public int FsVersion { get; private set; } public ulong FsPermissionsBitmask { get; private set; } @@ -28,7 +28,7 @@ namespace Ryujinx.HLE.Loaders.Npdm stream.Seek(0xc, SeekOrigin.Current); - TitleId = reader.ReadInt64(); + TitleId = reader.ReadUInt64(); // Reserved. stream.Seek(8, SeekOrigin.Current); diff --git a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs index 36449e40a..169e68daf 100644 --- a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs +++ b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs @@ -18,7 +18,7 @@ namespace Ryujinx.HLE.Loaders.Npdm public int PersonalMmHeapSize { get; private set; } public int ProcessCategory { get; private set; } public int MainThreadStackSize { get; private set; } - public string TitleName { get; private set; } + public string TitleName { get; set; } public byte[] ProductCode { get; private set; } public Aci0 Aci0 { get; private set; } diff --git a/Ryujinx.sln b/Ryujinx.sln index 8177f8617..18df571bb 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -28,7 +28,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Common", "Ryujinx.C EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Profiler", "Ryujinx.Profiler\Ryujinx.Profiler.csproj", "{4E69B67F-8CA7-42CF-A9E1-CCB0915DFB34}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ARMeilleure", "ARMeilleure\ARMeilleure.csproj", "{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARMeilleure", "ARMeilleure\ARMeilleure.csproj", "{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -126,6 +126,14 @@ Global {4E69B67F-8CA7-42CF-A9E1-CCB0915DFB34}.Profile Release|Any CPU.Build.0 = Profile Release|Any CPU {4E69B67F-8CA7-42CF-A9E1-CCB0915DFB34}.Release|Any CPU.ActiveCfg = Release|Any CPU {4E69B67F-8CA7-42CF-A9E1-CCB0915DFB34}.Release|Any CPU.Build.0 = Release|Any CPU + {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Profile Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Profile Debug|Any CPU.Build.0 = Debug|Any CPU + {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Profile Release|Any CPU.ActiveCfg = Release|Any CPU + {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Profile Release|Any CPU.Build.0 = Release|Any CPU + {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Ryujinx/Config.jsonc b/Ryujinx/Config.json similarity index 55% rename from Ryujinx/Config.jsonc rename to Ryujinx/Config.json index 2acb7f38d..d6ed189ad 100644 --- a/Ryujinx/Config.jsonc +++ b/Ryujinx/Config.json @@ -1,75 +1,28 @@ { - "$schema": "./_schema.json", - - // Dump shaders in local directory (e.g. `C:\ShaderDumps`) "graphics_shaders_dump_path": "", - - // Enable printing debug logs "logging_enable_debug": false, - - // Enable printing stubbed calls logs "logging_enable_stub": true, - - // Enable printing information logs "logging_enable_info": true, - - // Enable printing warning logs "logging_enable_warn": true, - - // Enable printing error logs "logging_enable_error": true, - - // Enable printing guest logs "logging_enable_guest": true, - - // Enable printing FS access logs. fs_global_access_log_mode must be 2 or 3 "logging_enable_fs_access_log": false, - - // Filtered log classes, in a JSON array, eg. `[ "Loader", "ServiceFs" ]` "logging_filtered_classes": [ ], - - // Enable file logging "enable_file_log": true, - - // Change System Language - // System Language list: https://gist.github.com/HorrorTroll/b6e4a88d774c3c9b3bdf54d79a7ca43b "system_language": "AmericanEnglish", - - // Enable or disable Docked Mode "docked_mode": false, - - // Enable or disable Discord Rich Presence "enable_discord_integration": true, - - // Enable or disable Game Vsync "enable_vsync": true, - - // Enable or disable Multi-core scheduling of threads "enable_multicore_scheduling": true, - - // Enable integrity checks on Switch content files "enable_fs_integrity_checks": true, - - // Sets the "GlobalAccessLogMode". Possible modes are 0-3 - "fs_global_access_log_mode": 0, - - // Use old ChocolArm64 ARM emulator "enable_legacy_jit": false, - - // Enable or disable ignoring missing services, this may cause instability "ignore_missing_services": false, - - // The primary controller's type - // Supported Values: Handheld, ProController, NpadPair, NpadLeft, NpadRight "controller_type": "Handheld", - - // Enable or disable "direct keyboard access (HID) support" (Provides games access to your keyboard as a text entry device). - "enable_keyboard": false, - - // Keyboard Controls - // https://github.com/opentk/opentk/blob/master/src/OpenTK/Input/Key.cs + "gui_columns": [ true, true, true, true, true, true, true, true, true ], + "game_dirs": [], + "enable_custom_theme": false, + "custom_theme_path": "", "keyboard_controls": { - // Left JoyCon Keyboard Bindings "left_joycon": { "stick_up": "W", "stick_down": "S", @@ -84,8 +37,6 @@ "button_l": "E", "button_zl": "Q" }, - - // Right JoyCon Keyboard Bindings "right_joycon": { "stick_up": "I", "stick_down": "K", @@ -100,27 +51,15 @@ "button_r": "U", "button_zr": "O" }, - "hotkeys": { "toggle_vsync": "Tab" } }, - - // Controller Controls - "joystick_controls": { - // Whether or not to enable Controller support + "joystick_controls": { "enabled": true, - - // Controller Device Index "index": 0, - - // Controller Analog Stick Deadzone "deadzone": 0.05, - - // The value of how pressed down each trigger has to be in order to register a button press "trigger_threshold": 0.5, - - // Left JoyCon Controller Bindings "left_joycon": { "stick": "Axis0", "stick_button": "Button13", @@ -132,8 +71,6 @@ "button_l": "Button6", "button_zl": "Button8" }, - - // Right JoyCon Controller Bindings "right_joycon": { "stick": "Axis2", "stick_button": "Button14", diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration.cs index 7c9182052..53560521b 100644 --- a/Ryujinx/Configuration.cs +++ b/Ryujinx/Configuration.cs @@ -1,4 +1,4 @@ -using ARMeilleure; +using JsonPrettyPrinterPlus; using LibHac.Fs; using OpenTK.Input; using Ryujinx.Common; @@ -7,9 +7,12 @@ using Ryujinx.HLE; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.Services; using Ryujinx.HLE.Input; +using Ryujinx.UI; using Ryujinx.UI.Input; using System; +using System.Collections.Generic; using System.IO; +using System.Text; using System.Threading.Tasks; using Utf8Json; using Utf8Json.Resolvers; @@ -26,112 +29,132 @@ namespace Ryujinx /// /// Dumps shaders in this local directory /// - public string GraphicsShadersDumpPath { get; private set; } + public string GraphicsShadersDumpPath { get; set; } /// /// Enables printing debug log messages /// - public bool LoggingEnableDebug { get; private set; } + public bool LoggingEnableDebug { get; set; } /// /// Enables printing stub log messages /// - public bool LoggingEnableStub { get; private set; } + public bool LoggingEnableStub { get; set; } /// /// Enables printing info log messages /// - public bool LoggingEnableInfo { get; private set; } + public bool LoggingEnableInfo { get; set; } /// /// Enables printing warning log messages /// - public bool LoggingEnableWarn { get; private set; } + public bool LoggingEnableWarn { get; set; } /// /// Enables printing error log messages /// - public bool LoggingEnableError { get; private set; } + public bool LoggingEnableError { get; set; } /// /// Enables printing guest log messages /// - public bool LoggingEnableGuest { get; private set; } + public bool LoggingEnableGuest { get; set; } /// /// Enables printing FS access log messages /// - public bool LoggingEnableFsAccessLog { get; private set; } + public bool LoggingEnableFsAccessLog { get; set; } /// /// Controls which log messages are written to the log targets /// - public LogClass[] LoggingFilteredClasses { get; private set; } + public LogClass[] LoggingFilteredClasses { get; set; } /// /// Enables or disables logging to a file on disk /// - public bool EnableFileLog { get; private set; } + public bool EnableFileLog { get; set; } /// /// Change System Language /// - public SystemLanguage SystemLanguage { get; private set; } + public SystemLanguage SystemLanguage { get; set; } /// /// Enables or disables Docked Mode /// - public bool DockedMode { get; private set; } + public bool DockedMode { get; set; } /// /// Enables or disables Discord Rich Presence /// - public bool EnableDiscordIntegration { get; private set; } + public bool EnableDiscordIntegration { get; set; } /// /// Enables or disables Vertical Sync /// - public bool EnableVsync { get; private set; } + public bool EnableVsync { get; set; } /// /// Enables or disables multi-core scheduling of threads /// - public bool EnableMulticoreScheduling { get; private set; } + public bool EnableMulticoreScheduling { get; set; } /// /// Enables integrity checks on Game content files /// - public bool EnableFsIntegrityChecks { get; private set; } + public bool EnableFsIntegrityChecks { get; set; } /// /// Enables FS access log output to the console. Possible modes are 0-3 /// - public int FsGlobalAccessLogMode { get; private set; } + public int FsGlobalAccessLogMode { get; set; } /// /// Use old ChocolArm64 ARM emulator /// - public bool EnableLegacyJit { get; private set; } + public bool EnableLegacyJit { get; set; } /// /// Enable or disable ignoring missing services /// - public bool IgnoreMissingServices { get; private set; } + public bool IgnoreMissingServices { get; set; } /// /// The primary controller's type /// - public ControllerStatus ControllerType { get; private set; } + public ControllerStatus ControllerType { get; set; } + + /// + /// Used to toggle columns in the GUI + /// + public List GuiColumns { get; set; } + + /// + /// A list of directories containing games to be used to load games into the games list + /// + public List GameDirs { get; set; } + + /// + /// Enable or disable custom themes in the GUI + /// + public bool EnableCustomTheme { get; set; } + + /// + /// Path to custom GUI theme + /// + public string CustomThemePath { get; set; } /// /// Enable or disable keyboard support (Independent from controllers binding) /// - public bool EnableKeyboard { get; private set; } + public bool EnableKeyboard { get; set; } /// /// Keyboard control bindings /// - public NpadKeyboard KeyboardControls { get; private set; } + public NpadKeyboard KeyboardControls { get; set; } /// /// Controller control bindings @@ -161,8 +184,8 @@ namespace Ryujinx /// The path to the JSON configuration file public static async Task LoadAsync(string path) { - var resolver = CompositeResolver.Create( - new[] { new ConfigurationEnumFormatter() }, + IJsonFormatterResolver resolver = CompositeResolver.Create( + new[] { new ConfigurationEnumFormatter() }, new[] { StandardResolver.AllowPrivateSnakeCase } ); @@ -172,18 +195,33 @@ namespace Ryujinx } } + /// + /// Save a configuration file to disk + /// + /// The path to the JSON configuration file + public static void SaveConfig(Configuration config, string path) + { + IJsonFormatterResolver resolver = CompositeResolver.Create( + new[] { new ConfigurationEnumFormatter() }, + new[] { StandardResolver.AllowPrivateSnakeCase } + ); + + byte[] data = JsonSerializer.Serialize(config, resolver); + File.WriteAllText(path, Encoding.UTF8.GetString(data, 0, data.Length).PrettyPrintJson()); + } + /// /// Configures a instance /// /// The instance to configure - public static void Configure(Switch device) + public static void InitialConfigure(Switch device) { if (Instance == null) { throw new InvalidOperationException("Configuration has not been loaded yet."); } - GraphicsConfig.ShadersDumpPath = Instance.GraphicsShadersDumpPath; + SwitchSettings.ConfigureSettings(Instance); Logger.AddTarget(new AsyncLogTargetWrapper( new ConsoleLogTarget(), @@ -194,65 +232,74 @@ namespace Ryujinx if (Instance.EnableFileLog) { Logger.AddTarget(new AsyncLogTargetWrapper( - new FileLogTarget(Path.Combine(Program.ApplicationDirectory, "Ryujinx.log")), + new FileLogTarget(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.log")), 1000, AsyncLogTargetOverflowAction.Block )); } - Logger.SetEnable(LogLevel.Debug, Instance.LoggingEnableDebug); - Logger.SetEnable(LogLevel.Stub, Instance.LoggingEnableStub); - Logger.SetEnable(LogLevel.Info, Instance.LoggingEnableInfo); - Logger.SetEnable(LogLevel.Warning, Instance.LoggingEnableWarn); - Logger.SetEnable(LogLevel.Error, Instance.LoggingEnableError); - Logger.SetEnable(LogLevel.Guest, Instance.LoggingEnableGuest); - Logger.SetEnable(LogLevel.AccessLog, Instance.LoggingEnableFsAccessLog); + Configure(device, Instance); + } - if (Instance.LoggingFilteredClasses.Length > 0) + public static void Configure(Switch device, Configuration SwitchConfig) + { + GraphicsConfig.ShadersDumpPath = SwitchConfig.GraphicsShadersDumpPath; + + Logger.SetEnable(LogLevel.Debug, SwitchConfig.LoggingEnableDebug ); + Logger.SetEnable(LogLevel.Stub, SwitchConfig.LoggingEnableStub ); + Logger.SetEnable(LogLevel.Info, SwitchConfig.LoggingEnableInfo ); + Logger.SetEnable(LogLevel.Warning, SwitchConfig.LoggingEnableWarn ); + Logger.SetEnable(LogLevel.Error, SwitchConfig.LoggingEnableError ); + Logger.SetEnable(LogLevel.Guest, SwitchConfig.LoggingEnableGuest ); + Logger.SetEnable(LogLevel.AccessLog, SwitchConfig.LoggingEnableFsAccessLog); + + if (SwitchConfig.LoggingFilteredClasses.Length > 0) { foreach (var logClass in EnumExtensions.GetValues()) { Logger.SetEnable(logClass, false); } - foreach (var logClass in Instance.LoggingFilteredClasses) + foreach (var logClass in SwitchConfig.LoggingFilteredClasses) { Logger.SetEnable(logClass, true); } } - device.System.State.DiscordIntegrationEnabled = Instance.EnableDiscordIntegration; + MainWindow.DiscordIntegrationEnabled = SwitchConfig.EnableDiscordIntegration; - device.EnableDeviceVsync = Instance.EnableVsync; + device.EnableDeviceVsync = SwitchConfig.EnableVsync; - device.System.State.DockedMode = Instance.DockedMode; + device.System.State.DockedMode = SwitchConfig.DockedMode; - device.System.State.SetLanguage(Instance.SystemLanguage); + device.System.State.SetLanguage(SwitchConfig.SystemLanguage); - if (Instance.EnableMulticoreScheduling) + if (SwitchConfig.EnableMulticoreScheduling) { device.System.EnableMultiCoreScheduling(); } - device.System.FsIntegrityCheckLevel = Instance.EnableFsIntegrityChecks + device.System.FsIntegrityCheckLevel = SwitchConfig.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None; - device.System.GlobalAccessLogMode = Instance.FsGlobalAccessLogMode; + device.System.GlobalAccessLogMode = SwitchConfig.FsGlobalAccessLogMode; - device.System.UseLegacyJit = Instance.EnableLegacyJit; + device.System.UseLegacyJit = SwitchConfig.EnableLegacyJit; - ServiceConfiguration.IgnoreMissingServices = Instance.IgnoreMissingServices; - - if (Instance.JoystickControls.Enabled) + ServiceConfiguration.IgnoreMissingServices = SwitchConfig.IgnoreMissingServices; + } + + public static void ConfigureHid(Switch device, Configuration SwitchConfig) + { + if (SwitchConfig.JoystickControls.Enabled) { - if (!Joystick.GetState(Instance.JoystickControls.Index).IsConnected) + if (!Joystick.GetState(SwitchConfig.JoystickControls.Index).IsConnected) { - Instance.JoystickControls.SetEnabled(false); + SwitchConfig.JoystickControls.SetEnabled(false); } } - - device.Hid.InitializePrimaryController(Instance.ControllerType); + device.Hid.InitializePrimaryController(SwitchConfig.ControllerType); device.Hid.InitializeKeyboard(); } diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index d0518441b..5663a5d5b 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -1,169 +1,41 @@ -using DiscordRPC; -using Ryujinx.Audio; +using Gtk; using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Gal; -using Ryujinx.Graphics.Gal.OpenGL; -using Ryujinx.HLE; using Ryujinx.Profiler; +using Ryujinx.UI; using System; using System.IO; -using System.Linq; namespace Ryujinx { class Program { - public static DiscordRpcClient DiscordClient; - - public static RichPresence DiscordPresence; - - public static string ApplicationDirectory => AppDomain.CurrentDomain.BaseDirectory; - static void Main(string[] args) { Console.Title = "Ryujinx Console"; - IGalRenderer renderer = new OglRenderer(); - - IAalOutput audioOut = InitializeAudioEngine(); - - Switch device = new Switch(renderer, audioOut); - - Configuration.Load(Path.Combine(ApplicationDirectory, "Config.jsonc")); - Configuration.Configure(device); - - Profile.Initialize(); + string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); + Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; - if (device.System.State.DiscordIntegrationEnabled) - { - DiscordClient = new DiscordRpcClient("568815339807309834"); - DiscordPresence = new RichPresence - { - Assets = new Assets - { - LargeImageKey = "ryujinx", - LargeImageText = "Ryujinx is an emulator for the Nintendo Switch" - } - }; + Profile.Initialize(); - DiscordClient.Initialize(); - DiscordClient.SetPresence(DiscordPresence); - } + Application.Init(); - if (args.Length == 1) - { - if (Directory.Exists(args[0])) - { - string[] romFsFiles = Directory.GetFiles(args[0], "*.istorage"); + Application gtkApplication = new Application("Ryujinx.Ryujinx", GLib.ApplicationFlags.None); + MainWindow mainWindow = new MainWindow(args, gtkApplication); - if (romFsFiles.Length == 0) - { - romFsFiles = Directory.GetFiles(args[0], "*.romfs"); - } + gtkApplication.Register(GLib.Cancellable.Current); + gtkApplication.AddWindow(mainWindow); + mainWindow.Show(); - if (romFsFiles.Length > 0) - { - Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS."); - device.LoadCart(args[0], romFsFiles[0]); - } - else - { - Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS."); - device.LoadCart(args[0]); - } - } - else if (File.Exists(args[0])) - { - switch (Path.GetExtension(args[0]).ToLowerInvariant()) - { - case ".xci": - Logger.PrintInfo(LogClass.Application, "Loading as XCI."); - device.LoadXci(args[0]); - break; - case ".nca": - Logger.PrintInfo(LogClass.Application, "Loading as NCA."); - device.LoadNca(args[0]); - break; - case ".nsp": - case ".pfs0": - Logger.PrintInfo(LogClass.Application, "Loading as NSP."); - device.LoadNsp(args[0]); - break; - default: - Logger.PrintInfo(LogClass.Application, "Loading as homebrew."); - device.LoadProgram(args[0]); - break; - } - } - else - { - Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file"); - } - } - else - { - Logger.PrintWarning(LogClass.Application, "Please specify the folder with the NSOs/IStorage or a NSO/NRO."); - } - - if (device.System.State.DiscordIntegrationEnabled) - { - if (File.ReadAllLines(Path.Combine(ApplicationDirectory, "RPsupported.dat")).Contains(device.System.TitleID)) - { - DiscordPresence.Assets.LargeImageKey = device.System.TitleID; - } - - string state = device.System.TitleID; - - if (state == null) - { - state = "Ryujinx"; - } - else - { - state = state.ToUpper(); - } - - string details = "Idling"; - - if (device.System.TitleName != null) - { - details = $"Playing {device.System.TitleName}"; - } - - DiscordPresence.Details = details; - DiscordPresence.State = state; - DiscordPresence.Assets.LargeImageText = device.System.TitleName; - DiscordPresence.Assets.SmallImageKey = "ryujinx"; - DiscordPresence.Assets.SmallImageText = "Ryujinx is an emulator for the Nintendo Switch"; - DiscordPresence.Timestamps = new Timestamps(DateTime.UtcNow); - - DiscordClient.SetPresence(DiscordPresence); - } - - using (GlScreen screen = new GlScreen(device, renderer)) - { - screen.MainLoop(); - - Profile.FinishProfiling(); - - device.Dispose(); - } - - audioOut.Dispose(); - - Logger.Shutdown(); - - DiscordClient.Dispose(); + Application.Run(); } private static void CurrentDomain_ProcessExit(object sender, EventArgs e) { Logger.Shutdown(); - - DiscordClient.Dispose(); } private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) @@ -175,29 +47,7 @@ namespace Ryujinx if (e.IsTerminating) { Logger.Shutdown(); - - DiscordClient.Dispose(); - } - } - - /// - /// Picks an audio output renderer supported on this machine - /// - /// An supported by this machine - private static IAalOutput InitializeAudioEngine() - { - if (SoundIoAudioOut.IsSupported) - { - return new SoundIoAudioOut(); - } - else if (OpenALAudioOut.IsSupported) - { - return new OpenALAudioOut(); - } - else - { - return new DummyAudioOut(); } } } -} +} \ No newline at end of file diff --git a/Ryujinx/RPsupported.dat b/Ryujinx/RPsupported.dat index ad2d715df..bcce8b495 100644 --- a/Ryujinx/RPsupported.dat +++ b/Ryujinx/RPsupported.dat @@ -2,10 +2,10 @@ 01000d700be88000 01000dc007e90000 01000e2003fa0000 -01002fc00c6d0000 0100225000fee000 010028d0045ce000 01002b30028f6000 +01002fc00c6d0000 010034e005c9c000 01004f8006a78000 010051f00ac5e000 @@ -15,12 +15,14 @@ 010065500b218000 010068f00aa78000 01006a800016e000 +010072800cbe8000 01007330027ee000 0100749009844000 01007a4008486000 010080b00ad66000 010094e00b52e000 01009aa000faa000 +01009b90006dc000 0100a4200a284000 0100a5c00d162000 0100ae000aebc000 @@ -31,8 +33,11 @@ 0100d6b00cd88000 0100d870045b6000 0100e0c00adac000 +0100e46006708000 0100e7200b272000 0100e9f00b882000 0100eab00605c000 0100efd00a4fa000 -0100f6a00a684000 \ No newline at end of file +0100f6a00a684000 +0100f9f00c696000 +051337133769a000 \ No newline at end of file diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj index 80b03f46b..763feec72 100644 --- a/Ryujinx/Ryujinx.csproj +++ b/Ryujinx/Ryujinx.csproj @@ -18,8 +18,28 @@ false + + + + + + + + + + + + + + + + + + + + @@ -33,7 +53,10 @@ - + + PreserveNewest + + PreserveNewest diff --git a/Ryujinx/Theme.css b/Ryujinx/Theme.css new file mode 100644 index 000000000..286e092c8 --- /dev/null +++ b/Ryujinx/Theme.css @@ -0,0 +1,4054 @@ +/* GTK NAMED COLORS + ---------------- + use responsibly! */ +/* +widget text/foreground color */ +@define-color theme_fg_color white; +/* +text color for entries, views and content in general */ +@define-color theme_text_color white; +/* +widget base background color */ +@define-color theme_bg_color #292f34; +/* +text widgets and the like base background color */ +@define-color theme_base_color #292f34; +/* +base background color of selections */ +@define-color theme_selected_bg_color #FF5F57; +/* +text/foreground color of selections */ +@define-color theme_selected_fg_color white; +/* +base background color of insensitive widgets */ +@define-color insensitive_bg_color #252b2f; +/* +text foreground color of insensitive widgets */ +@define-color insensitive_fg_color rgba(232, 232, 232, 0.35); +/* +insensitive text widgets and the like base background color */ +@define-color insensitive_base_color rgba(232, 232, 232, 0.35); +/* +widget text/foreground color on backdrop windows */ +@define-color theme_unfocused_fg_color white; +/* +text color for entries, views and content in general on backdrop windows */ +@define-color theme_unfocused_text_color white; +/* +widget base background color on backdrop windows */ +@define-color theme_unfocused_bg_color #292f34; +/* +text widgets and the like base background color on backdrop windows */ +@define-color theme_unfocused_base_color #292f34; +/* +base background color of selections on backdrop windows */ +@define-color theme_unfocused_selected_bg_color rgba(255, 95, 87, 0.5); +/* +text/foreground color of selections on backdrop windows */ +@define-color theme_unfocused_selected_fg_color white; +/* +widgets main borders color */ +@define-color borders #5f6367; +/* +widgets main borders color on backdrop windows */ +@define-color unfocused_borders #5f6367; +/* +widgets main borders color insensitive */ +@define-color insensitive_borders rgba(86, 90, 94, 0.35); +/* +these are pretty self explicative */ +@define-color warning_color #e67e22; +@define-color error_color #e74c3c; +@define-color success_color #3498db; +@define-color content_view_bg #292f34; +* { + padding: 0; + -GtkToolButton-icon-spacing: 4; + -GtkTextView-error-underline-color: #e74c3c; + -GtkScrolled-window-overlay-scrolling: FALSE; + -GtkToolItemGroup-expander-size: 11; + -GtkExpander-expander-size: 16; + -GtkTreeView-expander-size: 11; + -GtkTreeView-horizontal-separator: 4; + -GtkWidget-text-handle-width: 20; + -GtkWidget-text-handle-height: 20; + -GtkDialog-button-spacing: 4; + -GtkDialog-action-area-border: 0; + -GtkStatusbar-shadow-type: none; + outline-width: 0px; } + +/*************** + * Base States * + ***************/ +* { + color: white +} + +.background { + color: white; + background-color: #292f34; } + .background:backdrop { + text-shadow: none; + -gtk-icon-shadow: none; + color: white; + background-color: #292f34; } + +/* + These wildcard seems unavoidable, need to investigate. + Wildcards are bad and troublesome, use them with care, + or better, just don't. + Everytime a wildcard is used a kitten dies, painfully. +*/ +*:disabled { + -gtk-icon-effect: dim; } + +.gtkstyle-fallback { + background-color: #292f34; + color: white; } + .gtkstyle-fallback:hover { + background-color: #3f4951; + color: white; } + .gtkstyle-fallback:active { + background-color: #131517; + color: white; } + .gtkstyle-fallback:disabled { + background-color: #252b2f; + color: rgba(232, 232, 232, 0.35); } + .gtkstyle-fallback:selected { + background-color: #FF5F57; + color: white; } + +.view text, +textview text, +.view { + color: white; + background-color: #292f34; } + .view text:backdrop, + textview text:backdrop, + .view:backdrop { + color: white; + background-color: #292f34; } + .view text:selected:focus, + textview text:selected:focus, .view text:selected, + textview text:selected, + .view:selected:focus, + .view:selected { + border-radius: 3px; } + +textview border { + background-color: #292f34; + background-image: image(#5f6367); + background-repeat: no-repeat; } + textview border:backdrop { + background-color: #292f34; } + textview border.bottom { + background-size: 100% 1px; + background-position: top; } + textview border.top { + background-size: 100% 1px; + background-position: bottom; } + textview border.left { + background-size: 1px 100%; + background-position: right; } + textview border.right { + background-size: 1px 100%; + background-position: left; } + +.rubberband, +rubberband, +flowbox rubberband, +treeview.view rubberband { + border: 1px solid #FF5F57; + background-color: rgba(255, 95, 87, 0.2); } + .rubberband:backdrop, + rubberband:backdrop, + treeview.view rubberband:backdrop { + border-color: #FF5F57; + background-color: rgba(255, 95, 87, 0.2); } + +flowbox flowboxchild { + padding: 3px; + border-radius: 3px; } + flowbox flowboxchild:selected { + outline-offset: 0px; } + +label.separator { + color: white; } + label.separator:backdrop { + color: white; } +label selection { + background-color: #FF5F57; + color: white; } +label:disabled { + color: rgba(232, 232, 232, 0.35); } + label:disabled:backdrop { + color: rgba(232, 232, 232, 0.35); } +label:backdrop { + color: white; } + +.dim-label, label.separator, +headerbar .subtitle { + opacity: 0.5; + text-shadow: none; } + +assistant .sidebar { + background-color: white; + border-top: 1px solid #5f6367; } + assistant .sidebar:backdrop { + background-color: white; + border-color: #5f6367; } +assistant.csd .sidebar { + border-top-style: none; } +assistant .sidebar label { + padding: 6px 12px; } +assistant .sidebar label.highlight { + background-color: #54595d; } + +.app-notification, +.app-notification.frame, .csd popover.background.touch-selection, .csd popover.background.magnifier, popover.background.touch-selection, popover.background.magnifier, .csd popover.background.osd, popover.background.osd, +.osd { + color: white; + border: 1px solid #5f6367; + background-color: rgba(41, 47, 52, 0.8); + background-clip: padding-box; + box-shadow: none; + text-shadow: none; + -gtk-icon-shadow: none; } + .app-notification:backdrop, popover.background.touch-selection:backdrop, popover.background.magnifier:backdrop, popover.background.osd:backdrop, + .osd:backdrop { + color: white; + background-color: rgba(41, 47, 52, 0.8); + -gtk-icon-shadow: none; } + +.view text:selected:focus, +textview text:selected:focus, .view text:selected, +textview text:selected, +.view:selected:focus, +.view:selected, .view text selection:focus, .view text selection, +textview text selection:focus, +textview text selection, flowbox flowboxchild:selected, spinbutton:not(.vertical) selection:focus, spinbutton:not(.vertical) selection, +entry selection:focus, +entry selection, row:selected, .sidebar:selected { + background-color: #FF5F57; + color: white; } + textview text:hover:selected:focus, .view text:hover:selected, + textview text:hover:selected, + .view:hover:selected, .view text selection:hover, + textview text selection:hover, flowbox flowboxchild:hover:selected, spinbutton:not(.vertical) selection:hover, + entry selection:hover, row:hover:selected, .sidebar:hover:selected { + background-color: #FF5F57; + color: white; } + textview text:backdrop:selected:focus, .view text:backdrop:selected, + textview text:backdrop:selected, + .view:backdrop:selected, .view text selection:backdrop, + textview text selection:backdrop, flowbox flowboxchild:backdrop:selected, label:backdrop selction, spinbutton:not(.vertical) selection:backdrop, + entry selection:backdrop, row:backdrop:selected, .sidebar:backdrop:selected { + background-color: rgba(255, 95, 87, 0.5); + color: #292f34; } + +.view text:selected:focus, +textview text:selected:focus, .view text:selected, +textview text:selected, +.view:selected:focus, +.view:selected, .view text selection:focus, .view text selection, +textview text selection:focus, +textview text selection, flowbox flowboxchild:selected, spinbutton:not(.vertical) selection:focus, spinbutton:not(.vertical) selection, +entry selection:focus, +entry selection, row:selected, .sidebar:selected { + background-color: #FF5F57; + border-radius: 0px; } + .view text:selected:focus, + textview text:selected:focus, .view text:selected, + textview text:selected, + .view:selected:focus, + .view:selected, .view text selection:focus, .view text selection, + textview text selection:focus, + textview text selection, flowbox flowboxchild:selected, spinbutton:not(.vertical) selection:focus, spinbutton:not(.vertical) selection, + entry selection:focus, + entry selection, row:selected, .sidebar:selected { + color: white; } + textview text:disabled:selected:focus, .view text:disabled:selected, + textview text:disabled:selected, + .view:disabled:selected, .view text selection:disabled, + textview text selection:disabled, flowbox flowboxchild:disabled:selected, label:disabled selection, spinbutton:not(.vertical) selection:disabled, + entry selection:disabled, row:disabled:selected, .sidebar:disabled:selected { + color: rgba(232, 232, 232, 0.35); } + textview text:backdrop:selected:focus, .view text:backdrop:selected, + textview text:backdrop:selected, + .view:backdrop:selected, .view text selection:backdrop, + textview text selection:backdrop, flowbox flowboxchild:backdrop:selected, label:backdrop selction, spinbutton:not(.vertical) selection:backdrop, + entry selection:backdrop, row:backdrop:selected, .sidebar:backdrop:selected { + color: white; } + .view text:backdrop:disabled:selected, + textview text:backdrop:disabled:selected, + .view:backdrop:disabled:selected, .view text selection:backdrop:disabled, + textview text selection:backdrop:disabled, flowbox flowboxchild:backdrop:disabled:selected, label:disabled selection:backdrop, label:backdrop selction:disabled, spinbutton:not(.vertical) selection:backdrop:disabled, + entry selection:backdrop:disabled, row:backdrop:disabled:selected, .sidebar:backdrop:disabled:selected { + color: rgba(232, 232, 232, 0.35); } + +/*********** + * Buttons * + ***********/ +@keyframes needs_attention { + from { + background-image: -gtk-gradient(radial, center center, 0, center center, 0.01, to(#FF5F57), to(transparent)); } + to { + background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(#FF5F57), to(transparent)); } } +notebook > header > tabs > arrow, .csd popover.background.touch-selection button, .csd popover.background.magnifier button, popover.background.touch-selection button, popover.background.magnifier button, +button, notebook > header > tabs > arrow.osd, +button.osd { + border: 1px solid; + border-radius: 3px; + padding: 4px 6px; + background-clip: border-box; + transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); + text-shadow: none; + -gtk-icon-shadow: none; + color: white; + border-color: #5f6367; + background-image: linear-gradient(to bottom, #292f35, #282e32); } + notebook > header > tabs > arrow, button.sidebar-button, popover.background.touch-selection button.flat, popover.background.magnifier button.flat, + button.flat, notebook > header > tabs > arrow.osd, button.osd.sidebar-button { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + transition: none; } + notebook > header > tabs > arrow:hover, button.sidebar-button:hover, popover.background.touch-selection button.flat:hover, popover.background.magnifier button.flat:hover, + button.flat:hover, notebook > header > tabs > arrow.osd:hover { + transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); + transition-duration: 500ms; } + notebook > header > tabs > arrow:hover:active, button.sidebar-button:hover:active, + button.flat:hover:active { + transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + notebook > header > tabs > arrow:checked, button.sidebar-button:checked, popover.background.touch-selection button.flat:checked, popover.background.magnifier button.flat:checked, + button.flat:checked, notebook > header > tabs > arrow.osd:checked { + background-color: #5f6367; } + notebook > header > tabs > arrow:hover, popover.background.touch-selection button:hover, popover.background.magnifier button:hover, + button:hover, notebook > header > tabs > arrow.osd:hover { + color: white; + border-color: #FF5F57; + -gtk-icon-effect: none; } + notebook > header > tabs > arrow:active, popover.background.touch-selection button:active, popover.background.magnifier button:active, + button:active, notebook > header > tabs > arrow.osd:active, notebook > header > tabs > arrow:checked, popover.background.touch-selection button:checked, popover.background.magnifier button:checked, + button:checked, notebook > header > tabs > arrow.osd:checked { + color: white; + border-color: #FF5F57; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); + transition-duration: 50ms; } + notebook > header > tabs > arrow:active:hover, popover.background.touch-selection button:active:hover, popover.background.magnifier button:active:hover, + button:active:hover, notebook > header > tabs > arrow:checked:hover, popover.background.touch-selection button:checked:hover, popover.background.magnifier button:checked:hover, + button:checked:hover { + color: white; + border-color: #FF5F57; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); } + notebook > header > tabs > arrow:backdrop, popover.background.touch-selection button:backdrop, popover.background.magnifier button:backdrop, + button:backdrop, notebook > header > tabs > arrow.osd:backdrop { + color: white; + border-color: #5f6367; + background-image: linear-gradient(to bottom, #292f35, #282e32); + -gtk-icon-effect: none; } + notebook > header > tabs > arrow:backdrop:active, popover.background.touch-selection button:backdrop:active, popover.background.magnifier button:backdrop:active, + button:backdrop:active, notebook > header > tabs > arrow:backdrop:checked, popover.background.touch-selection button:backdrop:checked, popover.background.magnifier button:backdrop:checked, + button:backdrop:checked { + color: white; + border-color: #FF5F57; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); } + notebook > header > tabs > arrow:backdrop:disabled, popover.background.touch-selection button:backdrop:disabled, popover.background.magnifier button:backdrop:disabled, + button:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(86, 90, 94, 0.35); + background-image: linear-gradient(to bottom, #262b30, #24292e); } + notebook > header > tabs > arrow:backdrop:disabled > .label, popover.background.touch-selection button:backdrop:disabled > .label, popover.background.magnifier button:backdrop:disabled > .label, + button:backdrop:disabled > .label { + color: inherit; } + notebook > header > tabs > arrow:backdrop:disabled:active, + button:backdrop:disabled:active, notebook > header > tabs > arrow:backdrop:disabled:checked, + button:backdrop:disabled:checked { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(24, 171, 142, 0.35); + background-image: linear-gradient(to bottom, rgba(255, 95, 87, 0.35), rgba(255, 95, 87, 0.35)); } + notebook > header > tabs > arrow:backdrop:disabled:active > .label, popover.background.touch-selection button:backdrop:disabled:active > .label, popover.background.magnifier button:backdrop:disabled:active > .label, + button:backdrop:disabled:active > .label, notebook > header > tabs > arrow:backdrop:disabled:checked > .label, popover.background.touch-selection button:backdrop:disabled:checked > .label, popover.background.magnifier button:backdrop:disabled:checked > .label, + button:backdrop:disabled:checked > .label { + color: inherit; } + notebook > header > tabs > arrow:backdrop, button.sidebar-button:backdrop, popover.background.touch-selection button.flat:backdrop, popover.background.magnifier button.flat:backdrop, + button.flat:backdrop, notebook > header > tabs > arrow.osd:backdrop { + -gtk-icon-effect: none; + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + color: white; } + notebook > header > tabs > arrow:disabled, button.sidebar-button:disabled, popover.background.touch-selection button.flat:disabled, popover.background.magnifier button.flat:disabled, + button.flat:disabled, notebook > header > tabs > arrow.osd:disabled { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + color: rgba(232, 232, 232, 0.35); } + notebook > header > tabs > arrow:backdrop:disabled, button.sidebar-button:backdrop:disabled, + button.flat:backdrop:disabled { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + color: rgba(232, 232, 232, 0.35); } + notebook > header > tabs > arrow:disabled, popover.background.touch-selection button:disabled, popover.background.magnifier button:disabled, + button:disabled, notebook > header > tabs > arrow.osd:disabled { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(86, 90, 94, 0.35); + background-image: linear-gradient(to bottom, #262b30, #24292e); } + notebook > header > tabs > arrow:disabled > .label, popover.background.touch-selection button:disabled > .label, popover.background.magnifier button:disabled > .label, + button:disabled > .label { + color: inherit; } + notebook > header > tabs > arrow:disabled:active, popover.background.touch-selection button:disabled:active, popover.background.magnifier button:disabled:active, + button:disabled:active, notebook > header > tabs > arrow:disabled:checked, popover.background.touch-selection button:disabled:checked, popover.background.magnifier button:disabled:checked, + button:disabled:checked { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(24, 171, 142, 0.35); + background-image: linear-gradient(to bottom, rgba(255, 95, 87, 0.35), rgba(255, 95, 87, 0.35)); } + notebook > header > tabs > arrow:disabled:active > .label, popover.background.touch-selection button:disabled:active > .label, popover.background.magnifier button:disabled:active > .label, + button:disabled:active > .label, notebook > header > tabs > arrow:disabled:checked > .label, popover.background.touch-selection button:disabled:checked > .label, popover.background.magnifier button:disabled:checked > .label, + button:disabled:checked > .label { + color: inherit; } + notebook > header > tabs > arrow separator, .csd popover.background.touch-selection button separator, .csd popover.background.magnifier button separator, popover.background.touch-selection button separator, popover.background.magnifier button separator, + button separator, notebook > header > tabs > arrow.osd separator, + button.osd separator { + background-color: transparent; + background-image: none; + color: transparent; } + +notebook > header > tabs > arrow.image-button, popover.background.touch-selection button.image-button, popover.background.magnifier button.image-button, +button.image-button { + min-width: 16px; + padding: 6px; } +notebook > header > tabs > arrow.text-button, popover.background.touch-selection button.text-button, popover.background.magnifier button.text-button, +button.text-button { + padding-left: 6px; + padding-right: 6px; } +notebook > header > tabs > arrow.text-button.image-button, popover.background.touch-selection button.text-button.image-button, popover.background.magnifier button.text-button.image-button, +button.text-button.image-button { + padding-left: 6px; + padding-right: 6px; } + notebook > header > tabs > arrow.text-button.image-button label, popover.background.touch-selection button.text-button.image-button label, popover.background.magnifier button.text-button.image-button label, + button.text-button.image-button label { + padding-left: 6px; + padding-right: 6px; } +row:selected popover.background.touch-selection button, popover.background.touch-selection row:selected button, row:selected popover.background.magnifier button, popover.background.magnifier row:selected button, row:selected +button { + border-color: #FF5F57; } + row:selected popover.background.touch-selection button.flat:not(:active):not(:checked):not(:hover):not(disabled), popover.background.touch-selection row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled), row:selected popover.background.magnifier button.flat:not(:active):not(:checked):not(:hover):not(disabled), popover.background.magnifier row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled), row:selected + button.flat:not(:active):not(:checked):not(:hover):not(disabled) { + color: white; + border-color: transparent; } + row:selected popover.background.touch-selection button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop, popover.background.touch-selection row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop, row:selected popover.background.magnifier button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop, popover.background.magnifier row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop, row:selected + button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop { + color: white; } +popover.background.touch-selection button.suggested-action, popover.background.magnifier button.suggested-action, popover.background.touch-selection button.suggested-action.osd button, popover.background.magnifier button.suggested-action.osd button, +button.suggested-action, +button.suggested-action.osd popover.background.touch-selection button, +popover.background.touch-selection button.suggested-action.osd button, +button.suggested-action.osd popover.background.magnifier button, +popover.background.magnifier button.suggested-action.osd button, popover.background.touch-selection button.suggested-action.osd +button, popover.background.magnifier button.suggested-action.osd +button, +button.suggested-action.osd +button { + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); + text-shadow: none; + -gtk-icon-shadow: none; + color: white; + border-color: #FF5F57; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); } + popover.background.touch-selection button.suggested-action.flat, popover.background.magnifier button.suggested-action.flat, popover.background.touch-selection button.suggested-action.osd button.flat, popover.background.magnifier button.suggested-action.osd button.flat, + button.suggested-action.flat, + button.suggested-action.osd popover.background.touch-selection button.flat, + popover.background.touch-selection button.suggested-action.osd button.flat, + button.suggested-action.osd popover.background.magnifier button.flat, + popover.background.magnifier button.suggested-action.osd button.flat, popover.background.touch-selection button.suggested-action.osd + button.flat, popover.background.magnifier button.suggested-action.osd + button.flat, + button.suggested-action.osd + button.flat { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + color: #FF5F57; } + popover.background.touch-selection button.suggested-action:hover, popover.background.magnifier button.suggested-action:hover, popover.background.touch-selection button.suggested-action.osd button:hover, popover.background.magnifier button.suggested-action.osd button:hover, + button.suggested-action:hover, + button.suggested-action.osd popover.background.touch-selection button:hover, + popover.background.touch-selection button.suggested-action.osd button:hover, + button.suggested-action.osd popover.background.magnifier button:hover, + popover.background.magnifier button.suggested-action.osd button:hover, popover.background.touch-selection button.suggested-action.osd + button:hover, popover.background.magnifier button.suggested-action.osd + button:hover, + button.suggested-action.osd + button:hover { + color: white; + border-color: #FF5F57; } + popover.background.touch-selection button.suggested-action:active, popover.background.magnifier button.suggested-action:active, popover.background.touch-selection button.suggested-action:checked, popover.background.magnifier button.suggested-action:checked, popover.background.touch-selection button.suggested-action.osd button:active, popover.background.magnifier button.suggested-action.osd button:active, popover.background.touch-selection button.suggested-action.osd button:checked, popover.background.magnifier button.suggested-action.osd button:checked, + button.suggested-action:active, + button.suggested-action:checked, + button.suggested-action.osd popover.background.touch-selection button:active, + popover.background.touch-selection button.suggested-action.osd button:active, + button.suggested-action.osd popover.background.magnifier button:active, + popover.background.magnifier button.suggested-action.osd button:active, + button.suggested-action.osd popover.background.touch-selection button:checked, + popover.background.touch-selection button.suggested-action.osd button:checked, + button.suggested-action.osd popover.background.magnifier button:checked, + popover.background.magnifier button.suggested-action.osd button:checked, popover.background.touch-selection button.suggested-action.osd + button:active, popover.background.magnifier button.suggested-action.osd + button:active, popover.background.touch-selection button.suggested-action.osd + button:checked, popover.background.magnifier button.suggested-action.osd + button:checked, + button.suggested-action.osd + button:active, + button.suggested-action.osd + button:checked { + color: white; + border-color: #FF5F57; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); } + popover.background.touch-selection button.suggested-action:backdrop, popover.background.magnifier button.suggested-action:backdrop, popover.background.touch-selection button.suggested-action.flat:backdrop, popover.background.magnifier button.suggested-action.flat:backdrop, popover.background.touch-selection button.suggested-action.osd button:backdrop, popover.background.magnifier button.suggested-action.osd button:backdrop, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop, popover.background.magnifier button.suggested-action.osd button.flat:backdrop, + button.suggested-action:backdrop, + button.suggested-action.flat:backdrop, + button.suggested-action.osd popover.background.touch-selection button:backdrop, + popover.background.touch-selection button.suggested-action.osd button:backdrop, + button.suggested-action.osd popover.background.magnifier button:backdrop, + popover.background.magnifier button.suggested-action.osd button:backdrop, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop, popover.background.touch-selection button.suggested-action.osd + button:backdrop, popover.background.magnifier button.suggested-action.osd + button:backdrop, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop, + button.suggested-action.osd + button:backdrop, + button.suggested-action.osd + button.flat:backdrop { + color: white; + border-color: #5f6367; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); } + popover.background.touch-selection button.suggested-action:backdrop:active, popover.background.magnifier button.suggested-action:backdrop:active, popover.background.touch-selection button.suggested-action:backdrop:checked, popover.background.magnifier button.suggested-action:backdrop:checked, popover.background.touch-selection button.suggested-action.flat:backdrop:active, popover.background.magnifier button.suggested-action.flat:backdrop:active, popover.background.touch-selection button.suggested-action.flat:backdrop:checked, popover.background.magnifier button.suggested-action.flat:backdrop:checked, popover.background.touch-selection button.suggested-action.osd button:backdrop:active, popover.background.magnifier button.suggested-action.osd button:backdrop:active, popover.background.touch-selection button.suggested-action.osd button:backdrop:checked, popover.background.magnifier button.suggested-action.osd button:backdrop:checked, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:active, popover.background.magnifier button.suggested-action.osd button.flat:backdrop:active, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:checked, popover.background.magnifier button.suggested-action.osd button.flat:backdrop:checked, + button.suggested-action:backdrop:active, + button.suggested-action:backdrop:checked, + button.suggested-action.flat:backdrop:active, + button.suggested-action.flat:backdrop:checked, + button.suggested-action.osd popover.background.touch-selection button:backdrop:active, + popover.background.touch-selection button.suggested-action.osd button:backdrop:active, + button.suggested-action.osd popover.background.magnifier button:backdrop:active, + popover.background.magnifier button.suggested-action.osd button:backdrop:active, + button.suggested-action.osd popover.background.touch-selection button:backdrop:checked, + popover.background.touch-selection button.suggested-action.osd button:backdrop:checked, + button.suggested-action.osd popover.background.magnifier button:backdrop:checked, + popover.background.magnifier button.suggested-action.osd button:backdrop:checked, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:active, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:active, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop:active, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop:active, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:checked, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:checked, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop:checked, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop:checked, popover.background.touch-selection button.suggested-action.osd + button:backdrop:active, popover.background.magnifier button.suggested-action.osd + button:backdrop:active, popover.background.touch-selection button.suggested-action.osd + button:backdrop:checked, popover.background.magnifier button.suggested-action.osd + button:backdrop:checked, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop:active, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop:active, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop:checked, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop:checked, + button.suggested-action.osd + button:backdrop:active, + button.suggested-action.osd + button:backdrop:checked, + button.suggested-action.osd + button.flat:backdrop:active, + button.suggested-action.osd + button.flat:backdrop:checked { + color: white; + border-color: #FF5F57; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); } + popover.background.touch-selection button.suggested-action:backdrop:disabled, popover.background.magnifier button.suggested-action:backdrop:disabled, popover.background.touch-selection button.suggested-action.flat:backdrop:disabled, popover.background.magnifier button.suggested-action.flat:backdrop:disabled, popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled, popover.background.magnifier button.suggested-action.osd button:backdrop:disabled, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled, popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled, + button.suggested-action:backdrop:disabled, + button.suggested-action.flat:backdrop:disabled, + button.suggested-action.osd popover.background.touch-selection button:backdrop:disabled, + popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled, + button.suggested-action.osd popover.background.magnifier button:backdrop:disabled, + popover.background.magnifier button.suggested-action.osd button:backdrop:disabled, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled, popover.background.touch-selection button.suggested-action.osd + button:backdrop:disabled, popover.background.magnifier button.suggested-action.osd + button:backdrop:disabled, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop:disabled, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop:disabled, + button.suggested-action.osd + button:backdrop:disabled, + button.suggested-action.osd + button.flat:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(86, 90, 94, 0.35); + background-image: linear-gradient(to bottom, #262b30, #24292e); } + popover.background.touch-selection button.suggested-action:backdrop:disabled > .label, popover.background.magnifier button.suggested-action:backdrop:disabled > .label, popover.background.touch-selection button.suggested-action.flat:backdrop:disabled > .label, popover.background.magnifier button.suggested-action.flat:backdrop:disabled > .label, popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled > .label, popover.background.magnifier button.suggested-action.osd popover.background.touch-selection button:backdrop:disabled > .label, popover.background.touch-selection button.suggested-action.osd popover.background.magnifier button:backdrop:disabled > .label, popover.background.magnifier button.suggested-action.osd button:backdrop:disabled > .label, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled > .label, popover.background.magnifier button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled > .label, popover.background.touch-selection button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled > .label, popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled > .label, + button.suggested-action:backdrop:disabled > .label, + button.suggested-action.flat:backdrop:disabled > .label, + button.suggested-action.osd popover.background.touch-selection button:backdrop:disabled > .label, + popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled > .label, + button.suggested-action.osd popover.background.magnifier button:backdrop:disabled > .label, + popover.background.magnifier button.suggested-action.osd button:backdrop:disabled > .label, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled > .label, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled > .label, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled > .label, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled > .label, popover.background.touch-selection button.suggested-action.osd + button:backdrop:disabled > .label, popover.background.magnifier button.suggested-action.osd + button:backdrop:disabled > .label, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop:disabled > .label, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop:disabled > .label, + button.suggested-action.osd + button:backdrop:disabled > .label, + button.suggested-action.osd + button.flat:backdrop:disabled > .label { + color: inherit; } + popover.background.touch-selection button.suggested-action:backdrop:disabled:active, popover.background.magnifier button.suggested-action:backdrop:disabled:active, popover.background.touch-selection button.suggested-action:backdrop:disabled:checked, popover.background.magnifier button.suggested-action:backdrop:disabled:checked, popover.background.touch-selection button.suggested-action.flat:backdrop:disabled:active, popover.background.magnifier button.suggested-action.flat:backdrop:disabled:active, popover.background.touch-selection button.suggested-action.flat:backdrop:disabled:checked, popover.background.magnifier button.suggested-action.flat:backdrop:disabled:checked, popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled:active, popover.background.magnifier button.suggested-action.osd button:backdrop:disabled:active, popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled:checked, popover.background.magnifier button.suggested-action.osd button:backdrop:disabled:checked, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled:active, popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled:active, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled:checked, popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled:checked, + button.suggested-action:backdrop:disabled:active, + button.suggested-action:backdrop:disabled:checked, + button.suggested-action.flat:backdrop:disabled:active, + button.suggested-action.flat:backdrop:disabled:checked, + button.suggested-action.osd popover.background.touch-selection button:backdrop:disabled:active, + popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled:active, + button.suggested-action.osd popover.background.magnifier button:backdrop:disabled:active, + popover.background.magnifier button.suggested-action.osd button:backdrop:disabled:active, + button.suggested-action.osd popover.background.touch-selection button:backdrop:disabled:checked, + popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled:checked, + button.suggested-action.osd popover.background.magnifier button:backdrop:disabled:checked, + popover.background.magnifier button.suggested-action.osd button:backdrop:disabled:checked, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled:active, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled:active, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled:active, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled:active, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled:checked, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled:checked, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled:checked, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled:checked, popover.background.touch-selection button.suggested-action.osd + button:backdrop:disabled:active, popover.background.magnifier button.suggested-action.osd + button:backdrop:disabled:active, popover.background.touch-selection button.suggested-action.osd + button:backdrop:disabled:checked, popover.background.magnifier button.suggested-action.osd + button:backdrop:disabled:checked, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop:disabled:active, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop:disabled:active, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop:disabled:checked, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop:disabled:checked, + button.suggested-action.osd + button:backdrop:disabled:active, + button.suggested-action.osd + button:backdrop:disabled:checked, + button.suggested-action.osd + button.flat:backdrop:disabled:active, + button.suggested-action.osd + button.flat:backdrop:disabled:checked { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(24, 171, 142, 0.35); + background-image: linear-gradient(to bottom, rgba(255, 95, 87, 0.35), rgba(255, 95, 87, 0.35)); } + popover.background.touch-selection button.suggested-action:backdrop:disabled:active > .label, popover.background.magnifier button.suggested-action:backdrop:disabled:active > .label, popover.background.touch-selection button.suggested-action:backdrop:disabled:checked > .label, popover.background.magnifier button.suggested-action:backdrop:disabled:checked > .label, popover.background.touch-selection button.suggested-action.flat:backdrop:disabled:active > .label, popover.background.magnifier button.suggested-action.flat:backdrop:disabled:active > .label, popover.background.touch-selection button.suggested-action.flat:backdrop:disabled:checked > .label, popover.background.magnifier button.suggested-action.flat:backdrop:disabled:checked > .label, popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled:active > .label, popover.background.magnifier button.suggested-action.osd popover.background.touch-selection button:backdrop:disabled:active > .label, popover.background.touch-selection button.suggested-action.osd popover.background.magnifier button:backdrop:disabled:active > .label, popover.background.magnifier button.suggested-action.osd button:backdrop:disabled:active > .label, popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled:checked > .label, popover.background.magnifier button.suggested-action.osd popover.background.touch-selection button:backdrop:disabled:checked > .label, popover.background.touch-selection button.suggested-action.osd popover.background.magnifier button:backdrop:disabled:checked > .label, popover.background.magnifier button.suggested-action.osd button:backdrop:disabled:checked > .label, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled:active > .label, popover.background.magnifier button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled:active > .label, popover.background.touch-selection button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled:active > .label, popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled:active > .label, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled:checked > .label, popover.background.magnifier button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled:checked > .label, popover.background.touch-selection button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled:checked > .label, popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled:checked > .label, + button.suggested-action:backdrop:disabled:active > .label, + button.suggested-action:backdrop:disabled:checked > .label, + button.suggested-action.flat:backdrop:disabled:active > .label, + button.suggested-action.flat:backdrop:disabled:checked > .label, + button.suggested-action.osd popover.background.touch-selection button:backdrop:disabled:active > .label, + popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled:active > .label, + button.suggested-action.osd popover.background.magnifier button:backdrop:disabled:active > .label, + popover.background.magnifier button.suggested-action.osd button:backdrop:disabled:active > .label, + button.suggested-action.osd popover.background.touch-selection button:backdrop:disabled:checked > .label, + popover.background.touch-selection button.suggested-action.osd button:backdrop:disabled:checked > .label, + button.suggested-action.osd popover.background.magnifier button:backdrop:disabled:checked > .label, + popover.background.magnifier button.suggested-action.osd button:backdrop:disabled:checked > .label, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled:active > .label, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled:active > .label, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled:active > .label, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled:active > .label, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled:checked > .label, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled:checked > .label, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled:checked > .label, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled:checked > .label, popover.background.touch-selection button.suggested-action.osd + button:backdrop:disabled:active > .label, popover.background.magnifier button.suggested-action.osd + button:backdrop:disabled:active > .label, popover.background.touch-selection button.suggested-action.osd + button:backdrop:disabled:checked > .label, popover.background.magnifier button.suggested-action.osd + button:backdrop:disabled:checked > .label, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop:disabled:active > .label, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop:disabled:active > .label, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop:disabled:checked > .label, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop:disabled:checked > .label, + button.suggested-action.osd + button:backdrop:disabled:active > .label, + button.suggested-action.osd + button:backdrop:disabled:checked > .label, + button.suggested-action.osd + button.flat:backdrop:disabled:active > .label, + button.suggested-action.osd + button.flat:backdrop:disabled:checked > .label { + color: inherit; } + popover.background.touch-selection button.suggested-action.flat:backdrop, popover.background.magnifier button.suggested-action.flat:backdrop, popover.background.touch-selection button.suggested-action.flat:disabled, popover.background.magnifier button.suggested-action.flat:disabled, popover.background.touch-selection button.suggested-action.flat:backdrop:disabled, popover.background.magnifier button.suggested-action.flat:backdrop:disabled, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop, popover.background.magnifier button.suggested-action.osd button.flat:backdrop, popover.background.touch-selection button.suggested-action.osd button.flat:disabled, popover.background.magnifier button.suggested-action.osd button.flat:disabled, popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled, popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled, + button.suggested-action.flat:backdrop, + button.suggested-action.flat:disabled, + button.suggested-action.flat:backdrop:disabled, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop, + button.suggested-action.osd popover.background.touch-selection button.flat:disabled, + popover.background.touch-selection button.suggested-action.osd button.flat:disabled, + button.suggested-action.osd popover.background.magnifier button.flat:disabled, + popover.background.magnifier button.suggested-action.osd button.flat:disabled, + button.suggested-action.osd popover.background.touch-selection button.flat:backdrop:disabled, + popover.background.touch-selection button.suggested-action.osd button.flat:backdrop:disabled, + button.suggested-action.osd popover.background.magnifier button.flat:backdrop:disabled, + popover.background.magnifier button.suggested-action.osd button.flat:backdrop:disabled, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop, popover.background.touch-selection button.suggested-action.osd + button.flat:disabled, popover.background.magnifier button.suggested-action.osd + button.flat:disabled, popover.background.touch-selection button.suggested-action.osd + button.flat:backdrop:disabled, popover.background.magnifier button.suggested-action.osd + button.flat:backdrop:disabled, + button.suggested-action.osd + button.flat:backdrop, + button.suggested-action.osd + button.flat:disabled, + button.suggested-action.osd + button.flat:backdrop:disabled { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + color: rgba(255, 95, 87, 0.8); } + popover.background.touch-selection button.suggested-action:disabled, popover.background.magnifier button.suggested-action:disabled, popover.background.touch-selection button.suggested-action.osd button:disabled, popover.background.magnifier button.suggested-action.osd button:disabled, + button.suggested-action:disabled, + button.suggested-action.osd popover.background.touch-selection button:disabled, + popover.background.touch-selection button.suggested-action.osd button:disabled, + button.suggested-action.osd popover.background.magnifier button:disabled, + popover.background.magnifier button.suggested-action.osd button:disabled, popover.background.touch-selection button.suggested-action.osd + button:disabled, popover.background.magnifier button.suggested-action.osd + button:disabled, + button.suggested-action.osd + button:disabled { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(86, 90, 94, 0.35); + background-image: linear-gradient(to bottom, #262b30, #24292e); } + popover.background.touch-selection button.suggested-action:disabled > .label, popover.background.magnifier button.suggested-action:disabled > .label, popover.background.touch-selection button.suggested-action.osd button:disabled > .label, popover.background.magnifier button.suggested-action.osd popover.background.touch-selection button:disabled > .label, popover.background.touch-selection button.suggested-action.osd popover.background.magnifier button:disabled > .label, popover.background.magnifier button.suggested-action.osd button:disabled > .label, + button.suggested-action:disabled > .label, + button.suggested-action.osd popover.background.touch-selection button:disabled > .label, + popover.background.touch-selection button.suggested-action.osd button:disabled > .label, + button.suggested-action.osd popover.background.magnifier button:disabled > .label, + popover.background.magnifier button.suggested-action.osd button:disabled > .label, popover.background.touch-selection button.suggested-action.osd + button:disabled > .label, popover.background.magnifier button.suggested-action.osd + button:disabled > .label, + button.suggested-action.osd + button:disabled > .label { + color: inherit; } + popover.background.touch-selection button.suggested-action:disabled:active, popover.background.magnifier button.suggested-action:disabled:active, popover.background.touch-selection button.suggested-action:disabled:checked, popover.background.magnifier button.suggested-action:disabled:checked, popover.background.touch-selection button.suggested-action.osd button:disabled:active, popover.background.magnifier button.suggested-action.osd button:disabled:active, popover.background.touch-selection button.suggested-action.osd button:disabled:checked, popover.background.magnifier button.suggested-action.osd button:disabled:checked, + button.suggested-action:disabled:active, + button.suggested-action:disabled:checked, + button.suggested-action.osd popover.background.touch-selection button:disabled:active, + popover.background.touch-selection button.suggested-action.osd button:disabled:active, + button.suggested-action.osd popover.background.magnifier button:disabled:active, + popover.background.magnifier button.suggested-action.osd button:disabled:active, + button.suggested-action.osd popover.background.touch-selection button:disabled:checked, + popover.background.touch-selection button.suggested-action.osd button:disabled:checked, + button.suggested-action.osd popover.background.magnifier button:disabled:checked, + popover.background.magnifier button.suggested-action.osd button:disabled:checked, popover.background.touch-selection button.suggested-action.osd + button:disabled:active, popover.background.magnifier button.suggested-action.osd + button:disabled:active, popover.background.touch-selection button.suggested-action.osd + button:disabled:checked, popover.background.magnifier button.suggested-action.osd + button:disabled:checked, + button.suggested-action.osd + button:disabled:active, + button.suggested-action.osd + button:disabled:checked { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(24, 171, 142, 0.35); + background-image: linear-gradient(to bottom, rgba(255, 95, 87, 0.35), rgba(255, 95, 87, 0.35)); } + popover.background.touch-selection button.suggested-action:disabled:active > .label, popover.background.magnifier button.suggested-action:disabled:active > .label, popover.background.touch-selection button.suggested-action:disabled:checked > .label, popover.background.magnifier button.suggested-action:disabled:checked > .label, popover.background.touch-selection button.suggested-action.osd button:disabled:active > .label, popover.background.magnifier button.suggested-action.osd popover.background.touch-selection button:disabled:active > .label, popover.background.touch-selection button.suggested-action.osd popover.background.magnifier button:disabled:active > .label, popover.background.magnifier button.suggested-action.osd button:disabled:active > .label, popover.background.touch-selection button.suggested-action.osd button:disabled:checked > .label, popover.background.magnifier button.suggested-action.osd popover.background.touch-selection button:disabled:checked > .label, popover.background.touch-selection button.suggested-action.osd popover.background.magnifier button:disabled:checked > .label, popover.background.magnifier button.suggested-action.osd button:disabled:checked > .label, + button.suggested-action:disabled:active > .label, + button.suggested-action:disabled:checked > .label, + button.suggested-action.osd popover.background.touch-selection button:disabled:active > .label, + popover.background.touch-selection button.suggested-action.osd button:disabled:active > .label, + button.suggested-action.osd popover.background.magnifier button:disabled:active > .label, + popover.background.magnifier button.suggested-action.osd button:disabled:active > .label, + button.suggested-action.osd popover.background.touch-selection button:disabled:checked > .label, + popover.background.touch-selection button.suggested-action.osd button:disabled:checked > .label, + button.suggested-action.osd popover.background.magnifier button:disabled:checked > .label, + popover.background.magnifier button.suggested-action.osd button:disabled:checked > .label, popover.background.touch-selection button.suggested-action.osd + button:disabled:active > .label, popover.background.magnifier button.suggested-action.osd + button:disabled:active > .label, popover.background.touch-selection button.suggested-action.osd + button:disabled:checked > .label, popover.background.magnifier button.suggested-action.osd + button:disabled:checked > .label, + button.suggested-action.osd + button:disabled:active > .label, + button.suggested-action.osd + button:disabled:checked > .label { + color: inherit; } +popover.background.touch-selection button.destructive-action, popover.background.magnifier button.destructive-action, popover.background.touch-selection button.destructive-action.osd button, popover.background.magnifier button.destructive-action.osd button, +button.destructive-action, +button.destructive-action.osd popover.background.touch-selection button, +popover.background.touch-selection button.destructive-action.osd button, +button.destructive-action.osd popover.background.magnifier button, +popover.background.magnifier button.destructive-action.osd button, popover.background.touch-selection button.destructive-action.osd +button, popover.background.magnifier button.destructive-action.osd +button, +button.destructive-action.osd +button { + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); + text-shadow: none; + -gtk-icon-shadow: none; + color: white; + border-color: #e74c3c; + background-image: linear-gradient(to bottom, #e74e3f, #e64534); } + popover.background.touch-selection button.destructive-action.flat, popover.background.magnifier button.destructive-action.flat, popover.background.touch-selection button.destructive-action.osd button.flat, popover.background.magnifier button.destructive-action.osd button.flat, + button.destructive-action.flat, + button.destructive-action.osd popover.background.touch-selection button.flat, + popover.background.touch-selection button.destructive-action.osd button.flat, + button.destructive-action.osd popover.background.magnifier button.flat, + popover.background.magnifier button.destructive-action.osd button.flat, popover.background.touch-selection button.destructive-action.osd + button.flat, popover.background.magnifier button.destructive-action.osd + button.flat, + button.destructive-action.osd + button.flat { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + color: #e74c3c; } + popover.background.touch-selection button.destructive-action:hover, popover.background.magnifier button.destructive-action:hover, popover.background.touch-selection button.destructive-action.osd button:hover, popover.background.magnifier button.destructive-action.osd button:hover, + button.destructive-action:hover, + button.destructive-action.osd popover.background.touch-selection button:hover, + popover.background.touch-selection button.destructive-action.osd button:hover, + button.destructive-action.osd popover.background.magnifier button:hover, + popover.background.magnifier button.destructive-action.osd button:hover, popover.background.touch-selection button.destructive-action.osd + button:hover, popover.background.magnifier button.destructive-action.osd + button:hover, + button.destructive-action.osd + button:hover { + color: white; + border-color: #e74c3c; } + popover.background.touch-selection button.destructive-action:active, popover.background.magnifier button.destructive-action:active, popover.background.touch-selection button.destructive-action:checked, popover.background.magnifier button.destructive-action:checked, popover.background.touch-selection button.destructive-action.osd button:active, popover.background.magnifier button.destructive-action.osd button:active, popover.background.touch-selection button.destructive-action.osd button:checked, popover.background.magnifier button.destructive-action.osd button:checked, + button.destructive-action:active, + button.destructive-action:checked, + button.destructive-action.osd popover.background.touch-selection button:active, + popover.background.touch-selection button.destructive-action.osd button:active, + button.destructive-action.osd popover.background.magnifier button:active, + popover.background.magnifier button.destructive-action.osd button:active, + button.destructive-action.osd popover.background.touch-selection button:checked, + popover.background.touch-selection button.destructive-action.osd button:checked, + button.destructive-action.osd popover.background.magnifier button:checked, + popover.background.magnifier button.destructive-action.osd button:checked, popover.background.touch-selection button.destructive-action.osd + button:active, popover.background.magnifier button.destructive-action.osd + button:active, popover.background.touch-selection button.destructive-action.osd + button:checked, popover.background.magnifier button.destructive-action.osd + button:checked, + button.destructive-action.osd + button:active, + button.destructive-action.osd + button:checked { + color: white; + border-color: #e74c3c; + background-image: linear-gradient(to bottom, #e85344, #e43624); } + popover.background.touch-selection button.destructive-action:backdrop, popover.background.magnifier button.destructive-action:backdrop, popover.background.touch-selection button.destructive-action.flat:backdrop, popover.background.magnifier button.destructive-action.flat:backdrop, popover.background.touch-selection button.destructive-action.osd button:backdrop, popover.background.magnifier button.destructive-action.osd button:backdrop, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop, popover.background.magnifier button.destructive-action.osd button.flat:backdrop, + button.destructive-action:backdrop, + button.destructive-action.flat:backdrop, + button.destructive-action.osd popover.background.touch-selection button:backdrop, + popover.background.touch-selection button.destructive-action.osd button:backdrop, + button.destructive-action.osd popover.background.magnifier button:backdrop, + popover.background.magnifier button.destructive-action.osd button:backdrop, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop, popover.background.touch-selection button.destructive-action.osd + button:backdrop, popover.background.magnifier button.destructive-action.osd + button:backdrop, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop, + button.destructive-action.osd + button:backdrop, + button.destructive-action.osd + button.flat:backdrop { + color: white; + border-color: #5f6367; + background-image: linear-gradient(to bottom, #e74e3f, #e64534); } + popover.background.touch-selection button.destructive-action:backdrop:active, popover.background.magnifier button.destructive-action:backdrop:active, popover.background.touch-selection button.destructive-action:backdrop:checked, popover.background.magnifier button.destructive-action:backdrop:checked, popover.background.touch-selection button.destructive-action.flat:backdrop:active, popover.background.magnifier button.destructive-action.flat:backdrop:active, popover.background.touch-selection button.destructive-action.flat:backdrop:checked, popover.background.magnifier button.destructive-action.flat:backdrop:checked, popover.background.touch-selection button.destructive-action.osd button:backdrop:active, popover.background.magnifier button.destructive-action.osd button:backdrop:active, popover.background.touch-selection button.destructive-action.osd button:backdrop:checked, popover.background.magnifier button.destructive-action.osd button:backdrop:checked, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:active, popover.background.magnifier button.destructive-action.osd button.flat:backdrop:active, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:checked, popover.background.magnifier button.destructive-action.osd button.flat:backdrop:checked, + button.destructive-action:backdrop:active, + button.destructive-action:backdrop:checked, + button.destructive-action.flat:backdrop:active, + button.destructive-action.flat:backdrop:checked, + button.destructive-action.osd popover.background.touch-selection button:backdrop:active, + popover.background.touch-selection button.destructive-action.osd button:backdrop:active, + button.destructive-action.osd popover.background.magnifier button:backdrop:active, + popover.background.magnifier button.destructive-action.osd button:backdrop:active, + button.destructive-action.osd popover.background.touch-selection button:backdrop:checked, + popover.background.touch-selection button.destructive-action.osd button:backdrop:checked, + button.destructive-action.osd popover.background.magnifier button:backdrop:checked, + popover.background.magnifier button.destructive-action.osd button:backdrop:checked, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:active, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:active, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop:active, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop:active, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:checked, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:checked, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop:checked, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop:checked, popover.background.touch-selection button.destructive-action.osd + button:backdrop:active, popover.background.magnifier button.destructive-action.osd + button:backdrop:active, popover.background.touch-selection button.destructive-action.osd + button:backdrop:checked, popover.background.magnifier button.destructive-action.osd + button:backdrop:checked, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop:active, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop:active, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop:checked, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop:checked, + button.destructive-action.osd + button:backdrop:active, + button.destructive-action.osd + button:backdrop:checked, + button.destructive-action.osd + button.flat:backdrop:active, + button.destructive-action.osd + button.flat:backdrop:checked { + color: white; + border-color: #e74c3c; + background-image: linear-gradient(to bottom, #e85344, #e43624); } + popover.background.touch-selection button.destructive-action:backdrop:disabled, popover.background.magnifier button.destructive-action:backdrop:disabled, popover.background.touch-selection button.destructive-action.flat:backdrop:disabled, popover.background.magnifier button.destructive-action.flat:backdrop:disabled, popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled, popover.background.magnifier button.destructive-action.osd button:backdrop:disabled, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled, popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled, + button.destructive-action:backdrop:disabled, + button.destructive-action.flat:backdrop:disabled, + button.destructive-action.osd popover.background.touch-selection button:backdrop:disabled, + popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled, + button.destructive-action.osd popover.background.magnifier button:backdrop:disabled, + popover.background.magnifier button.destructive-action.osd button:backdrop:disabled, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled, popover.background.touch-selection button.destructive-action.osd + button:backdrop:disabled, popover.background.magnifier button.destructive-action.osd + button:backdrop:disabled, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop:disabled, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop:disabled, + button.destructive-action.osd + button:backdrop:disabled, + button.destructive-action.osd + button.flat:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(86, 90, 94, 0.35); + background-image: linear-gradient(to bottom, #262b30, #24292e); } + popover.background.touch-selection button.destructive-action:backdrop:disabled > .label, popover.background.magnifier button.destructive-action:backdrop:disabled > .label, popover.background.touch-selection button.destructive-action.flat:backdrop:disabled > .label, popover.background.magnifier button.destructive-action.flat:backdrop:disabled > .label, popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled > .label, popover.background.magnifier button.destructive-action.osd popover.background.touch-selection button:backdrop:disabled > .label, popover.background.touch-selection button.destructive-action.osd popover.background.magnifier button:backdrop:disabled > .label, popover.background.magnifier button.destructive-action.osd button:backdrop:disabled > .label, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled > .label, popover.background.magnifier button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled > .label, popover.background.touch-selection button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled > .label, popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled > .label, + button.destructive-action:backdrop:disabled > .label, + button.destructive-action.flat:backdrop:disabled > .label, + button.destructive-action.osd popover.background.touch-selection button:backdrop:disabled > .label, + popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled > .label, + button.destructive-action.osd popover.background.magnifier button:backdrop:disabled > .label, + popover.background.magnifier button.destructive-action.osd button:backdrop:disabled > .label, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled > .label, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled > .label, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled > .label, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled > .label, popover.background.touch-selection button.destructive-action.osd + button:backdrop:disabled > .label, popover.background.magnifier button.destructive-action.osd + button:backdrop:disabled > .label, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop:disabled > .label, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop:disabled > .label, + button.destructive-action.osd + button:backdrop:disabled > .label, + button.destructive-action.osd + button.flat:backdrop:disabled > .label { + color: inherit; } + popover.background.touch-selection button.destructive-action:backdrop:disabled:active, popover.background.magnifier button.destructive-action:backdrop:disabled:active, popover.background.touch-selection button.destructive-action:backdrop:disabled:checked, popover.background.magnifier button.destructive-action:backdrop:disabled:checked, popover.background.touch-selection button.destructive-action.flat:backdrop:disabled:active, popover.background.magnifier button.destructive-action.flat:backdrop:disabled:active, popover.background.touch-selection button.destructive-action.flat:backdrop:disabled:checked, popover.background.magnifier button.destructive-action.flat:backdrop:disabled:checked, popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled:active, popover.background.magnifier button.destructive-action.osd button:backdrop:disabled:active, popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled:checked, popover.background.magnifier button.destructive-action.osd button:backdrop:disabled:checked, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled:active, popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled:active, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled:checked, popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled:checked, + button.destructive-action:backdrop:disabled:active, + button.destructive-action:backdrop:disabled:checked, + button.destructive-action.flat:backdrop:disabled:active, + button.destructive-action.flat:backdrop:disabled:checked, + button.destructive-action.osd popover.background.touch-selection button:backdrop:disabled:active, + popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled:active, + button.destructive-action.osd popover.background.magnifier button:backdrop:disabled:active, + popover.background.magnifier button.destructive-action.osd button:backdrop:disabled:active, + button.destructive-action.osd popover.background.touch-selection button:backdrop:disabled:checked, + popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled:checked, + button.destructive-action.osd popover.background.magnifier button:backdrop:disabled:checked, + popover.background.magnifier button.destructive-action.osd button:backdrop:disabled:checked, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled:active, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled:active, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled:active, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled:active, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled:checked, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled:checked, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled:checked, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled:checked, popover.background.touch-selection button.destructive-action.osd + button:backdrop:disabled:active, popover.background.magnifier button.destructive-action.osd + button:backdrop:disabled:active, popover.background.touch-selection button.destructive-action.osd + button:backdrop:disabled:checked, popover.background.magnifier button.destructive-action.osd + button:backdrop:disabled:checked, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop:disabled:active, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop:disabled:active, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop:disabled:checked, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop:disabled:checked, + button.destructive-action.osd + button:backdrop:disabled:active, + button.destructive-action.osd + button:backdrop:disabled:checked, + button.destructive-action.osd + button.flat:backdrop:disabled:active, + button.destructive-action.osd + button.flat:backdrop:disabled:checked { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(228, 54, 36, 0.35); + background-image: linear-gradient(to bottom, rgba(229, 61, 44, 0.35), rgba(214, 44, 26, 0.35)); } + popover.background.touch-selection button.destructive-action:backdrop:disabled:active > .label, popover.background.magnifier button.destructive-action:backdrop:disabled:active > .label, popover.background.touch-selection button.destructive-action:backdrop:disabled:checked > .label, popover.background.magnifier button.destructive-action:backdrop:disabled:checked > .label, popover.background.touch-selection button.destructive-action.flat:backdrop:disabled:active > .label, popover.background.magnifier button.destructive-action.flat:backdrop:disabled:active > .label, popover.background.touch-selection button.destructive-action.flat:backdrop:disabled:checked > .label, popover.background.magnifier button.destructive-action.flat:backdrop:disabled:checked > .label, popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled:active > .label, popover.background.magnifier button.destructive-action.osd popover.background.touch-selection button:backdrop:disabled:active > .label, popover.background.touch-selection button.destructive-action.osd popover.background.magnifier button:backdrop:disabled:active > .label, popover.background.magnifier button.destructive-action.osd button:backdrop:disabled:active > .label, popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled:checked > .label, popover.background.magnifier button.destructive-action.osd popover.background.touch-selection button:backdrop:disabled:checked > .label, popover.background.touch-selection button.destructive-action.osd popover.background.magnifier button:backdrop:disabled:checked > .label, popover.background.magnifier button.destructive-action.osd button:backdrop:disabled:checked > .label, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled:active > .label, popover.background.magnifier button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled:active > .label, popover.background.touch-selection button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled:active > .label, popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled:active > .label, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled:checked > .label, popover.background.magnifier button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled:checked > .label, popover.background.touch-selection button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled:checked > .label, popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled:checked > .label, + button.destructive-action:backdrop:disabled:active > .label, + button.destructive-action:backdrop:disabled:checked > .label, + button.destructive-action.flat:backdrop:disabled:active > .label, + button.destructive-action.flat:backdrop:disabled:checked > .label, + button.destructive-action.osd popover.background.touch-selection button:backdrop:disabled:active > .label, + popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled:active > .label, + button.destructive-action.osd popover.background.magnifier button:backdrop:disabled:active > .label, + popover.background.magnifier button.destructive-action.osd button:backdrop:disabled:active > .label, + button.destructive-action.osd popover.background.touch-selection button:backdrop:disabled:checked > .label, + popover.background.touch-selection button.destructive-action.osd button:backdrop:disabled:checked > .label, + button.destructive-action.osd popover.background.magnifier button:backdrop:disabled:checked > .label, + popover.background.magnifier button.destructive-action.osd button:backdrop:disabled:checked > .label, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled:active > .label, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled:active > .label, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled:active > .label, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled:active > .label, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled:checked > .label, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled:checked > .label, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled:checked > .label, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled:checked > .label, popover.background.touch-selection button.destructive-action.osd + button:backdrop:disabled:active > .label, popover.background.magnifier button.destructive-action.osd + button:backdrop:disabled:active > .label, popover.background.touch-selection button.destructive-action.osd + button:backdrop:disabled:checked > .label, popover.background.magnifier button.destructive-action.osd + button:backdrop:disabled:checked > .label, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop:disabled:active > .label, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop:disabled:active > .label, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop:disabled:checked > .label, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop:disabled:checked > .label, + button.destructive-action.osd + button:backdrop:disabled:active > .label, + button.destructive-action.osd + button:backdrop:disabled:checked > .label, + button.destructive-action.osd + button.flat:backdrop:disabled:active > .label, + button.destructive-action.osd + button.flat:backdrop:disabled:checked > .label { + color: inherit; } + popover.background.touch-selection button.destructive-action.flat:backdrop, popover.background.magnifier button.destructive-action.flat:backdrop, popover.background.touch-selection button.destructive-action.flat:disabled, popover.background.magnifier button.destructive-action.flat:disabled, popover.background.touch-selection button.destructive-action.flat:backdrop:disabled, popover.background.magnifier button.destructive-action.flat:backdrop:disabled, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop, popover.background.magnifier button.destructive-action.osd button.flat:backdrop, popover.background.touch-selection button.destructive-action.osd button.flat:disabled, popover.background.magnifier button.destructive-action.osd button.flat:disabled, popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled, popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled, + button.destructive-action.flat:backdrop, + button.destructive-action.flat:disabled, + button.destructive-action.flat:backdrop:disabled, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop, + button.destructive-action.osd popover.background.touch-selection button.flat:disabled, + popover.background.touch-selection button.destructive-action.osd button.flat:disabled, + button.destructive-action.osd popover.background.magnifier button.flat:disabled, + popover.background.magnifier button.destructive-action.osd button.flat:disabled, + button.destructive-action.osd popover.background.touch-selection button.flat:backdrop:disabled, + popover.background.touch-selection button.destructive-action.osd button.flat:backdrop:disabled, + button.destructive-action.osd popover.background.magnifier button.flat:backdrop:disabled, + popover.background.magnifier button.destructive-action.osd button.flat:backdrop:disabled, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop, popover.background.touch-selection button.destructive-action.osd + button.flat:disabled, popover.background.magnifier button.destructive-action.osd + button.flat:disabled, popover.background.touch-selection button.destructive-action.osd + button.flat:backdrop:disabled, popover.background.magnifier button.destructive-action.osd + button.flat:backdrop:disabled, + button.destructive-action.osd + button.flat:backdrop, + button.destructive-action.osd + button.flat:disabled, + button.destructive-action.osd + button.flat:backdrop:disabled { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + color: rgba(231, 76, 60, 0.8); } + popover.background.touch-selection button.destructive-action:disabled, popover.background.magnifier button.destructive-action:disabled, popover.background.touch-selection button.destructive-action.osd button:disabled, popover.background.magnifier button.destructive-action.osd button:disabled, + button.destructive-action:disabled, + button.destructive-action.osd popover.background.touch-selection button:disabled, + popover.background.touch-selection button.destructive-action.osd button:disabled, + button.destructive-action.osd popover.background.magnifier button:disabled, + popover.background.magnifier button.destructive-action.osd button:disabled, popover.background.touch-selection button.destructive-action.osd + button:disabled, popover.background.magnifier button.destructive-action.osd + button:disabled, + button.destructive-action.osd + button:disabled { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(86, 90, 94, 0.35); + background-image: linear-gradient(to bottom, #262b30, #24292e); } + popover.background.touch-selection button.destructive-action:disabled > .label, popover.background.magnifier button.destructive-action:disabled > .label, popover.background.touch-selection button.destructive-action.osd button:disabled > .label, popover.background.magnifier button.destructive-action.osd popover.background.touch-selection button:disabled > .label, popover.background.touch-selection button.destructive-action.osd popover.background.magnifier button:disabled > .label, popover.background.magnifier button.destructive-action.osd button:disabled > .label, + button.destructive-action:disabled > .label, + button.destructive-action.osd popover.background.touch-selection button:disabled > .label, + popover.background.touch-selection button.destructive-action.osd button:disabled > .label, + button.destructive-action.osd popover.background.magnifier button:disabled > .label, + popover.background.magnifier button.destructive-action.osd button:disabled > .label, popover.background.touch-selection button.destructive-action.osd + button:disabled > .label, popover.background.magnifier button.destructive-action.osd + button:disabled > .label, + button.destructive-action.osd + button:disabled > .label { + color: inherit; } + popover.background.touch-selection button.destructive-action:disabled:active, popover.background.magnifier button.destructive-action:disabled:active, popover.background.touch-selection button.destructive-action:disabled:checked, popover.background.magnifier button.destructive-action:disabled:checked, popover.background.touch-selection button.destructive-action.osd button:disabled:active, popover.background.magnifier button.destructive-action.osd button:disabled:active, popover.background.touch-selection button.destructive-action.osd button:disabled:checked, popover.background.magnifier button.destructive-action.osd button:disabled:checked, + button.destructive-action:disabled:active, + button.destructive-action:disabled:checked, + button.destructive-action.osd popover.background.touch-selection button:disabled:active, + popover.background.touch-selection button.destructive-action.osd button:disabled:active, + button.destructive-action.osd popover.background.magnifier button:disabled:active, + popover.background.magnifier button.destructive-action.osd button:disabled:active, + button.destructive-action.osd popover.background.touch-selection button:disabled:checked, + popover.background.touch-selection button.destructive-action.osd button:disabled:checked, + button.destructive-action.osd popover.background.magnifier button:disabled:checked, + popover.background.magnifier button.destructive-action.osd button:disabled:checked, popover.background.touch-selection button.destructive-action.osd + button:disabled:active, popover.background.magnifier button.destructive-action.osd + button:disabled:active, popover.background.touch-selection button.destructive-action.osd + button:disabled:checked, popover.background.magnifier button.destructive-action.osd + button:disabled:checked, + button.destructive-action.osd + button:disabled:active, + button.destructive-action.osd + button:disabled:checked { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(24, 171, 142, 0.35); + background-image: linear-gradient(to bottom, rgba(229, 61, 44, 0.35), rgba(214, 44, 26, 0.35)); } + popover.background.touch-selection button.destructive-action:disabled:active > .label, popover.background.magnifier button.destructive-action:disabled:active > .label, popover.background.touch-selection button.destructive-action:disabled:checked > .label, popover.background.magnifier button.destructive-action:disabled:checked > .label, popover.background.touch-selection button.destructive-action.osd button:disabled:active > .label, popover.background.magnifier button.destructive-action.osd popover.background.touch-selection button:disabled:active > .label, popover.background.touch-selection button.destructive-action.osd popover.background.magnifier button:disabled:active > .label, popover.background.magnifier button.destructive-action.osd button:disabled:active > .label, popover.background.touch-selection button.destructive-action.osd button:disabled:checked > .label, popover.background.magnifier button.destructive-action.osd popover.background.touch-selection button:disabled:checked > .label, popover.background.touch-selection button.destructive-action.osd popover.background.magnifier button:disabled:checked > .label, popover.background.magnifier button.destructive-action.osd button:disabled:checked > .label, + button.destructive-action:disabled:active > .label, + button.destructive-action:disabled:checked > .label, + button.destructive-action.osd popover.background.touch-selection button:disabled:active > .label, + popover.background.touch-selection button.destructive-action.osd button:disabled:active > .label, + button.destructive-action.osd popover.background.magnifier button:disabled:active > .label, + popover.background.magnifier button.destructive-action.osd button:disabled:active > .label, + button.destructive-action.osd popover.background.touch-selection button:disabled:checked > .label, + popover.background.touch-selection button.destructive-action.osd button:disabled:checked > .label, + button.destructive-action.osd popover.background.magnifier button:disabled:checked > .label, + popover.background.magnifier button.destructive-action.osd button:disabled:checked > .label, popover.background.touch-selection button.destructive-action.osd + button:disabled:active > .label, popover.background.magnifier button.destructive-action.osd + button:disabled:active > .label, popover.background.touch-selection button.destructive-action.osd + button:disabled:checked > .label, popover.background.magnifier button.destructive-action.osd + button:disabled:checked > .label, + button.destructive-action.osd + button:disabled:active > .label, + button.destructive-action.osd + button:disabled:checked > .label { + color: inherit; } +popover.background.touch-selection .stack-switcher > button > label, popover.background.magnifier .stack-switcher > button > label, .stack-switcher > +button > label { + padding-left: 6px; + padding-right: 6px; } +popover.background.touch-selection .stack-switcher > button > image, popover.background.magnifier .stack-switcher > button > image, .stack-switcher > +button > image { + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + padding-bottom: 3px; } +popover.background.touch-selection .stack-switcher > button.text-button, popover.background.magnifier .stack-switcher > button.text-button, .stack-switcher > +button.text-button { + padding: 6px; } +popover.background.touch-selection .stack-switcher > button.image-button, popover.background.magnifier .stack-switcher > button.image-button, .stack-switcher > +button.image-button { + padding: 3px 0px; } +popover.background.touch-selection .stack-switcher > button.needs-attention:active > label, popover.background.magnifier .stack-switcher > button.needs-attention:active > label, popover.background.touch-selection .stack-switcher > button.needs-attention:active > image, popover.background.magnifier .stack-switcher > button.needs-attention:active > image, popover.background.touch-selection .stack-switcher > button.needs-attention:checked > label, popover.background.magnifier .stack-switcher > button.needs-attention:checked > label, popover.background.touch-selection .stack-switcher > button.needs-attention:checked > image, popover.background.magnifier .stack-switcher > button.needs-attention:checked > image, .stack-switcher > +button.needs-attention:active > label, .stack-switcher > +button.needs-attention:active > image, .stack-switcher > +button.needs-attention:checked > label, .stack-switcher > +button.needs-attention:checked > image { + animation: none; + background-image: none; } +.inline-toolbar popover.background.touch-selection button, popover.background.touch-selection .inline-toolbar button, .inline-toolbar popover.background.magnifier button, popover.background.magnifier .inline-toolbar button, .inline-toolbar popover.background.touch-selection button:backdrop, popover.background.touch-selection .inline-toolbar button:backdrop, .inline-toolbar popover.background.magnifier button:backdrop, popover.background.magnifier .inline-toolbar button:backdrop, .inline-toolbar +button, .inline-toolbar +button:backdrop { + border-radius: 3px; + border-width: 1px; } +.primary-toolbar popover.background.touch-selection button, popover.background.touch-selection .primary-toolbar button, .primary-toolbar popover.background.magnifier button, popover.background.magnifier .primary-toolbar button, .primary-toolbar +button { + -gtk-icon-shadow: none; } + +/************** + * ComboBoxes * + **************/ +combobox arrow { + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); + min-height: 16px; + min-width: 16px; } + +popover.background.touch-selection .stack-switcher > button.needs-attention > label, popover.background.magnifier .stack-switcher > button.needs-attention > label, popover.background.touch-selection .stack-switcher > button.needs-attention > image, popover.background.magnifier .stack-switcher > button.needs-attention > image, .stack-switcher > +button.needs-attention > label, .stack-switcher > +button.needs-attention > image, stacksidebar.sidebar row.needs-attention > .label { + animation: needs_attention 150ms ease-in; + background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(#FF5F57), to(transparent)), -gtk-gradient(radial, center center, 0, center center, 0.5, to(white), to(transparent)); + background-size: 6px 6px, 6px 6px; + background-repeat: no-repeat; + background-position: right 3px, right 4px; } + .stack-switcher > + button.needs-attention > label:backdrop, .stack-switcher > + button.needs-attention > image:backdrop, stacksidebar.sidebar row.needs-attention > .label:backdrop { + background-size: 6px 6px, 0 0; } + .stack-switcher > + button.needs-attention > label:dir(rtl), .stack-switcher > + button.needs-attention > image:dir(rtl), stacksidebar.sidebar row.needs-attention > .label:dir(rtl) { + background-position: left 3px, left 4px; } + +.linked > combobox > box > button.combo:dir(ltr), .linked > combobox > box > button.combo:dir(rtl), .inline-toolbar popover.background.touch-selection button, popover.background.touch-selection .inline-toolbar button, .inline-toolbar popover.background.magnifier button, popover.background.magnifier .inline-toolbar button, .inline-toolbar +button, .inline-toolbar +button:backdrop, popover.background.touch-selection .linked > button, popover.background.magnifier .linked > button, .linked > +button, .linked > +button:hover, .linked > +button:active, .linked > +button:checked, .linked > +button:backdrop { + border-radius: 3px; } + .linked > combobox > box > button.combo:dir(rtl), .inline-toolbar popover.background.touch-selection button:dir(rtl), popover.background.touch-selection .inline-toolbar button:dir(rtl), .inline-toolbar popover.background.magnifier button:dir(rtl), popover.background.magnifier .inline-toolbar button:dir(rtl), .inline-toolbar + button:dir(rtl), popover.background.touch-selection .linked > button:dir(rtl), popover.background.magnifier .linked > button:dir(rtl), .linked > + button:dir(rtl) { + border-radius: 3px; } + +.inline-toolbar popover.background.touch-selection button, popover.background.touch-selection .inline-toolbar button, .inline-toolbar popover.background.magnifier button, popover.background.magnifier .inline-toolbar button, .inline-toolbar +button, .inline-toolbar +button:backdrop, popover.background.touch-selection .linked > button, popover.background.magnifier .linked > button, .linked > +button, .linked > +button:hover, .linked > +button:active, .linked > +button:checked, .linked > +button:backdrop { + margin-left: 2px; + margin-right: 2px; } + .inline-toolbar popover.background.touch-selection button:first-child, popover.background.touch-selection .inline-toolbar button:first-child, .inline-toolbar popover.background.magnifier button:first-child, popover.background.magnifier .inline-toolbar button:first-child, .inline-toolbar + button:first-child, popover.background.touch-selection .linked > button:first-child, popover.background.magnifier .linked > button:first-child, .linked > + button:first-child, combobox.linked button:nth-child(2):dir(rtl), .linked:not(.vertical) > combobox:first-child > box > button.combo { + border-radius: 3px; + border-style: solid; } + .inline-toolbar popover.background.touch-selection button:last-child, popover.background.touch-selection .inline-toolbar button:last-child, .inline-toolbar popover.background.magnifier button:last-child, popover.background.magnifier .inline-toolbar button:last-child, .inline-toolbar + button:last-child, popover.background.touch-selection .linked > button:last-child, popover.background.magnifier .linked > button:last-child, .linked > + button:last-child, combobox.linked button:nth-child(2):dir(ltr), .linked:not(.vertical) > combobox:last-child > box > button.combo { + border-radius: 3px; } + .inline-toolbar popover.background.touch-selection button:only-child, popover.background.touch-selection .inline-toolbar button:only-child, .inline-toolbar popover.background.magnifier button:only-child, popover.background.magnifier .inline-toolbar button:only-child, .inline-toolbar + button:only-child, popover.background.touch-selection .linked > button:only-child, popover.background.magnifier .linked > button:only-child, .linked > + button:only-child, .linked:not(.vertical) > combobox:only-child > box > button.combo { + border-radius: 3px; + border-style: solid; } + +.linked.vertical > combobox > box > button.combo, popover.background.touch-selection .linked.vertical > button, popover.background.magnifier .linked.vertical > button, .linked.vertical > +button, .linked.vertical > +button:hover, .linked.vertical > +button:active, .linked.vertical > +button:checked, .linked.vertical > +button:backdrop { + border-style: solid; + border-radius: 3px; } + +popover.background.touch-selection .linked.vertical > button:first-child, popover.background.magnifier .linked.vertical > button:first-child, .linked.vertical > +button:first-child, .linked.vertical > combobox:first-child > box > button.combo { + border-radius: 3px; } +popover.background.touch-selection .linked.vertical > button:last-child, popover.background.magnifier .linked.vertical > button:last-child, .linked.vertical > +button:last-child, .linked.vertical > combobox:last-child > box > button.combo { + border-radius: 3px; + border-style: solid; } +popover.background.touch-selection .linked.vertical > button:only-child, popover.background.magnifier .linked.vertical > button:only-child, .linked.vertical > +button:only-child, .linked.vertical > combobox:only-child > box > button.combo { + border-radius: 3px; + border-style: solid; } + +.app-notification button.flat, +.app-notification.frame button.flat, .app-notification button.flat:hover, +.app-notification.frame button.flat:hover, .app-notification button.flat:active, +.app-notification.frame button.flat:active, .app-notification button.flat:backdrop, .app-notification button.flat:disabled, .app-notification button.flat:backdrop:disabled, +.app-notification.frame button.flat:backdrop, +.app-notification.frame button.flat:disabled, +.app-notification.frame button.flat:backdrop:disabled, calendar.button, calendar.button:hover, calendar.button:active, calendar.button:backdrop, +headerbar button.flat:disabled, button:link, +button:visited, button:link:hover, button:link:active, button:link:checked, +button:visited:hover, +button:visited:active, +button:visited:checked, modelbutton.flat, popover.background checkbutton, +popover.background radiobutton, +.menuitem.button.flat, modelbutton.flat:backdrop, popover.background checkbutton:backdrop, +popover.background radiobutton:backdrop, modelbutton.flat:backdrop:hover, popover.background checkbutton:backdrop:hover, +popover.background radiobutton:backdrop:hover, +.menuitem.button.flat:backdrop, +.menuitem.button.flat:backdrop:hover, scrollbar button:backdrop, button.sidebar-button { + border-color: transparent; + background-color: transparent; + background-image: none; + box-shadow: none; + text-shadow: none; + -gtk-icon-shadow: none; } + +/**************** + * Text Entries * + ****************/ +spinbutton:not(.vertical), +entry { + min-height: 30px; + padding-left: 8px; + padding-right: 8px; + border: 1px solid; + border-radius: 3px; + transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); + color: white; + border-color: #5f6367; + background-color: #292f34; + box-shadow: none; } + spinbutton:not(.vertical) image.left, + entry image.left { + padding-left: 0; + padding-right: 6px; } + spinbutton:not(.vertical) image.right, + entry image.right { + padding-left: 6px; + padding-right: 0; } + spinbutton.flat:focus:not(.vertical), spinbutton.flat:not(.vertical), + entry.flat:focus, + entry.flat { + min-height: 0; + padding: 2px; + color: white; + border-color: #5f6367; + background-color: #292f34; + box-shadow: none; } + spinbutton:focus:not(.vertical), + entry:focus { + border-color: #FF5F57; } + spinbutton:disabled:not(.vertical), + entry:disabled { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(86, 90, 94, 0.35); + background-color: #252b2f; } + spinbutton:backdrop:not(.vertical), + entry:backdrop { + color: white; + border-color: #5f6367; + background-color: #292f34; } + spinbutton:backdrop:disabled:not(.vertical), + entry:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(86, 90, 94, 0.35); + background-color: #252b2f; } + spinbutton.error:not(.vertical), + entry.error { + color: #e74c3c; + border-color: #e74c3c; + background-color: rgba(231, 76, 60, 0.5); } + spinbutton.error:focus:not(.vertical), + entry.error:focus { + border-color: #e74c3c; + background-color: rgba(231, 76, 60, 0.5); } + spinbutton.error:selected:not(.vertical), spinbutton.error:selected:focus:not(.vertical), + entry.error:selected, + entry.error:selected:focus { + background-color: #e74c3c; } + spinbutton.error:backdrop:not(.vertical), + entry.error:backdrop { + color: #e74c3c; + border-color: #e74c3c; + background-color: rgba(231, 76, 60, 0.5); } + spinbutton.warning:not(.vertical), + entry.warning { + color: #e67e22; + border-color: #e67e22; + background-color: rgba(230, 126, 34, 0.5); } + spinbutton.warning:focus:not(.vertical), + entry.warning:focus { + border-color: #e67e22; + background-color: rgba(230, 126, 34, 0.5); } + spinbutton.warning:selected:not(.vertical), spinbutton.warning:selected:focus:not(.vertical), + entry.warning:selected, + entry.warning:selected:focus { + background-color: #e67e22; } + spinbutton.warning:backdrop:not(.vertical), + entry.warning:backdrop { + color: #e67e22; + border-color: #e67e22; + background-color: rgba(230, 126, 34, 0.5); } + spinbutton:not(.vertical) image, + entry image { + color: white; } + spinbutton:not(.vertical) image:hover, + entry image:hover { + color: #FF5F57; } + spinbutton:not(.vertical) image:active, + entry image:active { + color: #FF5F57; } + spinbutton:not(.vertical) image:backdrop, + entry image:backdrop { + color: white; } +spinbutton:not(.vertical) progress, +entry progress { + margin: 1px; + border-radius: 0; + border-width: 0 0 2px; + border-color: #FF5F57; + border-style: solid; + background-image: none; + background-color: transparent; + box-shadow: none; } + spinbutton:not(.vertical) progress:backdrop, + entry progress:backdrop { + background-color: transparent; + border-color: rgba(255, 95, 87, 0.5); } + +treeview acceleditor > label { + background-color: #FF5F57; } + +treeview entry.flat, treeview entry { + border-radius: 0; + background-image: none; + background-color: #292f34; } + treeview entry.flat:focus, treeview entry:focus { + border-color: #FF5F57; } + +/********************* + * App Notifications * + *********************/ +.app-notification, +.app-notification.frame { + padding: 10px; + border-top-width: 0px; + border-radius: 0px 0px 3px 3px; } + .app-notification:backdrop, + .app-notification.frame:backdrop { + background-image: none; } + .app-notification button, + .app-notification.frame button { + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); + text-shadow: none; + -gtk-icon-shadow: none; + color: white; + border-color: #5f6367; + background-image: linear-gradient(to bottom, #292f35, #282e32); } + .app-notification button.flat, + .app-notification.frame button.flat { + -gtk-icon-shadow: none; + text-shadow: none; } + .app-notification button.flat:hover, + .app-notification.frame button.flat:hover { + color: #FF5F57; } + .app-notification button.flat:active, + .app-notification.frame button.flat:active { + color: #FF5F57; } + .app-notification button:hover, + .app-notification.frame button:hover { + color: white; + border-color: #FF5F57; } + .app-notification button:active, .app-notification button:checked, .app-notification button:backdrop:active, .app-notification button:backdrop:checked, + .app-notification.frame button:active, + .app-notification.frame button:checked, + .app-notification.frame button:backdrop:active, + .app-notification.frame button:backdrop:checked { + color: white; + border-color: #FF5F57; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); } + .app-notification button:disabled, .app-notification button:backdrop:disabled, + .app-notification.frame button:disabled, + .app-notification.frame button:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(86, 90, 94, 0.35); + background-image: linear-gradient(to bottom, #262b30, #24292e); } + .app-notification button:disabled > .label, .app-notification button:backdrop:disabled > .label, + .app-notification.frame button:disabled > .label, + .app-notification.frame button:backdrop:disabled > .label { + color: inherit; } + .app-notification button:backdrop, + .app-notification.frame button:backdrop { + color: white; + border-color: #5f6367; + background-image: linear-gradient(to bottom, #292f35, #282e32); } + .app-notification border, + .app-notification.frame border { + border: none; } + +/************ + * Calendar * + ***********/ +calendar { + color: white; + border: 1px solid #5f6367; + background-color: #292f34; } + calendar:selected { + background-color: #5f6367; } + calendar.header { + border: 1px solid #5f6367; + border-radius: 0; + color: white; } + calendar.header:backdrop { + color: white; + border-color: #5f6367; } + calendar.button { + color: white; } + calendar.button:hover { + color: #FF5F57; } + calendar.button:active { + color: #FF5F57; } + calendar.button:backdrop { + color: white; } + calendar:indeterminate, calendar.highlight { + color: rgba(255, 255, 255, 0.5); } + calendar:indeterminate:backdrop, calendar.highlight:backdrop { + color: rgba(255, 255, 255, 0.5); } + calendar:backdrop { + color: white; + border-color: #5f6367; + background-color: #292f34; } + +/************************* + * Check and Radio items * + *************************/ +checkbutton.text-button, radiobutton.text-button { + padding: 2px 0; + outline-offset: 0; } + checkbutton.text-button label:not(:only-child):first-child, radiobutton.text-button label:not(:only-child):first-child { + margin-left: 4px; } + checkbutton.text-button label:not(:only-child):last-child, radiobutton.text-button label:not(:only-child):last-child { + margin-right: 4px; } + +check { + margin: 0 4px; + min-height: 18px; + min-width: 18px; + animation: none; + background-color: #FFFFFF; + color: #292f34 +} + +radio { + margin: 0 4px; + min-height: 18px; + min-width: 18px; + animation: none; + background-color: transparent; +} + +/***************** + * Color Chooser * + *****************/ +:selected colorswatch { + box-shadow: none; } + :selected colorswatch.overlay, :selected colorswatch.overlay:hover { + border-color: white; } +colorswatch:selected { + box-shadow: none; } +colorswatch.top, colorswatch.bottom, colorswatch.left, colorswatch:first-child:not(.overlay):not(.top), colorswatch.right, colorswatch:last-child:not(.overlay):not(.bottom), colorswatch:only-child:not(.overlay), colorswatch.top > .overlay, colorswatch.bottom > .overlay, colorswatch:first-child:not(.top) > .overlay, colorswatch:last-child:not(.bottom) > .overlay, colorswatch:only-child > .overlay { + border-radius: 3px; } +colorswatch:hover, colorswatch:hover:selected { + background-image: linear-gradient(135deg, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0) 50%); + box-shadow: inset 0 1px rgba(255, 255, 255, 0.4); } + colorswatch:hover.color-dark, colorswatch:hover:selected.color-dark { + background-image: linear-gradient(135deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 50%); } +colorswatch:backdrop, colorswatch:backdrop:selected +colorswatch.color-dark:backdrop, colorswatch.color-dark:backdrop:selected { + background-image: none; + box-shadow: none; } +GtkColorEditor colorswatch { + border-radius: 3px; } + GtkColorEditor colorswatch:hover { + background-image: none; + box-shadow: none; } + GtkColorEditor colorswatch:backdrop { + box-shadow: none; } +colorswatch.color-dark { + color: white; + outline-color: rgba(0, 0, 0, 0.3); } + colorswatch.color-dark:backdrop { + color: rgba(255, 255, 255, 0.3); } +colorswatch.color-light { + color: black; + outline-color: rgba(255, 255, 255, 0.5); } + colorswatch.color-light:backdrop { + color: rgba(0, 0, 0, 0.3); } +colorswatch overlay, +colorswatch overlay:selected { + border: 1px solid #5f6367; } + colorswatch overlay:hover, + colorswatch overlay:selected:hover { + border-color: #FF5F57; } +colorswatch#add-color-button { + border-style: solid; + border-width: 1px; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1); + text-shadow: none; + -gtk-icon-shadow: none; + color: white; + border-color: #5f6367; + background-image: linear-gradient(to bottom, #292f35, #282e32); } + colorswatch#add-color-button:hover { + color: white; + border-color: #FF5F57; } + colorswatch#add-color-button:backdrop { + color: white; + border-color: #5f6367; + background-image: linear-gradient(to bottom, #292f35, #282e32); } + colorswatch#add-color-button overlay { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; } + +GtkColorButton.button { + padding: 5px; } + GtkColorButton.button GtkColorSwatch:first-child:last-child { + border-radius: 0; + box-shadow: none; } + GtkColorButton.button GtkColorSwatch:first-child:last-child:disabled, GtkColorButton.button GtkColorSwatch:first-child:last-child:backdrop { + box-shadow: none; } + +/*********** + * Dialogs * + ***********/ +messagedialog.background { + background-color: #292f34; } +messagedialog:backdrop { + background-color: #292f34; } +messagedialog .titlebar { + min-height: 32px; + background-color: transparent; + background-image: linear-gradient(to bottom, #31383e, #292f34); + box-shadow: none; } +messagedialog .dialog-action-area { + padding: 8px; } +messagedialog button { + margin: 2px; } + +filechooser .search-bar { + background-color: #292f34; + border-color: #292f34; + box-shadow: none; } + filechooser .search-bar:backdrop { + background-color: #292f34; + border-color: #292f34; + color: white; } +filechooser .dialog-action-box { + border-top: 1px solid #5f6367; } + filechooser .dialog-action-box:backdrop { + border-top-color: #5f6367; } +filechooser #pathbarbox { + background-color: #292f34; + border-bottom: 1px solid #5f6367; } + +/*************** + * Header bars * + ***************/ +headerbar { + transition: none; + padding: 0px 6px; + border-width: 0px 0px 1px 0px; + border-radius: 3px 3px 0px 0px; + border-style: solid; + border-color: #FF5F57; + color: white; + background-image: linear-gradient(to bottom, #31383e, #292f34); } + headerbar:backdrop { + border-color: transparent; + background-image: none; + background-color: #292f34; + color: #828282; + box-shadow: none; } + headerbar label { + font-weight: normal; } + headerbar label:backdrop { + color: #828282; } + headerbar .path-bar button { + color: white; + font-weight: normal; } + headerbar .path-bar button:backdrop { + color: #828282; } + headerbar button { + transition: none; + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; } + headerbar button.flat { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; } + headerbar button:hover { + color: white; + border-color: #FF5F57; } + headerbar button:hover:backdrop { + border-color: #292f34; } + headerbar button:active, + headerbar button:checked { + color: white; + border-color: #FF5F57; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); } + headerbar button:active:hover, + headerbar button:checked:hover { + color: white; + border-color: #FF5F57; + background-image: linear-gradient(to bottom, #FF5F57, #FF5F57); } + headerbar button:active:backdrop, + headerbar button:checked:backdrop { + background-image: none; + background-color: #292f34; + border-color: #292f34; + color: #828282; } + headerbar button:backdrop { + border-color: transparent; + background-image: none; + background-color: #292f34; + color: #828282; } + headerbar button.flat:backdrop, + headerbar button.flat:backdrop:disabled, + headerbar button:disabled:backdrop { + background-image: none; + background-color: #292f34; + color: #828282; + border-color: transparent; } + headerbar button.flat:disabled { + color: rgba(232, 232, 232, 0.35); } + headerbar button:disabled { + background-color: transparent; + background-image: none; + border-color: transparent; + color: rgba(232, 232, 232, 0.35); } + headerbar button:disabled:active, + headerbar button:disabled:checked { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(24, 171, 142, 0.35); + background-image: linear-gradient(to bottom, rgba(255, 95, 87, 0.35), rgba(255, 95, 87, 0.35)); } + headerbar button:disabled:active > .label, + headerbar button:disabled:checked > .label { + color: inherit; } + headerbar .title { + font-weight: normal; + padding: 0px 12px; } + headerbar .title:backdrop { + color: #828282; } + headerbar .subtitle { + font-size: smaller; + padding: 0 12px; } + headerbar .subtitle:backdrop { + color: #828282; } + headerbar separator { + border-width: 0px; + background-color: transparent; + background-image: none; + border-color: transparent; } + headerbar.selection-mode .selection-menu { + padding: 4px 6px; } + headerbar.selection-mode .selection-menu GtkArrow { + -GtkArrow-arrow-scaling: 1; } + headerbar.selection-mode .selection-menu .arrow { + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); + -gtk-icon-shadow: none; } + .tiled + headerbar, .maximized + headerbar { + border-radius: 0; } + +headerbar entry, +headerbar spinbutton, +headerbar separator, +headerbar button { + margin-top: 3px; + margin-bottom: 3px; } + +headerbar button.suggested-action, +headerbar.selection-mode.suggested-action { + background-image: none; + background-color: #FF5F57; } + headerbar button.suggested-action:hover, + headerbar.selection-mode.suggested-action:hover { + background-color: #FF5F57; + color: white; } + headerbar button.suggested-action:disabled, + headerbar.selection-mode.suggested-action:disabled { + background-color: transparent; + background-image: none; + color: rgba(232, 232, 232, 0.35); } + headerbar button.suggested-action:disabled:active, + headerbar.selection-mode.suggested-action:disabled:active, + headerbar button.suggested-action:disabled:checked, + headerbar.selection-mode.suggested-action:disabled:checked { + color: rgba(232, 232, 232, 0.35); + border-color: rgba(24, 171, 142, 0.35); + background-image: linear-gradient(to bottom, rgba(255, 95, 87, 0.35), rgba(255, 95, 87, 0.35)); } + headerbar button.suggested-action:disabled:active > .label, + headerbar.selection-mode.suggested-action:disabled:active > .label, + headerbar button.suggested-action:disabled:checked > .label, + headerbar.selection-mode.suggested-action:disabled:checked > .label { + color: inherit; } + headerbar button.suggested-action:backdrop, + headerbar.selection-mode.suggested-action:backdrop { + background-color: #292f34; + border-color: transparent; + color: #828282; } + headerbar button.suggested-action:backdrop:disabled, + headerbar.selection-mode.suggested-action:backdrop:disabled { + color: rgba(118, 118, 118, 0.35); } + +/************** + * GtkInfoBar * + **************/ +infobar { + border-style: none; + border-bottom: 1px solid #5f6367; + background-color: #292f34; + background-image: none; } + infobar:backdrop { + border-bottom: 1px solid #5f6367; } + +.info, +headerbar.selection-mode, +.question, +.warning, +.error { + background-color: #292f34; + background-image: none; + color: #e67e22; + text-shadow: none; } + .info:backdrop, + headerbar.selection-mode:backdrop, + .question:backdrop, + .warning:backdrop, + .error:backdrop { + background-color: #292f34; + color: #e67e22; } + .info button, + headerbar.selection-mode button, + .question button, + .warning button, + .error button { + box-shadow: none; + background-image: none; + background-color: rgba(230, 126, 34, 0.5); + border-color: rgba(230, 126, 34, 0.5); + color: white; } + .info button:hover, + headerbar.selection-mode button:hover, + .question button:hover, + .warning button:hover, + .error button:hover { + background-color: rgba(230, 126, 34, 0.25); + border-color: #e67e22; } + .info button:active, + headerbar.selection-mode button:active, .info button:checked, + headerbar.selection-mode button:checked, + .question button:active, + .question button:checked, + .warning button:active, + .warning button:checked, + .error button:active, + .error button:checked { + background-image: linear-gradient(to bottom, #e67f24, #e57a1b); + color: #292f34; + border-color: #e67e22; } + .info button:disabled, + headerbar.selection-mode button:disabled, + .question button:disabled, + .warning button:disabled, + .error button:disabled { + background-color: rgba(216, 114, 24, 0); + border-color: rgba(216, 114, 24, 0); + color: rgba(232, 232, 232, 0.35); } + .info button:backdrop, + headerbar.selection-mode button:backdrop, + .question button:backdrop, + .warning button:backdrop, + .error button:backdrop { + background-color: rgba(230, 126, 34, 0.5); + border-color: rgba(230, 126, 34, 0.5); + color: white; } + .info button:backdrop:active, + headerbar.selection-mode button:backdrop:active, .info button:backdrop:checked, + headerbar.selection-mode button:backdrop:checked, + .question button:backdrop:active, + .question button:backdrop:checked, + .warning button:backdrop:active, + .warning button:backdrop:checked, + .error button:backdrop:active, + .error button:backdrop:checked { + background-image: linear-gradient(to bottom, #e67f24, #e57a1b); + color: #292f34; + border-color: #e67e22; } + .info button:backdrop:disabled, + headerbar.selection-mode button:backdrop:disabled, + .question button:backdrop:disabled, + .warning button:backdrop:disabled, + .error button:backdrop:disabled { + background-color: rgba(216, 114, 24, 0); + border-color: rgba(216, 114, 24, 0); + color: rgba(232, 232, 232, 0.35); } + .info button:backdrop:disabled:active, + headerbar.selection-mode button:backdrop:disabled:active, .info button:backdrop:disabled:checked, + headerbar.selection-mode button:backdrop:disabled:checked, + .question button:backdrop:disabled:active, + .question button:backdrop:disabled:checked, + .warning button:backdrop:disabled:active, + .warning button:backdrop:disabled:checked, + .error button:backdrop:disabled:active, + .error button:backdrop:disabled:checked { + background-image: linear-gradient(to bottom, rgba(218, 115, 25, 0.35), rgba(209, 111, 24, 0.35)); + color: #252b2f; + border-color: rgba(216, 114, 24, 0.35); } + +/********* + * Links * + *********/ +button:link > label, +button:visited > label, +*:link, +button:link, +button:visited { + color: #4c6b8a; } + button:link > label:visited, + button:visited > label:visited, + *:link:visited, + button:visited { + color: #913d88; } + *:selected button:link > label:visited, + *:selected button:visited > label:visited, *:selected + *:link:visited, *:selected + button:visited:link, + *:selected button:visited { + color: #a3e4d7; } + button:link > label:hover, + button:visited > label:hover, + *:link:hover, + button:hover:link, + button:hover:visited { + color: #6185a8; } + *:selected button:link > label:hover, + *:selected button:visited > label:hover, *:selected + *:link:hover, *:selected + button:hover:link, + *:selected button:hover:visited { + color: #e8f8f5; } + button:link > label:active, + button:visited > label:active, + *:link:active, + button:active:link, + button:active:visited { + color: #4c6b8a; } + *:selected button:link > label:active, + *:selected button:visited > label:active, *:selected + *:link:active, *:selected + button:active:link, + *:selected button:active:visited { + color: #d1f2eb; } + button:link > label:backdrop, + button:visited > label:backdrop, button:link > label:backdrop:hover, + button:visited > label:backdrop:hover, button:link > label:backdrop:hover:selected, + button:visited > label:backdrop:hover:selected, + *:link:backdrop, + button:backdrop:link, + button:backdrop:visited, + *:link:backdrop:hover, + button:backdrop:hover:link, + button:backdrop:hover:visited, + *:link:backdrop:hover:selected, + headerbar.selection-mode .subtitle:backdrop:hover:link, + button:backdrop:hover:selected:link, + button:backdrop:hover:selected:visited { + color: rgba(255, 95, 87, 0.5); } + button:link > label:selected, + button:visited > label:selected, *:selected button:link > label, + *:selected button:visited > label, + *:link:selected, + headerbar.selection-mode .subtitle:link, + button:selected:link, + button:selected:visited, *:selected + *:link, *:selected + button:link, + *:selected button:visited { + color: #d1f2eb; } + +button:link, +button:visited { + text-shadow: none; } + button:link:hover, button:link:active, button:link:checked, + button:visited:hover, + button:visited:active, + button:visited:checked { + text-shadow: none; } + button:link > label, + button:visited > label { + text-decoration-line: underline; } + +/********* + * Lists * + *********/ +list { + background-color: #292f34; + color: white; + border-width: 0px; } + list:backdrop { + background-color: #292f34; + color: white; } + list row { + padding: 2px; } + +row { + transition: all 150ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } + row:hover { + transition: none; } + row.activatable.has-open-popup, row.activatable:hover { + background-color: rgba(255, 95, 87, 0.5); } + row.activatable:active { + box-shadow: none; + background-color: #FF5F57; } + row.activatable:selected:active { + box-shadow: none; + background-color: #FF5F57; } + row.activatable:selected.has-open-popup, row.activatable:selected:hover { + color: white; + background-color: #FF5F57; } + row.activatable:selected:backdrop { + background-color: #FF5F57; } + +/********* + * Menus * + *********/ +menubar, +.menubar { + -GtkWidget-window-dragging: true; + padding: 0px; + box-shadow: none; + border-style: none; + background-color: #292f34; } + menubar:backdrop, + .menubar:backdrop { + background-color: #292f34; } + menubar > menuitem, + .menubar > menuitem { + min-height: 16px; + padding: 4px 6px; + border-style: solid; + border-width: 1px 0px; + border-color: #292f34; } + menubar > menuitem:hover, + .menubar > menuitem:hover { + background-color: #FF5F57; + color: white; } + menubar > menuitem:disabled, + .menubar > menuitem:disabled { + color: rgba(232, 232, 232, 0.35); + box-shadow: none; } + menubar > menuitem:disabled:backdrop, + .menubar > menuitem:disabled:backdrop { + background-color: #292f34; + color: rgba(232, 232, 232, 0.35); } + menubar > menuitem:backdrop, + .menubar > menuitem:backdrop { + background-color: #292f34; + border-color: #292f34; + color: white; } + +menu, +.menu { + padding: 0px; + background-color: #292f34; + border: 0px solid transparent; + box-shadow: inset 0px 0px 0px 1px #5f6367; + border-radius: 3px; } + .csd menu, .csd + .menu { + border: 0px solid; + border-radius: 3px; } + menu separator, + .menu separator { + color: #5f6367; + margin-top: 3px; + margin-bottom: 3px; } + menu menuitem, + .menu menuitem { + text-shadow: none; + min-height: 16px; + min-width: 40px; + padding: 4px 4px; } + menu menuitem:hover, + .menu menuitem:hover { + color: white; + background-color: #FF5F57; } + menu menuitem:disabled, + .menu menuitem:disabled { + color: rgba(232, 232, 232, 0.35); } + menu menuitem:disabled:backdrop, + .menu menuitem:disabled:backdrop { + color: rgba(232, 232, 232, 0.35); } + menu menuitem:backdrop, menu menuitem:backdrop:hover, + .menu menuitem:backdrop, + .menu menuitem:backdrop:hover { + color: white; + background-color: #292f34; } + menu menuitem arrow, + .menu menuitem arrow { + min-height: 16px; + min-width: 16px; } + menu menuitem arrow:dir(ltr), + .menu menuitem arrow:dir(ltr) { + -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); + margin-left: 10px; } + menu menuitem arrow:dir(rtl), + .menu menuitem arrow:dir(rtl) { + -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); + margin-right: 10px; } + menu > arrow, + .menu > arrow { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + min-height: 16px; + min-width: 16px; + padding: 4px; + background-color: transparent; + border-radius: 0; } + menu > arrow.top, + .menu > arrow.top { + margin-top: -6px; + border: none; + -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + menu > arrow.bottom, + .menu > arrow.bottom { + margin-bottom: -6px; + border: none; + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + menu > arrow:hover, + .menu > arrow:hover { + color: #FF5F57; } + menu > arrow:active, + .menu > arrow:active { + color: #FF5F57; } + menu > arrow:backdrop, + .menu > arrow:backdrop { + background-color: #292f34; } + menu > arrow:disabled, + .menu > arrow:disabled { + color: transparent; + background-color: transparent; + border-color: transparent; } + +menuitem accelerator { + color: alpha(currentColor,0.55); } +menuitem check, +menuitem radio { + min-height: 18px; + min-width: 18px; } + menuitem check:dir(ltr), + menuitem radio:dir(ltr) { + margin-right: 6px; } + menuitem check:dir(rtl), + menuitem radio:dir(rtl) { + margin-left: 6px; } + +/*************** + * Popovers * + ***************/ +/* menu buttons */ +modelbutton.flat, popover.background checkbutton, +popover.background radiobutton, +.menuitem.button.flat { + min-height: 16px; + padding: 4px 8px; + color: white; } + modelbutton.flat:hover, popover.background checkbutton:hover, + popover.background radiobutton:hover, + .menuitem.button.flat:hover { + background-color: #FF5F57; + color: white; } + modelbutton.flat:selected, popover.background checkbutton:selected, + popover.background radiobutton:selected, + .menuitem.button.flat:selected { + background-color: #FF5F57; + color: white; } + modelbutton.flat:backdrop, popover.background checkbutton:backdrop, + popover.background radiobutton:backdrop, modelbutton.flat:backdrop:hover, popover.background checkbutton:backdrop:hover, + popover.background radiobutton:backdrop:hover, + .menuitem.button.flat:backdrop, + .menuitem.button.flat:backdrop:hover { + color: white; } + modelbutton.flat check:hover, popover.background checkbutton check:hover, + popover.background radiobutton check:hover, + modelbutton.flat radio:hover, popover.background checkbutton radio:hover, + popover.background radiobutton radio:hover, + modelbutton.flat check:checked:hover, popover.background checkbutton check:checked:hover, + popover.background radiobutton check:checked:hover, + modelbutton.flat radio:checked:hover, popover.background checkbutton radio:checked:hover, + popover.background radiobutton radio:checked:hover, + modelbutton.flat check:indeterminate:hover, popover.background checkbutton check:indeterminate:hover, + popover.background radiobutton check:indeterminate:hover, + modelbutton.flat radio:indeterminate:hover, popover.background checkbutton radio:indeterminate:hover, + popover.background radiobutton radio:indeterminate:hover, + modelbutton.flat check:last-child, popover.background checkbutton check:last-child, + popover.background radiobutton check:last-child, + modelbutton.flat radio:last-child, + popover.background checkbutton radio:last-child, + popover.background radiobutton radio:last-child, + .menuitem.button.flat check:last-child, + .menuitem.button.flat radio:last-child { + margin-right: 0px; } + modelbutton.flat check:first-child, popover.background checkbutton check:first-child, + popover.background radiobutton check:first-child, + modelbutton.flat radio:first-child, + popover.background checkbutton radio:first-child, + popover.background radiobutton radio:first-child, + .menuitem.button.flat check:first-child, + .menuitem.button.flat radio:first-child { + margin-left: 0px; } + +modelbutton.flat arrow, popover.background checkbutton arrow, +popover.background radiobutton arrow { + background: none; } + modelbutton.flat arrow:hover, popover.background checkbutton arrow:hover, + popover.background radiobutton arrow:hover { + background: none; } + modelbutton.flat arrow.left, popover.background checkbutton arrow.left, + popover.background radiobutton arrow.left { + -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + modelbutton.flat arrow.right, popover.background checkbutton arrow.right, + popover.background radiobutton arrow.right { + -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + +popover.background { + margin: -10px; + padding: 0px; + border: 1px solid #5f6367; + border-radius: 3px; + background-color: #292f34; + box-shadow: 0 2px 3px rgba(0, 0, 0, 0.9); } + popover.background:backdrop { + box-shadow: none; } + popover.background > list, + popover.background > .view, + popover.background > toolbar { + border-style: none; + background-color: transparent; } + .csd popover.background.touch-selection, .csd popover.background.magnifier, popover.background.touch-selection, popover.background.magnifier { + border: 1px solid #5f6367; } + popover.background separator { + margin: 3px; } + popover.background list separator { + margin: 0px; } + +GtkVolumeButton.button { + padding: 5px; } + +/******** + * Misc * + ********/ +/**************** +* Print dialog * +*****************/ +printdialog paper { + color: white; + border: 1px solid #5f6367; + background: white; + padding: 0; } + printdialog paper:backdrop { + color: white; + border-color: #5f6367; + background: white; } +printdialog .dialog-action-box { + margin: 12px; } + +/********** +* Frames * +**********/ +frame > border, +.frame { + box-shadow: none; + margin: 0; + padding: 0; + border-radius: 0; + border: 1px solid #5f6367; } + frame > border.flat, + .frame.flat { + border-style: none; } + frame > border:backdrop, + .frame:backdrop { + border-color: #5f6367; } + +actionbar > revealer > box { + padding: 6px; + border-top: 1px solid #5f6367; } + actionbar > revealer > box:backdrop { + border-color: #5f6367; } + +scrolledwindow viewport.frame { + border-style: none; } +scrolledwindow junction { + border-color: transparent; + background-color: transparent; + background-image: none; } + +separator { + background: #5f6367; + min-width: 1px; + min-height: 1px; } + +/************* +* Expanders * +*************/ +expander arrow { + min-width: 16px; + min-height: 16px; + -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + expander arrow:dir(rtl) { + -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + expander arrow:hover { + color: white; } + expander arrow:checked { + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + +/********* +* Paned * +*********/ +paned > separator { + min-width: 1px; + min-height: 1px; + -gtk-icon-source: none; + border-style: none; + background-color: transparent; + background-image: image(#5f6367); + background-size: 1px 1px; } + paned > separator:backdrop { + background-image: image(#5f6367); } + paned > separator.wide { + min-width: 5px; + min-height: 5px; + background-color: #292f34; + background-image: image(#5f6367), image(#5f6367); + background-size: 1px 1px, 1px 1px; } + paned > separator.wide:backdrop { + background-color: #292f34; + background-image: image(#5f6367), image(#5f6367); } +paned.horizontal > separator { + background-repeat: repeat-y; } + paned.horizontal > separator:dir(ltr) { + margin: 0 -8px 0 0; + padding: 0 8px 0 0; + background-position: left; } + paned.horizontal > separator:dir(rtl) { + margin: 0 0 0 -8px; + padding: 0 0 0 8px; + background-position: right; } + paned.horizontal > separator.wide { + margin: 0; + padding: 0; + background-repeat: repeat-y, repeat-y; + background-position: left, right; } +paned.vertical > separator { + margin: 0 0 -8px 0; + padding: 0 0 8px 0; + background-repeat: repeat-x; + background-position: top; } + paned.vertical > separator.wide { + margin: 0; + padding: 0; + background-repeat: repeat-x, repeat-x; + background-position: bottom, top; } + +/********************* +* Spinner Animation * +*********************/ +@keyframes spin { + to { + -gtk-icon-transform: rotate(1turn); } } +spinner { + background-image: none; + opacity: 0; + -gtk-icon-source: -gtk-icontheme("process-working-symbolic"); } + spinner:checked { + opacity: 1; + animation: spin 1s linear infinite; } + spinner:checked:disabled { + opacity: 0.5; } + +/***************** + * Notebooks and * + * Tabs * + *****************/ +/************* + * Notebooks * + *************/ +notebook.frame { + border: none; + padding: 0px; + box-shadow: inset 0px 0px 0px 1px #5f6367; } +notebook > header { + padding: 0px; + border: none; + background-color: #292f34; } + notebook > header.top { + box-shadow: inset 0 -1px #5f6367; } + notebook > header.top:backdrop { + box-shadow: inset 0 -1px #5f6367; } + notebook > header.bottom { + box-shadow: inset 0 1px #5f6367; } + notebook > header.bottom:backdrop { + box-shadow: inset 0 1px #5f6367; } + notebook > header.right { + box-shadow: inset 1px 0 #5f6367; } + notebook > header.right:backdrop { + box-shadow: inset 1px 0 #5f6367; } + notebook > header.left { + box-shadow: inset -1px 0 #5f6367; } + notebook > header.left:backdrop { + box-shadow: inset -1px 0 #5f6367; } + notebook > header:backdrop { + background-color: #292f34; } + notebook > header tabs { + margin: 0px; } + notebook > header.top > tabs > tab { + padding: 4px 6px; + border: 1px solid rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0.2); + border-radius: 3px 3px 0px 0px; + border-bottom-color: transparent; } + notebook > header.top > tabs > tab:hover, notebook > header.top > tabs > tab.prelight-page { + background-color: rgba(255, 95, 87, 0.2); + border-color: rgba(255, 95, 87, 0.2); } + notebook > header.top > tabs > tab:checked { + border-color: #5f6367; + border-bottom-color: #292f34; + background-color: #292f34; } + notebook > header.top > tabs > tab:checked:backdrop { + border-color: #5f6367; + border-bottom-color: #292f34; + background-color: #292f34; } + notebook > header.bottom > tabs > tab { + padding: 4px 6px; + border: 1px solid rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0.2); + border-radius: 0px 0px 3px 3px; + border-top-color: transparent; } + notebook > header.bottom > tabs > tab:hover, notebook > header.bottom > tabs > tab.prelight-page { + background-color: rgba(255, 95, 87, 0.2); + border-color: rgba(255, 95, 87, 0.2); } + notebook > header.bottom > tabs > tab:checked { + border-color: #5f6367; + border-top-color: #292f34; + background-color: #292f34; } + notebook > header.bottom > tabs > tab:checked:backdrop { + border-color: #5f6367; + border-top-color: #292f34; + background-color: #292f34; } + notebook > header.left > tabs > tab { + padding: 4px 6px; + border: 1px solid rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0.2); + border-radius: 3px 0px 0px 3px; + border-right-color: transparent; } + notebook > header.left > tabs > tab:hover, notebook > header.left > tabs > tab.prelight-page { + background-color: rgba(255, 95, 87, 0.2); + border-color: rgba(255, 95, 87, 0.2); } + notebook > header.left > tabs > tab:checked { + border-color: #5f6367; + border-right-color: #292f34; + background-color: #292f34; } + notebook > header.left > tabs > tab:checked:backdrop { + border-color: #5f6367; + border-right-color: #292f34; + background-color: #292f34; } + notebook > header.right > tabs > tab { + padding: 4px 6px; + border: 1px solid rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0.2); + border-radius: 0px 3px 3px 0px; + border-left-color: transparent; } + notebook > header.right > tabs > tab:hover, notebook > header.right > tabs > tab.prelight-page { + background-color: rgba(255, 95, 87, 0.2); + border-color: rgba(255, 95, 87, 0.2); } + notebook > header.right > tabs > tab:checked { + border-color: #5f6367; + border-left-color: #292f34; + background-color: #292f34; } + notebook > header.right > tabs > tab:checked:backdrop { + border-color: #5f6367; + border-left-color: #292f34; + background-color: #292f34; } + notebook > header.top > tabs > tab.reorderable-page { + border-width: 3px; + border-style: solid; + border-color: transparent; + background-color: #292f34; + background-clip: padding-box; + border-right-width: 1px; + border-right-color: #5f6367; + box-shadow: inset -3px 0px 0px 0px #292f34; } + notebook > header.top > tabs > tab.reorderable-page:hover, notebook > header.top > tabs > tab.reorderable-page.prelight-page { + box-shadow: inset 0px -3px 0px 0px rgba(255, 95, 87, 0.2), inset -3px 0px 0px 0px #292f34; } + notebook > header.top > tabs > tab.reorderable-page:checked { + box-shadow: inset 0px -3px 0px 0px #FF5F57, inset -3px 0px 0px 0px #292f34; } + notebook > header.top > tabs > tab.reorderable-page:checked:backdrop { + background-color: #292f34; + border-color: transparent; + border-right-color: #5f6367; + box-shadow: none; } + notebook > header.top > tabs > tab.reorderable-page:backdrop { + background-color: #292f34; + border-right-color: #5f6367; + box-shadow: none; } + notebook > header.bottom > tabs > tab.reorderable-page { + border-width: 3px; + border-style: solid; + border-color: transparent; + background-color: #292f34; + background-clip: padding-box; + border-right-width: 1px; + border-right-color: #5f6367; + box-shadow: inset -3px 0px 0px 0px #292f34; } + notebook > header.bottom > tabs > tab.reorderable-page:hover, notebook > header.bottom > tabs > tab.reorderable-page.prelight-page { + box-shadow: inset 0px -3px 0px 0px rgba(255, 95, 87, 0.2), inset -3px 0px 0px 0px #292f34; } + notebook > header.bottom > tabs > tab.reorderable-page:checked { + box-shadow: inset 0px -3px 0px 0px #FF5F57, inset -3px 0px 0px 0px #292f34; } + notebook > header.bottom > tabs > tab.reorderable-page:checked:backdrop { + background-color: #292f34; + border-color: transparent; + border-right-color: #5f6367; + box-shadow: none; } + notebook > header.bottom > tabs > tab.reorderable-page:backdrop { + background-color: #292f34; + border-right-color: #5f6367; + box-shadow: none; } + notebook > header.left > tabs > tab.reorderable-page { + border-width: 3px; + border-style: solid; + border-color: transparent; + background-color: #292f34; + background-clip: padding-box; + border-bottom-width: 1px; + border-bottom-color: #5f6367; + box-shadow: inset 0px -3px 0px 0px #292f34; } + notebook > header.left > tabs > tab.reorderable-page:hover, notebook > header.left > tabs > tab.reorderable-page.prelight-page { + box-shadow: inset 0px -3px 0px 0px rgba(255, 95, 87, 0.2), inset 0px -3px 0px 0px #292f34; } + notebook > header.left > tabs > tab.reorderable-page:checked { + box-shadow: inset 0px -3px 0px 0px #FF5F57, inset 0px -3px 0px 0px #292f34; } + notebook > header.left > tabs > tab.reorderable-page:checked:backdrop { + background-color: #292f34; + border-color: transparent; + border-bottom-color: #5f6367; + box-shadow: none; } + notebook > header.left > tabs > tab.reorderable-page:backdrop { + background-color: #292f34; + border-bottom-color: #5f6367; + box-shadow: none; } + notebook > header.right > tabs > tab.reorderable-page { + border-width: 3px; + border-style: solid; + border-color: transparent; + background-color: #292f34; + background-clip: padding-box; + border-bottom-width: 1px; + border-bottom-color: #5f6367; + box-shadow: inset 0px -3px 0px 0px #292f34; } + notebook > header.right > tabs > tab.reorderable-page:hover, notebook > header.right > tabs > tab.reorderable-page.prelight-page { + box-shadow: inset 0px -3px 0px 0px rgba(255, 95, 87, 0.2), inset 0px -3px 0px 0px #292f34; } + notebook > header.right > tabs > tab.reorderable-page:checked { + box-shadow: inset 0px -3px 0px 0px #FF5F57, inset 0px -3px 0px 0px #292f34; } + notebook > header.right > tabs > tab.reorderable-page:checked:backdrop { + background-color: #292f34; + border-color: transparent; + border-bottom-color: #5f6367; + box-shadow: none; } + notebook > header.right > tabs > tab.reorderable-page:backdrop { + background-color: #292f34; + border-bottom-color: #5f6367; + box-shadow: none; } + notebook > header.top > tabs > arrow { + border-top-style: none; } + notebook > header.bottom > tabs > arrow { + border-bottom-style: none; } + notebook > header.top > tabs > arrow, notebook > header.bottom > tabs > arrow { + margin-left: -5px; + margin-right: -5px; + padding-left: 4px; + padding-right: 4px; } + notebook > header.top > tabs > arrow.down, notebook > header.bottom > tabs > arrow.down { + -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + notebook > header.top > tabs > arrow.up, notebook > header.bottom > tabs > arrow.up { + -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + notebook > header.left > tabs > arrow { + border-left-style: none; } + notebook > header.right > tabs > arrow { + border-right-style: none; } + notebook > header.left > tabs > arrow, notebook > header.right > tabs > arrow { + margin-top: -5px; + margin-bottom: -5px; + padding-top: 4px; + padding-bottom: 4px; } + notebook > header.left > tabs > arrow.down, notebook > header.right > tabs > arrow.down { + -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + notebook > header.left > tabs > arrow.up, notebook > header.right > tabs > arrow.up { + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + notebook > header > tabs > arrow { + min-height: 16px; + min-width: 16px; + border-radius: 0; } + notebook > header > tabs > arrow:hover:not(:active):not(:backdrop) { + background-clip: padding-box; + background-image: none; + background-color: rgba(255, 255, 255, 0.3); + border-color: transparent; + box-shadow: none; } + notebook > header > tabs > arrow:disabled { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; } + notebook > header button.flat { + padding: 0; + margin: 4px; + min-width: 12px; + min-height: 12px; + border: 0px solid; + border-radius: 50%; + color: #292f34; + background-color: #5f6367; + background-image: none; } + notebook > header button.flat:hover { + background-color: #e74c3c; } + notebook > header button.flat:active { + background-color: #e74c3c; } + notebook > header button.flat:backdrop { + background-color: #5f6367; + color: #292f34; } +notebook > stack:not(:only-child) { + background-color: transparent; + border-style: solid; + border-color: #5f6367; + border-width: 0px; } + +scrolledwindow overshoot.top { + background-image: -gtk-gradient(radial, center top, 0, center top, 0.5, to(#474a4c), to(rgba(71, 74, 76, 0))), -gtk-gradient(radial, center top, 0, center top, 0.6, from(rgba(255, 255, 255, 0.07)), to(rgba(255, 255, 255, 0))); + background-size: 100% 5%, 100% 100%; + background-repeat: no-repeat; + background-position: center top; + background-color: transparent; + border: none; + box-shadow: none; } + scrolledwindow overshoot.top:backdrop { + background-image: -gtk-gradient(radial, center top, 0, center top, 0.5, to(#5f6367), to(rgba(95, 99, 103, 0))); + background-size: 100% 5%; + background-repeat: no-repeat; + background-position: center top; + background-color: transparent; + border: none; + box-shadow: none; } +scrolledwindow overshoot.bottom { + background-image: -gtk-gradient(radial, center bottom, 0, center bottom, 0.5, to(#474a4c), to(rgba(71, 74, 76, 0))), -gtk-gradient(radial, center bottom, 0, center bottom, 0.6, from(rgba(255, 255, 255, 0.07)), to(rgba(255, 255, 255, 0))); + background-size: 100% 5%, 100% 100%; + background-repeat: no-repeat; + background-position: center bottom; + background-color: transparent; + border: none; + box-shadow: none; } + scrolledwindow overshoot.bottom:backdrop { + background-image: -gtk-gradient(radial, center bottom, 0, center bottom, 0.5, to(#5f6367), to(rgba(95, 99, 103, 0))); + background-size: 100% 5%; + background-repeat: no-repeat; + background-position: center bottom; + background-color: transparent; + border: none; + box-shadow: none; } +scrolledwindow overshoot.left { + background-image: -gtk-gradient(radial, left center, 0, left center, 0.5, to(#474a4c), to(rgba(71, 74, 76, 0))), -gtk-gradient(radial, left center, 0, left center, 0.6, from(rgba(255, 255, 255, 0.07)), to(rgba(255, 255, 255, 0))); + background-size: 5% 100%, 100% 100%; + background-repeat: no-repeat; + background-position: left center; + background-color: transparent; + border: none; + box-shadow: none; } + scrolledwindow overshoot.left:backdrop { + background-image: -gtk-gradient(radial, left center, 0, left center, 0.5, to(#5f6367), to(rgba(95, 99, 103, 0))); + background-size: 5% 100%; + background-repeat: no-repeat; + background-position: left center; + background-color: transparent; + border: none; + box-shadow: none; } +scrolledwindow overshoot.right { + background-image: -gtk-gradient(radial, right center, 0, right center, 0.5, to(#474a4c), to(rgba(71, 74, 76, 0))), -gtk-gradient(radial, right center, 0, right center, 0.6, from(rgba(255, 255, 255, 0.07)), to(rgba(255, 255, 255, 0))); + background-size: 5% 100%, 100% 100%; + background-repeat: no-repeat; + background-position: right center; + background-color: transparent; + border: none; + box-shadow: none; } + scrolledwindow overshoot.right:backdrop { + background-image: -gtk-gradient(radial, right center, 0, right center, 0.5, to(#5f6367), to(rgba(95, 99, 103, 0))); + background-size: 5% 100%; + background-repeat: no-repeat; + background-position: right center; + background-color: transparent; + border: none; + box-shadow: none; } +scrolledwindow undershoot { + background-image: none; + border: none; } + +/************ + * Pathbars * + ************/ +.path-bar { + background-color: #292f34; + border-bottom: 1px solid #5f6367; } + +.path-bar button { + border-color: rgba(255, 255, 255, 0); + background-color: transparent; + background-image: none; + box-shadow: none; + color: white; + text-shadow: none; + -gtk-icon-shadow: none; + padding: 4px 8px; + color: white; } + .path-bar button:hover { + border-color: #FF5F57; } + .path-bar button:active, .path-bar button:checked { + background-color: #5f6367; + font-weight: normal; } + .path-bar button.text-button, .path-bar button.image-button, .path-bar button { + padding-left: 4px; + padding-right: 4px; } + .path-bar button.text-button.image-button label { + padding-left: 0; + padding-right: 0; } + .path-bar button.text-button.image-button label:last-child, .path-bar button label:last-child { + padding-right: 8px; } + .path-bar button.text-button.image-button label:first-child, .path-bar button label:first-child { + padding-left: 8px; } + .path-bar button image { + padding-left: 4px; + padding-right: 4px; } + .path-bar button.slider-button { + padding-left: 0; + padding-right: 0; } + +/***************** + * Progress bars * + *****************/ +progressbar { + font-size: smaller; + color: rgba(255, 255, 255, 0.3); } + progressbar.horizontal trough, + progressbar.horizontal progress { + min-height: 6px; } + progressbar.vertical trough, + progressbar.vertical progress { + min-width: 6px; } + progressbar trough { + border: 0px solid transparent; + border-radius: 3px; + background-color: rgba(255, 255, 255, 0.3); } + progressbar:backdrop trough { + background-color: rgba(255, 255, 255, 0.3); } + progressbar progress { + background-color: #FF5F57; + border: 0px solid transparent; + border-radius: 3px; + box-shadow: none; } + progressbar:backdrop progress { + background-color: #FF5F57; } + progressbar.osd { + background-color: transparent; } + +treeview.view.progressbar { + border: 0px solid transparent; + border-radius: 3px; + background-color: #FF5F57; + color: white; + background-image: none; } + treeview.view.progressbar:selected:focus, treeview.view.progressbar:selected { + background-color: rgba(255, 255, 255, 0.25); } +treeview.view.trough { + background-color: #696d71; } + treeview.view.trough:selected:focus, treeview.view.trough:selected { + background-color: rgba(255, 255, 255, 0.3); } + +/************* + * Level Bar * + *************/ +levelbar block { + min-width: 32px; + min-height: 6px; } +levelbar.vertical block { + min-width: 6px; + min-height: 32px; } +levelbar trough { + border: 1px solid; + padding: 2px; + border-radius: 3px; + color: white; + border-color: #5f6367; + background-color: #292f34; + box-shadow: none; } + levelbar trough:backdrop { + color: white; + border-color: #5f6367; + background-color: #292f34; } +levelbar.horizontal.discrete block { + margin: 0 1px; } +levelbar.vertical.discrete block { + margin: 1px 0; } +levelbar block:not(.empty) { + border: 1px solid #FF5F57; + background-color: #FF5F57; + box-shadow: none; + border-radius: 1px; } + levelbar block:not(.empty):backdrop { + border-color: #FF5F57; + background-color: #FF5F57; } +levelbar block.low { + border-color: #e67e22; + background-color: #e67e22; } + levelbar block.low:backdrop { + background-color: #e67e22; + border-color: #e67e22; } +levelbar block.high { + border-color: #3498db; + background-color: #3498db; } + levelbar block.high:backdrop { + background-color: #3498db; + border-color: #3498db; } +levelbar block.full { + border-color: #3498db; + background-color: #3498db; } + levelbar block.full:backdrop { + background-color: #3498db; + border-color: #3498db; } +levelbar block.empty { + background-color: rgba(255, 255, 255, 0.3); + border-color: transparent; + box-shadow: none; } + levelbar block.empty:backdrop { + background-color: rgba(255, 255, 255, 0.3); } + +/************ + * GtkScale * + ************/ +scale.fine-tune.trough { + margin: 8px; + border-radius: 3px; } +scale slider { + min-width: 18px; + min-height: 18px; + background-color: #292f34; + border: 1px solid #5f6367; + border-radius: 50%; + box-shadow: none; + margin: -9px; } + scale slider:hover { + border-style: solid; + border-width: 2px; + border-color: #FF5F57; + border-radius: 50%; } + scale slider:hover:backdrop { + background-color: #292f34; + border-color: #FF5F57; } + scale slider:disabled { + border-style: solid; + border-radius: 50%; + background-color: #292f34; + border-color: rgba(86, 90, 94, 0.35); } + scale slider:disabled:backdrop { + background-color: #292f34; + border-color: rgba(86, 90, 94, 0.35); } + scale slider:active { + border: 2px solid #FF5F57; } + scale slider:active:backdrop { + background-color: #292f34; + border-color: #FF5F57; } + scale slider:backdrop { + background-color: #292f34; + border-color: #5f6367; } +scale trough { + min-width: 6px; + min-height: 6px; + margin: 9px; + border: 0px solid; + border-radius: 3px; + background-color: #696d71; + box-shadow: none; } + scale trough:disabled, scale trough.vertical:disabled { + border-color: rgba(95, 99, 103, 0.35); + background-color: rgba(95, 99, 103, 0.35); + box-shadow: none; } + scale trough:disabled:backdrop, scale trough.vertical:disabled:backdrop { + background-color: rgba(95, 99, 103, 0.35); + border-color: rgba(95, 99, 103, 0.35); } + scale trough:backdrop { + background-color: #696d71; + border-color: #696d71; } +scale highlight { + border: 0px solid; + border-radius: 3px; + background-color: #FF5F57; + border-color: #FF5F57; } + scale highlight.vertical { + background-color: #FF5F57; + border-color: #FF5F57; } + scale highlight:disabled { + background-color: rgba(24, 171, 142, 0.35); } + scale highlight:backdrop { + background-color: rgba(255, 95, 87, 0.5); + border-color: rgba(255, 95, 87, 0.5); } + scale highlight:backdrop:disabled { + background-color: rgba(24, 171, 142, 0.35); } + +/************** + * Scrollbars * + **************/ +scrollbar { + -GtkScrollbar-has-backward-stepper: true; + -GtkScrollbar-has-forward-stepper: true; + background-color: #292f34; + border-width: 3px 0px; + border-color: #292f34; + margin: 0px; } + scrollbar button { + min-width: 14px; + min-height: 14px; + margin: 0px; + padding: 0px 3px; + border: none; + border-radius: 0px; + background-image: none; + background-color: #292f34; + color: white; + box-shadow: none; } + scrollbar button:hover { + border: none; + background-image: none; + background-color: #292f34; + color: #FF5F57; } + scrollbar button:active, scrollbar button:active:hover { + border: none; + background-image: none; + background-color: #292f34; + color: #FF5F57; } + scrollbar button:disabled { + border: none; + background-color: #292f34; + background-image: none; + color: rgba(232, 232, 232, 0.35); } + scrollbar button:backdrop { + color: white; } + scrollbar button:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); } + scrollbar.dragging, scrollbar.hovering { + opacity: 0.9910; } + scrollbar.overlay-indicator:not(.dragging):not(.hovering) { + opacity: 0.999; } + scrollbar.overlay-indicator:not(.dragging):not(.hovering) { + -GtkScrollbar-has-backward-stepper: false; + -GtkScrollbar-has-forward-stepper: false; + background: none; } + scrollbar.overlay-indicator:not(.dragging):not(.hovering) slider { + min-width: 4px; + margin: 2px; + border: none; + border-radius: 2px; + background-color: #b4b6b8; } + scrollbar.overlay-indicator:not(.dragging):not(.hovering) slider:backdrop { + background-color: #b4b6b8; } + scrollbar.overlay-indicator:not(.dragging):not(.hovering) trough { + min-width: 4px; + min-height: 4px; + border: none; + background: none; + box-shadow: none; } + scrollbar.overlay-indicator:not(.dragging):not(.hovering).horizontal slider { + min-height: 4px; } + scrollbar trough { + min-width: 16px; + min-height: 16px; + border: 0px solid transparent; + border-radius: 8px; + background-color: #696d71; + box-shadow: inset 0px 0px 0px 3px #292f34; } + scrollbar slider { + min-width: 10px; + min-height: 30px; + border: 2px solid transparent; + border-radius: 8px; + background-clip: padding-box; + background-color: #b4b6b8; } + scrollbar slider:hover { + background-color: #FF5F57; } + scrollbar slider:active { + background-color: #FF5F57; } + scrollbar slider:disabled { + background-color: rgba(163, 165, 168, 0.35); } + scrollbar slider:backdrop { + background-color: #b4b6b8; } + scrollbar slider:backdrop:disabled { + background-color: rgba(163, 165, 168, 0.35); } + scrollbar.horizontal slider { + min-width: 30px; + min-height: 10px; } + scrollbar.vertical button.down { + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + scrollbar.vertical button.up { + -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); } + scrollbar.horizontal button.down { + -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); } + scrollbar.horizontal button.up { + -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + +/*********** + * Sidebar * + ***********/ +.sidebar { + border: none; + background-color: #292f34; } + .sidebar:backdrop { + background-color: #292f34; } + +placessidebar > viewport.frame { + border-style: none; } +placessidebar row { + min-height: 36px; + padding: 0px; } + placessidebar row > revealer { + padding: 0 14px; } + placessidebar row:selected { + color: white; } + placessidebar row:disabled { + color: rgba(232, 232, 232, 0.35); } + placessidebar row:backdrop { + color: white; } + placessidebar row:backdrop:selected { + color: #FF5F57; } + placessidebar row:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); } + placessidebar row image.sidebar-icon:dir(ltr) { + padding-right: 8px; } + placessidebar row image.sidebar-icon:dir(rtl) { + padding-left: 8px; } + placessidebar row label.sidebar-label:dir(ltr) { + padding-right: 2px; } + placessidebar row label.sidebar-label:dir(rtl) { + padding-left: 2px; } + button.sidebar-button { + min-height: 26px; + min-width: 26px; + margin-top: 3px; + margin-bottom: 3px; + padding: 0; } + placessidebar row:selected:active { + box-shadow: none; } + placessidebar row.sidebar-placeholder-row { + padding: 0 8px; + min-height: 2px; + background-image: none; + background-clip: content-box; } + placessidebar row.sidebar-new-bookmark-row { + color: #FF5F57; } + +placesview .server-list-button > image { + transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); + -gtk-icon-transform: rotate(0turn); } +placesview .server-list-button:checked > image { + transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); + -gtk-icon-transform: rotate(-0.5turn); } +placesview row.activatable:hover { + background-color: transparent; } +placesview > actionbar > revealer > box > label { + padding-left: 8px; + padding-right: 8px; } + +stacksidebar.sidebar row { + padding: 10px 4px; } + stacksidebar.sidebar row > label { + padding-left: 6px; + padding-right: 6px; } + stacksidebar.sidebar row.needs-attention > .label { + background-size: 6px 6px, 0 0; } + +/***************** + * GtkSpinButton * + *****************/ +spinbutton:not(.vertical) { + padding: 0; } + spinbutton:not(.vertical) entry { + min-width: 28px; + margin: 0; + background: none; + background-color: transparent; + border: none; + border-radius: 0; + box-shadow: none; } + spinbutton:not(.vertical) entry:backdrop:disabled { + background-color: transparent; } + spinbutton:not(.vertical) button { + min-height: 16px; + margin: 0; + padding-bottom: 0; + padding-top: 0; + color: white; + background-image: none; + background-color: transparent; + border-style: none; + box-shadow: none; } + spinbutton:not(.vertical) button:hover { + color: #FF5F57; } + spinbutton:not(.vertical) button:disabled { + color: rgba(232, 232, 232, 0.35); } + spinbutton:not(.vertical) button:active { + color: #FF5F57; + box-shadow: none; } + spinbutton:not(.vertical) button:backdrop { + color: white; + background-color: transparent; } + spinbutton:not(.vertical) button:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); + background-color: transparent; + border-style: none; } + spinbutton:not(.vertical) button:dir(ltr):last-child { + border-radius: 0 3px 3px 0; } + spinbutton:not(.vertical) button:dir(rtl):first-child { + border-radius: 3px 0 0 3px; } +spinbutton.vertical:disabled { + color: rgba(232, 232, 232, 0.35); } +spinbutton.vertical:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); } +spinbutton.vertical:drop(active) { + border-color: transparent; + box-shadow: none; } +spinbutton.vertical entry { + margin: 0px; + min-height: 26px; + min-width: 26px; + border-style: none solid none solid; + border-color: #5f6367; + padding: 0; + border-radius: 0; } + spinbutton.vertical entry:disabled { + color: rgba(232, 232, 232, 0.35); + background-color: #252b2f; + border-color: rgba(86, 90, 94, 0.35); } + spinbutton.vertical entry:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); + background-color: #252b2f; + border-color: rgba(86, 90, 94, 0.35); } +spinbutton.vertical button { + min-height: 26px; + min-width: 26px; + padding: 0; + box-shadow: none; + background-image: none; + background-color: #292f34; + color: white; + border-color: #5f6367; } + spinbutton.vertical button:hover { + color: #FF5F57; } + spinbutton.vertical button:active { + color: #FF5F57; } + spinbutton.vertical button:disabled { + color: rgba(232, 232, 232, 0.35); + background-color: #252b2f; + border-color: rgba(86, 90, 94, 0.35); } + spinbutton.vertical button:backdrop:disabled { + color: rgba(232, 232, 232, 0.35); + background-color: #252b2f; + border-color: rgba(86, 90, 94, 0.35); } +spinbutton.vertical button.up { + border-radius: 3px 3px 0 0; + border-style: solid solid none solid; } +spinbutton.vertical button.down { + border-radius: 0 0 3px 3px; + border-style: none solid solid solid; } +treeview spinbutton:not(.vertical) { + min-height: 0; + border-style: none; + border-radius: 0; } + treeview spinbutton:not(.vertical) entry { + min-height: 0; + padding: 1px 2px; } + +/********** + * Switch * + **********/ +switch { + margin: 2px; + font-weight: bold; + font-size: smaller; + min-width: 48px; + min-height: 24px; + border: 0px solid; + border-radius: 12px; + color: transparent; + background-color: rgba(255, 255, 255, 0.3); + text-shadow: none; } + switch:checked { + background-color: #FF5F57; } + switch:backdrop { + background-color: rgba(255, 255, 255, 0.3); + text-shadow: none; } + switch:backdrop:checked { + background-color: #FF5F57; } + switch slider { + min-width: 22px; + min-height: 22px; + border: 1px solid; + border-radius: 11px; + background-color: #292f34; + border-color: #5f6367; } + switch:hover slider { + border-color: #FF5F57; } + switch:disabled slider { + background-color: #252b2f; } + switch:backdrop slider { + background-color: #292f34; } + switch:backdrop:disabled slider { + background-color: #252b2f; } + +/************ + * Toolbars * + ************/ +toolbar, .inline-toolbar, searchbar, +.location-bar { + -GtkWidget-window-dragging: true; + padding: 4px; + background-color: #292f34; } + +toolbar { + padding: 4px 3px 3px 4px; } + toolbar:backdrop { + background-color: #292f34; + box-shadow: none; } + toolbar button { + margin: 2px; + padding: 3px; } + toolbar button.image-button, toolbar button.text-button.image-button { + padding: 3px; } + toolbar separator { + margin-left: 3px; + margin-right: 3px; } + toolbar entry { + margin: 3px; } + .osd toolbar { + background-color: transparent; } + toolbar.osd { + padding: 13px; + border: none; + border-radius: 3px; + background-color: #292f34; } + toolbar.osd:backdrop { + border-color: #5f6367; + background-color: #292f34; + box-shadow: none; } + toolbar.osd.left, toolbar.osd.right, toolbar.osd.top, toolbar.osd.bottom { + border-radius: 0; } + +.inline-toolbar { + border-width: 0px 0px 1px 0px; + padding: 3px; + border-radius: 0; } + +searchbar, +.location-bar { + border-width: 0px 0px 1px 0px; + padding: 3px; } + +.inline-toolbar, searchbar, +.location-bar { + border-style: solid; + border-color: #5f6367; + text-shadow: none; + background-color: #292f34; } + +/************ + * Tooltips * + ************/ +tooltip { + color: #f7f7f7; + padding: 4px; + /* not working */ + border-radius: 3px; + box-shadow: none; + text-shadow: none; } + tooltip.background { + background-color: #292f34; + background-clip: padding-box; } + tooltip.window-frame.csd { + background-color: transparent; + box-shadow: none; } + tooltip decoration { + background-color: transparent; } + +tooltip * { + padding: 0px; + background-color: transparent; + color: #f7f7f7; } + +/************** + * Tree Views * + **************/ +treeview.view { + -GtkTreeView-grid-line-width: 0; + -GtkTreeView-grid-line-pattern: ''; + -GtkTreeView-tree-line-width: 1; + -GtkTreeView-tree-line-pattern: ''; + -GtkTreeView-expander-size: 16; + border-left-color: #5f6367; + border-top-color: transparent; } + treeview.view:selected { + border-radius: 0; } + treeview.view:selected { + background-color: #FF5F57; + border-left-color: white; + border-top-color: white; } + treeview.view:backdrop:selected { + background-color: rgba(255, 95, 87, 0.5); + border-left-color: white; + border-top-color: white; } + treeview.view:disabled { + color: rgba(86, 90, 94, 0.35); } + treeview.view:disabled:selected { + color: rgba(232, 232, 232, 0.35); } + treeview.view:disabled:selected:backdrop { + color: rgba(232, 232, 232, 0.35); } + treeview.view:disabled:backdrop { + color: rgba(86, 90, 94, 0.35); } + treeview.view.seperator { + min-height: 2px; + color: #5f6367; } + treeview.view.separator:backdrop { + color: #5f6367; } + treeview.view:backdrop { + border-left-color: #5f6367; } + treeview.view:drop(active) { + border-style: solid none; + border-width: 1px; + border-color: #FF5F57; } + treeview.view.expander { + -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); + color: white; } + treeview.view.expander:dir(rtl) { + -gtk-icon-source: -gtk-icontheme("pan-start-symbolic"); } + treeview.view.expander:hover { + color: #FF5F57; } + treeview.view.expander:selected { + color: white; } + treeview.view.expander:checked { + -gtk-icon-source: -gtk-icontheme("pan-down-symbolic"); } + treeview.view.expander:checked:selected { + color: white; } + treeview.view.expander:checked:backdrop { + color: #292f34; } + treeview.view.expander:backdrop { + color: #292f34; } + treeview.view header button { + color: white; + background-color: #292f34; + text-shadow: none; + box-shadow: none; } + treeview.view header button:hover { + color: white; + background-color: rgba(255, 95, 87, 0.5); + box-shadow: none; + transition: none; } + treeview.view header button:active { + color: white; + background-color: rgba(255, 95, 87, 0.5); + transition: none; } + treeview.view header button:last-child:backdrop, treeview.view header button:last-child { + border-right-style: none; } + treeview.view button.dnd:active, treeview.view button.dnd:selected, treeview.view button.dnd:hover, treeview.view button.dnd, + treeview.view header.button.dnd:active, + treeview.view header.button.dnd:selected, + treeview.view header.button.dnd:hover, + treeview.view header.button.dnd { + padding: 0 6px; + color: white; + background-image: none; + background-color: #FF5F57; + border-style: none; + border-radius: 0; + box-shadow: none; + text-shadow: none; + transition: none; } + +treeview.view header button, treeview.view header button:hover, treeview.view header button:active { + padding: 6px; + border-style: none solid solid none; + border-radius: 0; + background-image: none; + border-color: #5f6367; + text-shadow: none; } + treeview.view header button:disabled { + border-color: rgba(86, 90, 94, 0.35); + color: rgba(232, 232, 232, 0.35); + background-color: #252b2f; + background-image: none; } + treeview.view header button:backdrop { + border-color: #5f6367; + border-style: none solid solid none; + color: white; + background-image: none; + background-color: #292f34; } + treeview.view header button:backdrop:disabled { + border-color: rgba(86, 90, 94, 0.35); + background-image: none; + background-color: #252b2f; + color: rgba(232, 232, 232, 0.35); } + +/********************** + * Window Decorations * + *********************/ +decoration { + border-radius: 3px 3px 0 0; + border-width: 0px; + box-shadow: 0 2px 6px 1px rgba(0, 0, 0, 0.5); + /* this is used for the resize cursor area */ + margin: 10px; } + .maximized decoration, .fullscreen decoration, .tiled decoration { + border-radius: 0; } + .popup decoration { + border-radius: 3px; + box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.1); } + .ssd decoration { + box-shadow: 0 2px 6px 1px rgba(0, 0, 0, 0.1); } + .csd decoration { + border-radius: 3px; } + .csd decoration.popup { + box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.1); } + .csd decoration.tooltip { + box-shadow: none; } + .csd decoration.message-dialog { + box-shadow: 0 2px 6px 1px rgba(0, 0, 0, 0.5); } + .solid-csd decoration { + border-radius: 0; + margin: 0; + padding: 1px; + border: none; + background-color: #5f6367; + box-shadow: none; } + +headerbar.default-decoration button.titlebutton, +.titlebar.default-decoration button.titlebutton { + padding: 6px 1px; + min-height: 18px; + min-width: 18px; + margin: 0; } +headerbar button.titlebutton, +.titlebar button.titlebutton { + padding: 6px; } + headerbar button.titlebutton:hover, headerbar button.titlebutton:active, headerbar button.titlebutton:checked, headerbar button.titlebutton:backdrop, headerbar button.titlebutton:active:hover, + .titlebar button.titlebutton:hover, + .titlebar button.titlebutton:active, + .titlebar button.titlebutton:checked, + .titlebar button.titlebutton:backdrop, + .titlebar button.titlebutton:active:hover { + transition: none; } + headerbar button.titlebutton.close, + .titlebar button.titlebutton.close { + padding: 6px 1px; + color: transparent; + border-image: none; + box-shadow: none; + background-position: center; + background-repeat: no-repeat + } + headerbar button.titlebutton.close:hover, + .titlebar button.titlebutton.close:hover { + border-color: transparent; + background-color: transparent; + } + headerbar button.titlebutton.close:active, + .titlebar button.titlebutton.close:active { + border-color: transparent; + background-color: transparent; + } + headerbar button.titlebutton.close:backdrop, + .titlebar button.titlebutton.close:backdrop { + border-color: transparent; + background-color: transparent; + } + headerbar button.titlebutton.maximize, + .titlebar button.titlebutton.maximize { + padding: 6px 1px; + color: transparent; + border-image: none; + box-shadow: none; + background-position: center; + background-repeat: no-repeat; + } + headerbar button.titlebutton.maximize:hover, + .titlebar button.titlebutton.maximize:hover { + border-color: transparent; + background-color: transparent; + } + headerbar button.titlebutton.maximize:active, + .titlebar button.titlebutton.maximize:active { + border-color: transparent; + background-color: transparent; + } + headerbar button.titlebutton.maximize:backdrop, + .titlebar button.titlebutton.maximize:backdrop { + border-color: transparent; + background-color: transparent; + } + headerbar button.titlebutton.minimize, + .titlebar button.titlebutton.minimize { + padding: 6px 1px; + color: transparent; + border-image: none; + box-shadow: none; + background-position: center; + background-repeat: no-repeat; + } + headerbar button.titlebutton.minimize:hover, + .titlebar button.titlebutton.minimize:hover { + border-color: transparent; + background-color: transparent; + } + headerbar button.titlebutton.minimize:active, + .titlebar button.titlebutton.minimize:active { + border-color: transparent; + background-color: transparent; + } + headerbar button.titlebutton.minimize:backdrop, + .titlebar button.titlebutton.minimize:backdrop { + border-color: transparent; + background-color: transparent; + } +.maximized headerbar button.titlebutton.maximize, .maximized +.titlebar button.titlebutton.maximize { + padding: 6px 1px; + color: transparent; + border-image: none; + box-shadow: none; + background-position: center; + background-repeat: no-repeat; + } +.maximized headerbar button.titlebutton.maximize:hover, .maximized +.titlebar button.titlebutton.maximize:hover { + border-color: transparent; + background-color: transparent; + } +.maximized headerbar button.titlebutton.maximize:active, .maximized +.titlebar button.titlebutton.maximize:active { + border-color: transparent; + background-color: transparent; + } +.maximized headerbar button.titlebutton.maximize:backdrop, .maximized +.titlebar button.titlebutton.maximize:backdrop { + border-color: transparent; + background-color: transparent; + } + +headerbar.selection-mode button.titlebutton, +.titlebar.selection-mode button.titlebutton { + text-shadow: none; } + headerbar.selection-mode button.titlebutton:backdrop, + .titlebar.selection-mode button.titlebutton:backdrop { + -gtk-icon-shadow: none; } + +/* + Original theme source: https://gitlab.manjaro.org/artwork/themes/breath-gtk + Changes to original: + - all refrences to assets have been removed + - green hex codes been changed to #FF5F57 +*/ + +/* + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +(This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.) + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS +*/ \ No newline at end of file diff --git a/Ryujinx/Ui/AboutWindow.cs b/Ryujinx/Ui/AboutWindow.cs new file mode 100644 index 000000000..6f31b9cde --- /dev/null +++ b/Ryujinx/Ui/AboutWindow.cs @@ -0,0 +1,116 @@ +using Gtk; +using GUI = Gtk.Builder.ObjectAttribute; +using System; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.InteropServices; +using Utf8Json; +using Utf8Json.Resolvers; +using System.IO; + +namespace Ryujinx.UI +{ + public struct Info + { + public string InstallVersion; + public string InstallCommit; + public string InstallBranch; + } + + public class AboutWindow : Window + { + public static Info Information { get; private set; } + +#pragma warning disable 649 + [GUI] Window _aboutWin; + [GUI] Label _versionText; + [GUI] Image _ryujinxLogo; + [GUI] Image _patreonLogo; + [GUI] Image _gitHubLogo; + [GUI] Image _discordLogo; + [GUI] Image _twitterLogo; +#pragma warning restore 649 + + public AboutWindow() : this(new Builder("Ryujinx.Ui.AboutWindow.glade")) { } + + private AboutWindow(Builder builder) : base(builder.GetObject("_aboutWin").Handle) + { + builder.Autoconnect(this); + + _aboutWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.RyujinxIcon.png"); + _ryujinxLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.RyujinxIcon.png", 100, 100); + _patreonLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.PatreonLogo.png", 30 , 30 ); + _gitHubLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.GitHubLogo.png" , 30 , 30 ); + _discordLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.DiscordLogo.png", 30 , 30 ); + _twitterLogo.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.TwitterLogo.png", 30 , 30 ); + + try + { + IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase }); + + using (Stream stream = File.OpenRead(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "Installer", "Config", "Config.json"))) + { + Information = JsonSerializer.Deserialize(stream, resolver); + } + + _versionText.Text = $"Version {Information.InstallVersion} - {Information.InstallBranch} ({Information.InstallCommit})"; + } + catch + { + _versionText.Text = "Unknown Version"; + } + } + + public void OpenUrl(string url) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + Process.Start("xdg-open", url); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + Process.Start("open", url); + } + } + + //Events + private void RyujinxButton_Pressed(object obj, ButtonPressEventArgs args) + { + OpenUrl("https://ryujinx.org"); + } + + private void PatreonButton_Pressed(object obj, ButtonPressEventArgs args) + { + OpenUrl("https://www.patreon.com/ryujinx"); + } + + private void GitHubButton_Pressed(object obj, ButtonPressEventArgs args) + { + OpenUrl("https://github.com/Ryujinx/Ryujinx"); + } + + private void DiscordButton_Pressed(object obj, ButtonPressEventArgs args) + { + OpenUrl("https://discordapp.com/invite/N2FmfVc"); + } + + private void TwitterButton_Pressed(object obj, ButtonPressEventArgs args) + { + OpenUrl("https://twitter.com/RyujinxEmu"); + } + + private void ContributersButton_Pressed(object obj, ButtonPressEventArgs args) + { + OpenUrl("https://github.com/Ryujinx/Ryujinx/graphs/contributors?type=a"); + } + + private void CloseToggle_Activated(object obj, EventArgs args) + { + Destroy(); + } + } +} diff --git a/Ryujinx/Ui/AboutWindow.glade b/Ryujinx/Ui/AboutWindow.glade new file mode 100644 index 000000000..28a800720 --- /dev/null +++ b/Ryujinx/Ui/AboutWindow.glade @@ -0,0 +1,574 @@ + + + + + + False + False + True + center + 800 + 350 + dialog + + + + + + False + vertical + + + False + + + False + False + 0 + + + + + True + False + + + True + False + 10 + 15 + 10 + 15 + vertical + + + True + False + start + vertical + + + True + False + + + + True + True + 0 + + + + + True + False + center + vertical + + + True + False + Ryujinx + center + + + + + + False + True + 0 + + + + + True + False + (REE-YOU-JI-NX) + center + + + False + True + 1 + + + + + True + False + + + + True + False + Click to open the Ryujinx website in your default browser + www.ryujinx.org + center + + + + + + + + False + True + 5 + 2 + + + + + True + True + 1 + + + + + False + True + 0 + + + + + True + False + Version x.x.x (Commit Number) + center + + + False + True + 2 + 1 + + + + + True + False + Unlicenced + center + + + False + True + 5 + 2 + + + + + True + False + Ryujinx is not affiliated with Nintendo, +or any of its partners, in any way + center + + + + + + False + True + 5 + 3 + + + + + False + False + 0 + + + + + True + False + 25 + + + True + False + Click to open the Ryujinx Patreon page in your default browser + + + + True + False + vertical + + + + True + True + 0 + + + + + True + False + Patreon + + + False + True + 1 + + + + + + + True + True + 0 + + + + + True + False + Click to open the Ryujinx GitHub page in your default browser + + + + True + False + vertical + + + + True + True + 0 + + + + + True + False + GitHub + + + False + True + 1 + + + + + + + True + True + 1 + + + + + True + False + Click to open an invite to the Ryujinx Discord server in your default browser + + + + True + False + vertical + + + + True + True + 0 + + + + + True + False + Discord + + + False + True + 1 + + + + + + + True + True + 2 + + + + + True + False + Click to open the Ryujinx Twitter page in your default browser + + + + True + False + vertical + + + + True + True + 0 + + + + + True + False + Twitter + + + False + True + 1 + + + + + + + True + True + 3 + + + + + False + False + end + 2 + + + + + True + False + 0 + + + + + True + False + 10 + 10 + + + False + True + 1 + + + + + True + False + 15 + 10 + 40 + 15 + vertical + + + True + False + start + About + + + + + + False + True + 0 + + + + + True + False + start + 10 + Ryujinx is an emulator for the Nintendo Switch. +Please support us on Patreon. +Get all the latest news on our Twitter or Discord. +Developers interested in contributing can find out more on our Discord. + + + False + True + 5 + 1 + + + + + True + False + start + Created By: + + + + + + False + True + 5 + 2 + + + + + True + False + 10 + vertical + + + True + True + in + + + True + False + + + True + False + top + + + True + False + start + gdkchan +LDj3SNuD +Ac_K +Thog + 0 + + + True + True + 0 + + + + + True + False + start + »jD« +emmaus +Thealexbarney +Andy A (BaronKiko) + 0 + + + True + True + 1 + + + + + + + + + True + True + 0 + + + + + True + False + start + + + + True + False + end + 5 + All Contributors... + + + + + + + + False + False + 2 + + + + + True + True + 3 + + + + + True + True + 2 + + + + + True + True + 1 + + + + + + diff --git a/Ryujinx/Ui/ApplicationLibrary.cs b/Ryujinx/Ui/ApplicationLibrary.cs new file mode 100644 index 000000000..7e731f794 --- /dev/null +++ b/Ryujinx/Ui/ApplicationLibrary.cs @@ -0,0 +1,450 @@ +using LibHac; +using LibHac.Fs; +using LibHac.Fs.NcaUtils; +using Ryujinx.Common.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using SystemState = Ryujinx.HLE.HOS.SystemState; + +namespace Ryujinx.UI +{ + public class ApplicationLibrary + { + private static Keyset KeySet; + private static SystemState.TitleLanguage DesiredTitleLanguage; + + private const double SecondsPerMinute = 60.0; + private const double SecondsPerHour = SecondsPerMinute * 60; + private const double SecondsPerDay = SecondsPerHour * 24; + + public static byte[] RyujinxNspIcon { get; private set; } + public static byte[] RyujinxXciIcon { get; private set; } + public static byte[] RyujinxNcaIcon { get; private set; } + public static byte[] RyujinxNroIcon { get; private set; } + public static byte[] RyujinxNsoIcon { get; private set; } + + public static List ApplicationLibraryData { get; private set; } + + public struct ApplicationData + { + public byte[] Icon; + public string TitleName; + public string TitleId; + public string Developer; + public string Version; + public string TimePlayed; + public string LastPlayed; + public string FileExt; + public string FileSize; + public string Path; + } + + public static void Init(List AppDirs, Keyset keySet, SystemState.TitleLanguage desiredTitleLanguage) + { + KeySet = keySet; + DesiredTitleLanguage = desiredTitleLanguage; + + // Loads the default application Icons + RyujinxNspIcon = GetResourceBytes("Ryujinx.Ui.assets.ryujinxNSPIcon.png"); + RyujinxXciIcon = GetResourceBytes("Ryujinx.Ui.assets.ryujinxXCIIcon.png"); + RyujinxNcaIcon = GetResourceBytes("Ryujinx.Ui.assets.ryujinxNCAIcon.png"); + RyujinxNroIcon = GetResourceBytes("Ryujinx.Ui.assets.ryujinxNROIcon.png"); + RyujinxNsoIcon = GetResourceBytes("Ryujinx.Ui.assets.ryujinxNSOIcon.png"); + + // Builds the applications list with paths to found applications + List applications = new List(); + foreach (string appDir in AppDirs) + { + if (Directory.Exists(appDir) == false) + { + Logger.PrintWarning(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\""); + + continue; + } + + DirectoryInfo AppDirInfo = new DirectoryInfo(appDir); + foreach (FileInfo App in AppDirInfo.GetFiles()) + { + if ((Path.GetExtension(App.ToString()) == ".xci") || + (Path.GetExtension(App.ToString()) == ".nca") || + (Path.GetExtension(App.ToString()) == ".nsp") || + (Path.GetExtension(App.ToString()) == ".pfs0") || + (Path.GetExtension(App.ToString()) == ".nro") || + (Path.GetExtension(App.ToString()) == ".nso")) + { + applications.Add(App.ToString()); + } + } + } + + // Loops through applications list, creating a struct for each application and then adding the struct to a list of structs + ApplicationLibraryData = new List(); + foreach (string applicationPath in applications) + { + double filesize = new FileInfo(applicationPath).Length * 0.000000000931; + string titleName = null; + string titleId = null; + string developer = null; + string version = null; + byte[] applicationIcon = null; + + using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read)) + { + if ((Path.GetExtension(applicationPath) == ".nsp") || + (Path.GetExtension(applicationPath) == ".pfs0") || + (Path.GetExtension(applicationPath) == ".xci")) + { + try + { + IFileSystem controlFs = null; + + // Store the ControlFS in variable called controlFs + if (Path.GetExtension(applicationPath) == ".xci") + { + Xci xci = new Xci(KeySet, file.AsStorage()); + + controlFs = GetControlFs(xci.OpenPartition(XciPartitionType.Secure)); + } + else + { + controlFs = GetControlFs(new PartitionFileSystem(file.AsStorage())); + } + + // Creates NACP class from the NACP file + IFile controlNacp = controlFs.OpenFile("/control.nacp", OpenMode.Read); + Nacp controlData = new Nacp(controlNacp.AsStream()); + + // Get the title name, title ID, developer name and version number from the NACP + version = controlData.DisplayVersion; + + titleName = controlData.Descriptions[(int)DesiredTitleLanguage].Title; + + if (string.IsNullOrWhiteSpace(titleName)) + { + titleName = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title; + } + + titleId = controlData.PresenceGroupId.ToString("x16"); + + if (string.IsNullOrWhiteSpace(titleId)) + { + titleId = controlData.SaveDataOwnerId.ToString("x16"); + } + + if (string.IsNullOrWhiteSpace(titleId)) + { + titleId = (controlData.AddOnContentBaseId - 0x1000).ToString("x16"); + } + + developer = controlData.Descriptions[(int)DesiredTitleLanguage].Developer; + + if (string.IsNullOrWhiteSpace(developer)) + { + developer = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Developer)).Developer; + } + + // Read the icon from the ControlFS and store it as a byte array + try + { + IFile icon = controlFs.OpenFile($"/icon_{DesiredTitleLanguage}.dat", OpenMode.Read); + using (MemoryStream stream = new MemoryStream()) + { + icon.AsStream().CopyTo(stream); + applicationIcon = stream.ToArray(); + } + } + catch (HorizonResultException) + { + IDirectory controlDir = controlFs.OpenDirectory("./", OpenDirectoryMode.All); + foreach (DirectoryEntry entry in controlDir.Read()) + { + if (entry.Name == "control.nacp") + { + continue; + } + + IFile icon = controlFs.OpenFile(entry.FullPath, OpenMode.Read); + using (MemoryStream stream = new MemoryStream()) + { + icon.AsStream().CopyTo(stream); + applicationIcon = stream.ToArray(); + } + + if (applicationIcon != null) + { + break; + } + } + + if (applicationIcon == null) + { + applicationIcon = NspOrXciIcon(applicationPath); + } + } + } + catch (MissingKeyException exception) + { + titleName = "Unknown"; + titleId = "Unknown"; + developer = "Unknown"; + version = "?"; + applicationIcon = NspOrXciIcon(applicationPath); + + Logger.PrintWarning(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); + } + catch (InvalidDataException) + { + titleName = "Unknown"; + titleId = "Unknown"; + developer = "Unknown"; + version = "?"; + applicationIcon = NspOrXciIcon(applicationPath); + + Logger.PrintWarning(LogClass.Application, $"The file is not an NCA file or the header key is incorrect. Errored File: {applicationPath}"); + } + catch (Exception exception) + { + Logger.PrintWarning(LogClass.Application, $"This warning usualy means that you have a DLC in one of you game directories\n{exception}"); + + continue; + } + } + else if (Path.GetExtension(applicationPath) == ".nro") + { + BinaryReader reader = new BinaryReader(file); + + byte[] Read(long Position, int Size) + { + file.Seek(Position, SeekOrigin.Begin); + + return reader.ReadBytes(Size); + } + + file.Seek(24, SeekOrigin.Begin); + int AssetOffset = reader.ReadInt32(); + + if (Encoding.ASCII.GetString(Read(AssetOffset, 4)) == "ASET") + { + byte[] IconSectionInfo = Read(AssetOffset + 8, 0x10); + + long iconOffset = BitConverter.ToInt64(IconSectionInfo, 0); + long iconSize = BitConverter.ToInt64(IconSectionInfo, 8); + + ulong nacpOffset = reader.ReadUInt64(); + ulong nacpSize = reader.ReadUInt64(); + + // Reads and stores game icon as byte array + applicationIcon = Read(AssetOffset + iconOffset, (int)iconSize); + + // Creates memory stream out of byte array which is the NACP + using (MemoryStream stream = new MemoryStream(Read(AssetOffset + (int)nacpOffset, (int)nacpSize))) + { + // Creates NACP class from the memory stream + Nacp controlData = new Nacp(stream); + + // Get the title name, title ID, developer name and version number from the NACP + version = controlData.DisplayVersion; + + titleName = controlData.Descriptions[(int)DesiredTitleLanguage].Title; + + if (string.IsNullOrWhiteSpace(titleName)) + { + titleName = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title; + } + + titleId = controlData.PresenceGroupId.ToString("x16"); + + if (string.IsNullOrWhiteSpace(titleId)) + { + titleId = controlData.SaveDataOwnerId.ToString("x16"); + } + + if (string.IsNullOrWhiteSpace(titleId)) + { + titleId = (controlData.AddOnContentBaseId - 0x1000).ToString("x16"); + } + + developer = controlData.Descriptions[(int)DesiredTitleLanguage].Developer; + + if (string.IsNullOrWhiteSpace(developer)) + { + developer = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Developer)).Developer; + } + } + } + else + { + applicationIcon = RyujinxNroIcon; + titleName = "Application"; + titleId = "0000000000000000"; + developer = "Unknown"; + version = "?"; + } + } + // If its an NCA or NSO we just set defaults + else if ((Path.GetExtension(applicationPath) == ".nca") || (Path.GetExtension(applicationPath) == ".nso")) + { + if (Path.GetExtension(applicationPath) == ".nca") + { + applicationIcon = RyujinxNcaIcon; + } + else if (Path.GetExtension(applicationPath) == ".nso") + { + applicationIcon = RyujinxNsoIcon; + } + + string fileName = Path.GetFileName(applicationPath); + string fileExt = Path.GetExtension(applicationPath); + + StringBuilder titlename = new StringBuilder(); + titlename.Append(fileName); + titlename.Remove(fileName.Length - fileExt.Length, fileExt.Length); + + titleName = titlename.ToString(); + titleId = "0000000000000000"; + version = "?"; + developer = "Unknown"; + } + } + + string[] playedData = GetPlayedData(titleId, "00000000000000000000000000000001"); + + ApplicationData data = new ApplicationData() + { + Icon = applicationIcon, + TitleName = titleName, + TitleId = titleId, + Developer = developer, + Version = version, + TimePlayed = playedData[0], + LastPlayed = playedData[1], + FileExt = Path.GetExtension(applicationPath).ToUpper().Remove(0 ,1), + FileSize = (filesize < 1) ? (filesize * 1024).ToString("0.##") + "MB" : filesize.ToString("0.##") + "GB", + Path = applicationPath, + }; + + ApplicationLibraryData.Add(data); + } + } + + private static byte[] GetResourceBytes(string resourceName) + { + Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName); + byte[] resourceByteArray = new byte[resourceStream.Length]; + + resourceStream.Read(resourceByteArray); + + return resourceByteArray; + } + + private static IFileSystem GetControlFs(PartitionFileSystem Pfs) + { + Nca controlNca = null; + + // Add keys to keyset if needed + foreach (DirectoryEntry ticketEntry in Pfs.EnumerateEntries("*.tik")) + { + Ticket ticket = new Ticket(Pfs.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream()); + + if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId)) + { + KeySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(KeySet)); + } + } + + // Find the Control NCA and store it in variable called controlNca + foreach (DirectoryEntry fileEntry in Pfs.EnumerateEntries("*.nca")) + { + Nca nca = new Nca(KeySet, Pfs.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage()); + if (nca.Header.ContentType == ContentType.Control) + { + controlNca = nca; + } + } + + // Return the ControlFS + return controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); + } + + private static string[] GetPlayedData(string TitleId, string UserId) + { + try + { + string[] playedData = new string[2]; + string savePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "nand", "user", "save", "0000000000000000", UserId, TitleId); + + if (File.Exists(Path.Combine(savePath, "TimePlayed.dat")) == false) + { + Directory.CreateDirectory(savePath); + using (FileStream file = File.OpenWrite(Path.Combine(savePath, "TimePlayed.dat"))) + { + file.Write(Encoding.ASCII.GetBytes("0")); + } + } + using (FileStream fs = File.OpenRead(Path.Combine(savePath, "TimePlayed.dat"))) + { + using (StreamReader sr = new StreamReader(fs)) + { + float timePlayed = float.Parse(sr.ReadLine()); + + if (timePlayed < SecondsPerMinute) + { + playedData[0] = $"{timePlayed}s"; + } + else if (timePlayed < SecondsPerHour) + { + playedData[0] = $"{Math.Round(timePlayed / SecondsPerMinute, 2, MidpointRounding.AwayFromZero)} mins"; + } + else if (timePlayed < SecondsPerDay) + { + playedData[0] = $"{Math.Round(timePlayed / SecondsPerHour , 2, MidpointRounding.AwayFromZero)} hrs"; + } + else + { + playedData[0] = $"{Math.Round(timePlayed / SecondsPerDay , 2, MidpointRounding.AwayFromZero)} days"; + } + } + } + + if (File.Exists(Path.Combine(savePath, "LastPlayed.dat")) == false) + { + Directory.CreateDirectory(savePath); + using (FileStream file = File.OpenWrite(Path.Combine(savePath, "LastPlayed.dat"))) + { + file.Write(Encoding.ASCII.GetBytes("Never")); + } + } + + using (FileStream fs = File.OpenRead(Path.Combine(savePath, "LastPlayed.dat"))) + { + using (StreamReader sr = new StreamReader(fs)) + { + playedData[1] = sr.ReadLine(); + } + } + + return playedData; + } + catch + { + return new string[] { "Unknown", "Unknown" }; + } + } + + private static byte[] NspOrXciIcon(string applicationPath) + { + if (Path.GetExtension(applicationPath) == ".xci") + { + return RyujinxXciIcon; + } + else + { + return RyujinxNspIcon; + } + } + } +} diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index a881959cf..7c3946300 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -10,7 +10,7 @@ using System.Threading; using Stopwatch = System.Diagnostics.Stopwatch; -namespace Ryujinx +namespace Ryujinx.UI { public class GlScreen : GameWindow { diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs new file mode 100644 index 000000000..132c90e6d --- /dev/null +++ b/Ryujinx/Ui/MainWindow.cs @@ -0,0 +1,601 @@ +using DiscordRPC; +using Gtk; +using GUI = Gtk.Builder.ObjectAttribute; +using Ryujinx.Audio; +using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Gal.OpenGL; +using Ryujinx.Profiler; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; + +namespace Ryujinx.UI +{ + public class MainWindow : Window + { + internal static HLE.Switch _device; + + private static IGalRenderer _renderer; + + private static IAalOutput _audioOut; + + private static Application _gtkApplication; + + private static ListStore _tableStore; + + private static bool _gameLoaded = false; + + private static string _userId = "00000000000000000000000000000001"; + + public static bool DiscordIntegrationEnabled { get; set; } + + public static DiscordRpcClient DiscordClient; + + public static RichPresence DiscordPresence; + +#pragma warning disable 649 + [GUI] Window _mainWin; + [GUI] CheckMenuItem _fullScreen; + [GUI] MenuItem _stopEmulation; + [GUI] CheckMenuItem _iconToggle; + [GUI] CheckMenuItem _titleToggle; + [GUI] CheckMenuItem _developerToggle; + [GUI] CheckMenuItem _versionToggle; + [GUI] CheckMenuItem _timePlayedToggle; + [GUI] CheckMenuItem _lastPlayedToggle; + [GUI] CheckMenuItem _fileExtToggle; + [GUI] CheckMenuItem _fileSizeToggle; + [GUI] CheckMenuItem _pathToggle; + [GUI] Box _box; + [GUI] TreeView _gameTable; + [GUI] GLArea _glScreen; +#pragma warning restore 649 + + public MainWindow(string[] args, Application gtkApplication) : this(new Builder("Ryujinx.Ui.MainWindow.glade"), args, gtkApplication) { } + + private MainWindow(Builder builder, string[] args, Application gtkApplication) : base(builder.GetObject("_mainWin").Handle) + { + _renderer = new OglRenderer(); + + _audioOut = InitializeAudioEngine(); + + _device = new HLE.Switch(_renderer, _audioOut); + + Configuration.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + Configuration.InitialConfigure(_device); + + ApplicationLibrary.Init(SwitchSettings.SwitchConfig.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage); + + _gtkApplication = gtkApplication; + + ApplyTheme(); + + if (DiscordIntegrationEnabled) + { + DiscordClient = new DiscordRpcClient("568815339807309834"); + DiscordPresence = new RichPresence + { + Assets = new Assets + { + LargeImageKey = "ryujinx", + LargeImageText = "Ryujinx is an emulator for the Nintendo Switch" + }, + Details = "Main Menu", + State = "Idling", + Timestamps = new Timestamps(DateTime.UtcNow) + }; + + DiscordClient.Initialize(); + DiscordClient.SetPresence(DiscordPresence); + } + + builder.Autoconnect(this); + + DeleteEvent += Window_Close; + + _mainWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.RyujinxIcon.png"); + _stopEmulation.Sensitive = false; + + if (SwitchSettings.SwitchConfig.GuiColumns[0]) { _iconToggle.Active = true; } + if (SwitchSettings.SwitchConfig.GuiColumns[1]) { _titleToggle.Active = true; } + if (SwitchSettings.SwitchConfig.GuiColumns[2]) { _developerToggle.Active = true; } + if (SwitchSettings.SwitchConfig.GuiColumns[3]) { _versionToggle.Active = true; } + if (SwitchSettings.SwitchConfig.GuiColumns[4]) { _timePlayedToggle.Active = true; } + if (SwitchSettings.SwitchConfig.GuiColumns[5]) { _lastPlayedToggle.Active = true; } + if (SwitchSettings.SwitchConfig.GuiColumns[6]) { _fileExtToggle.Active = true; } + if (SwitchSettings.SwitchConfig.GuiColumns[7]) { _fileSizeToggle.Active = true; } + if (SwitchSettings.SwitchConfig.GuiColumns[8]) { _pathToggle.Active = true; } + + if (args.Length == 1) + { + // Temporary code section start, remove this section when game is rendered to the GLArea in the GUI + _box.Remove(_glScreen); + + if (SwitchSettings.SwitchConfig.GuiColumns[0]) { _gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 0); } + if (SwitchSettings.SwitchConfig.GuiColumns[1]) { _gameTable.AppendColumn("Application", new CellRendererText(), "text", 1); } + if (SwitchSettings.SwitchConfig.GuiColumns[2]) { _gameTable.AppendColumn("Developer", new CellRendererText(), "text", 2); } + if (SwitchSettings.SwitchConfig.GuiColumns[3]) { _gameTable.AppendColumn("Version", new CellRendererText(), "text", 3); } + if (SwitchSettings.SwitchConfig.GuiColumns[4]) { _gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 4); } + if (SwitchSettings.SwitchConfig.GuiColumns[5]) { _gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 5); } + if (SwitchSettings.SwitchConfig.GuiColumns[6]) { _gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 6); } + if (SwitchSettings.SwitchConfig.GuiColumns[7]) { _gameTable.AppendColumn("File Size", new CellRendererText(), "text", 7); } + if (SwitchSettings.SwitchConfig.GuiColumns[8]) { _gameTable.AppendColumn("Path", new CellRendererText(), "text", 8); } + + _tableStore = new ListStore(typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string)); + _gameTable.Model = _tableStore; + + UpdateGameTable(); + // Temporary code section end + + LoadApplication(args[0]); + } + else + { + _box.Remove(_glScreen); + + if (SwitchSettings.SwitchConfig.GuiColumns[0]) { _gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 0); } + if (SwitchSettings.SwitchConfig.GuiColumns[1]) { _gameTable.AppendColumn("Application", new CellRendererText(), "text", 1); } + if (SwitchSettings.SwitchConfig.GuiColumns[2]) { _gameTable.AppendColumn("Developer", new CellRendererText(), "text", 2); } + if (SwitchSettings.SwitchConfig.GuiColumns[3]) { _gameTable.AppendColumn("Version", new CellRendererText(), "text", 3); } + if (SwitchSettings.SwitchConfig.GuiColumns[4]) { _gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 4); } + if (SwitchSettings.SwitchConfig.GuiColumns[5]) { _gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 5); } + if (SwitchSettings.SwitchConfig.GuiColumns[6]) { _gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 6); } + if (SwitchSettings.SwitchConfig.GuiColumns[7]) { _gameTable.AppendColumn("File Size", new CellRendererText(), "text", 7); } + if (SwitchSettings.SwitchConfig.GuiColumns[8]) { _gameTable.AppendColumn("Path", new CellRendererText(), "text", 8); } + + _tableStore = new ListStore(typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string)); + _gameTable.Model = _tableStore; + + UpdateGameTable(); + } + } + + public static void CreateErrorDialog(string errorMessage) + { + MessageDialog errorDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, errorMessage) + { + Title = "Ryujinx - Error", + Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.RyujinxIcon.png"), + WindowPosition = WindowPosition.Center + }; + errorDialog.SetSizeRequest(100, 20); + errorDialog.Run(); + errorDialog.Destroy(); + } + + public static void UpdateGameTable() + { + _tableStore.Clear(); + ApplicationLibrary.Init(SwitchSettings.SwitchConfig.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage); + + foreach (ApplicationLibrary.ApplicationData AppData in ApplicationLibrary.ApplicationLibraryData) + { + _tableStore.AppendValues(new Gdk.Pixbuf(AppData.Icon, 75, 75), $"{AppData.TitleName}\n{AppData.TitleId.ToUpper()}", AppData.Developer, AppData.Version, AppData.TimePlayed, AppData.LastPlayed, AppData.FileExt, AppData.FileSize, AppData.Path); + } + } + + public static void ApplyTheme() + { + CssProvider cssProvider = new CssProvider(); + + if (SwitchSettings.SwitchConfig.EnableCustomTheme) + { + if (File.Exists(SwitchSettings.SwitchConfig.CustomThemePath) && (System.IO.Path.GetExtension(SwitchSettings.SwitchConfig.CustomThemePath) == ".css")) + { + cssProvider.LoadFromPath(SwitchSettings.SwitchConfig.CustomThemePath); + } + else + { + Logger.PrintWarning(LogClass.Application, $"The \"custom_theme_path\" section in \"Config.json\" contains an invalid path: \"{SwitchSettings.SwitchConfig.CustomThemePath}\""); + } + } + else + { + cssProvider.LoadFromPath(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Theme.css")); + } + + StyleContext.AddProviderForScreen(Gdk.Screen.Default, cssProvider, 800); + } + + private void LoadApplication(string path) + { + if (_gameLoaded) + { + CreateErrorDialog("A game has already been loaded. Please close the emulator and try again"); + } + else + { + if (Directory.Exists(path)) + { + string[] romFsFiles = Directory.GetFiles(path, "*.istorage"); + + if (romFsFiles.Length == 0) + { + romFsFiles = Directory.GetFiles(path, "*.romfs"); + } + + if (romFsFiles.Length > 0) + { + Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS."); + _device.LoadCart(path, romFsFiles[0]); + } + else + { + Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS."); + _device.LoadCart(path); + } + } + + else if (File.Exists(path)) + { + switch (System.IO.Path.GetExtension(path).ToLowerInvariant()) + { + case ".xci": + Logger.PrintInfo(LogClass.Application, "Loading as XCI."); + _device.LoadXci(path); + break; + case ".nca": + Logger.PrintInfo(LogClass.Application, "Loading as NCA."); + _device.LoadNca(path); + break; + case ".nsp": + case ".pfs0": + Logger.PrintInfo(LogClass.Application, "Loading as NSP."); + _device.LoadNsp(path); + break; + default: + Logger.PrintInfo(LogClass.Application, "Loading as homebrew."); + try + { + _device.LoadProgram(path); + } + catch (ArgumentOutOfRangeException) + { + Logger.PrintError(LogClass.Application, $"The file which you have specified is unsupported by Ryujinx"); + } + break; + } + } + else + { + Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file"); + End(); + } + + new Thread(new ThreadStart(CreateGameWindow)).Start(); + + _gameLoaded = true; + _stopEmulation.Sensitive = true; + + if (DiscordIntegrationEnabled) + { + if (File.ReadAllLines(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "RPsupported.dat")).Contains(_device.System.TitleID)) + { + DiscordPresence.Assets.LargeImageKey = _device.System.TitleID; + } + + string state = _device.System.TitleID; + + if (state == null) + { + state = "Ryujinx"; + } + else + { + state = state.ToUpper(); + } + + string details = "Idling"; + + if (_device.System.TitleName != null) + { + details = $"Playing {_device.System.TitleName}"; + } + + DiscordPresence.Details = details; + DiscordPresence.State = state; + DiscordPresence.Assets.LargeImageText = _device.System.TitleName; + DiscordPresence.Assets.SmallImageKey = "ryujinx"; + DiscordPresence.Assets.SmallImageText = "Ryujinx is an emulator for the Nintendo Switch"; + DiscordPresence.Timestamps = new Timestamps(DateTime.UtcNow); + + DiscordClient.SetPresence(DiscordPresence); + } + + try + { + string savePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "nand", "user", "save", "0000000000000000", _userId, _device.System.TitleID); + + if (File.Exists(System.IO.Path.Combine(savePath, "TimePlayed.dat")) == false) + { + Directory.CreateDirectory(savePath); + using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "TimePlayed.dat"))) + { + stream.Write(Encoding.ASCII.GetBytes("0")); + } + } + + if (File.Exists(System.IO.Path.Combine(savePath, "LastPlayed.dat")) == false) + { + Directory.CreateDirectory(savePath); + using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "LastPlayed.dat"))) + { + stream.Write(Encoding.ASCII.GetBytes("Never")); + } + } + + using (FileStream stream = File.OpenWrite(System.IO.Path.Combine(savePath, "LastPlayed.dat"))) + { + using (StreamWriter writer = new StreamWriter(stream)) + { + writer.WriteLine(DateTime.UtcNow); + } + } + } + catch (ArgumentNullException) + { + Logger.PrintWarning(LogClass.Application, $"Could not access save path to retrieve time/last played data using: UserID: {_userId}, TitleID: {_device.System.TitleID}"); + } + } + } + + private static void CreateGameWindow() + { + Configuration.ConfigureHid(_device, SwitchSettings.SwitchConfig); + + using (GlScreen screen = new GlScreen(_device, _renderer)) + { + screen.MainLoop(); + + End(); + } + } + + private static void End() + { + if (_gameLoaded) + { + try + { + string savePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "nand", "user", "save", "0000000000000000", _userId, _device.System.TitleID); + double currentPlayTime = 0; + + using (FileStream stream = File.OpenRead(System.IO.Path.Combine(savePath, "LastPlayed.dat"))) + { + using (StreamReader reader = new StreamReader(stream)) + { + DateTime startTime = DateTime.Parse(reader.ReadLine()); + + using (FileStream lastPlayedStream = File.OpenRead(System.IO.Path.Combine(savePath, "TimePlayed.dat"))) + { + using (StreamReader lastPlayedReader = new StreamReader(lastPlayedStream)) + { + currentPlayTime = double.Parse(lastPlayedReader.ReadLine()); + } + } + + using (FileStream timePlayedStream = File.OpenWrite(System.IO.Path.Combine(savePath, "TimePlayed.dat"))) + { + using (StreamWriter timePlayedWriter = new StreamWriter(timePlayedStream)) + { + timePlayedWriter.WriteLine(currentPlayTime + Math.Round(DateTime.UtcNow.Subtract(startTime).TotalSeconds, MidpointRounding.AwayFromZero)); + } + } + } + } + } + catch (ArgumentNullException) + { + Logger.PrintWarning(LogClass.Application, $"Could not access save path to retrieve time/last played data using: UserID: {_userId}, TitleID: {_device.System.TitleID}"); + } + } + + Profile.FinishProfiling(); + _device.Dispose(); + _audioOut.Dispose(); + DiscordClient.Dispose(); + Logger.Shutdown(); + Environment.Exit(0); + } + + /// + /// Picks an audio output renderer supported on this machine + /// + /// An supported by this machine + private static IAalOutput InitializeAudioEngine() + { + if (SoundIoAudioOut.IsSupported) + { + return new SoundIoAudioOut(); + } + else if (OpenALAudioOut.IsSupported) + { + return new OpenALAudioOut(); + } + else + { + return new DummyAudioOut(); + } + } + + //Events + private void Row_Activated(object o, RowActivatedArgs args) + { + _tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path.ToString())); + string path = (string)_tableStore.GetValue(treeIter, 8); + + LoadApplication(path); + } + + private void Load_Application_File(object o, EventArgs args) + { + FileChooserDialog fileChooser = new FileChooserDialog("Choose the file to open", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept); + + fileChooser.Filter = new FileFilter(); + fileChooser.Filter.AddPattern("*.nsp" ); + fileChooser.Filter.AddPattern("*.pfs0"); + fileChooser.Filter.AddPattern("*.xci" ); + fileChooser.Filter.AddPattern("*.nca" ); + fileChooser.Filter.AddPattern("*.nro" ); + fileChooser.Filter.AddPattern("*.nso" ); + + if (fileChooser.Run() == (int)ResponseType.Accept) + { + LoadApplication(fileChooser.Filename); + } + + fileChooser.Destroy(); + } + + private void Load_Application_Folder(object o, EventArgs args) + { + FileChooserDialog fileChooser = new FileChooserDialog("Choose the folder to open", this, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept); + + if (fileChooser.Run() == (int)ResponseType.Accept) + { + LoadApplication(fileChooser.Filename); + } + + fileChooser.Destroy(); + } + + private void Open_Ryu_Folder(object o, EventArgs args) + { + Process.Start(new ProcessStartInfo() + { + FileName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs"), + UseShellExecute = true, + Verb = "open" + }); + } + + private void Exit_Pressed(object o, EventArgs args) + { + End(); + } + + private void Window_Close(object o, DeleteEventArgs args) + { + End(); + } + + private void StopEmulation_Pressed(object o, EventArgs args) + { + // TODO: Write logic to kill running game + } + + private void FullScreen_Toggled(object o, EventArgs args) + { + if (_fullScreen.Active) + { + Fullscreen(); + } + else + { + Unfullscreen(); + } + } + + private void Settings_Pressed(object o, EventArgs args) + { + SwitchSettings SettingsWin = new SwitchSettings(_device); + + _gtkApplication.Register(GLib.Cancellable.Current); + _gtkApplication.AddWindow(SettingsWin); + + SettingsWin.Show(); + } + + private void Update_Pressed(object o, EventArgs args) + { + string ryuUpdater = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFS", "RyuUpdater.exe"); + + try + { + Process.Start(new ProcessStartInfo(ryuUpdater, "/U") { UseShellExecute = true }); + } + catch(System.ComponentModel.Win32Exception) + { + CreateErrorDialog("Update canceled by user or updater was not found"); + } + } + + private void About_Pressed(object o, EventArgs args) + { + AboutWindow AboutWin = new AboutWindow(); + + _gtkApplication.Register(GLib.Cancellable.Current); + _gtkApplication.AddWindow(AboutWin); + + AboutWin.Show(); + } + + private void Icon_Toggled(object o, EventArgs args) + { + SwitchSettings.SwitchConfig.GuiColumns[0] = _iconToggle.Active; + + Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } + + private void Title_Toggled(object o, EventArgs args) + { + SwitchSettings.SwitchConfig.GuiColumns[1] = _titleToggle.Active; + + Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } + + private void Developer_Toggled(object o, EventArgs args) + { + SwitchSettings.SwitchConfig.GuiColumns[2] = _developerToggle.Active; + + Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } + + private void Version_Toggled(object o, EventArgs args) + { + SwitchSettings.SwitchConfig.GuiColumns[3] = _versionToggle.Active; + + Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } + + private void TimePlayed_Toggled(object o, EventArgs args) + { + SwitchSettings.SwitchConfig.GuiColumns[4] = _timePlayedToggle.Active; + + Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } + + private void LastPlayed_Toggled(object o, EventArgs args) + { + SwitchSettings.SwitchConfig.GuiColumns[5] = _lastPlayedToggle.Active; + + Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } + + private void FileExt_Toggled(object o, EventArgs args) + { + SwitchSettings.SwitchConfig.GuiColumns[6] = _fileExtToggle.Active; + + Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } + + private void FileSize_Toggled(object o, EventArgs args) + { + SwitchSettings.SwitchConfig.GuiColumns[7] = _fileSizeToggle.Active; + + Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } + + private void Path_Toggled(object o, EventArgs args) + { + SwitchSettings.SwitchConfig.GuiColumns[8] = _pathToggle.Active; + + Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } + } +} diff --git a/Ryujinx/Ui/MainWindow.glade b/Ryujinx/Ui/MainWindow.glade new file mode 100644 index 000000000..e12a7b1bb --- /dev/null +++ b/Ryujinx/Ui/MainWindow.glade @@ -0,0 +1,347 @@ + + + + + + False + Ryujinx + center + 1280 + 750 + + + + + + True + False + vertical + + + True + False + + + True + False + File + True + + + True + False + + + True + False + Open a file chooser to chose a switch compatible file to load + Load Application from File + True + + + + + + True + False + Open a file chooser to chose a switch compatible, unpacked application to load + Load Unpacked Game + True + + + + + + True + False + + + + + True + False + Open Ryujinx filesystem folder + Open Ryujinx Folder + True + + + + + + True + False + + + + + True + False + Exit Ryujinx + Exit + True + + + + + + + + + + True + False + Options + True + + + True + False + + + True + False + Fullscreens the window + Fullscreen + True + + + + + + True + False + Stop emualtion of the current game and return to game selection + Stop Emulation + True + + + + + + True + False + + + + + True + False + Select which GUI columns to enable (restart Ryujinx for these changes to take effect) + Enable GUI Columns + True + + + True + False + + + True + False + Enable or Disable Icon Column in the game list + Enable Icon Column + True + + + + + + True + False + Enable or Disable Title Name/ID Column in the game list + Enable Title Name/ID Column + True + + + + + + True + False + Enable or Disable Developer Column in the game list + Enable Developer Column + True + + + + + + True + False + Enable or Disable Version Column in the game list + Enable Version Column + True + + + + + + True + False + Enable or Disable Time Played Column in the game list + Enable Time Played Column + True + + + + + + True + False + Enable or Disable Last Played Column in the game list + Enable Last Played Column + True + + + + + + True + False + Enable or Disable file extension column in the game list + Enable File Ext Column + True + + + + + + True + False + Enable or Disable File Size Column in the game list + Enable File Size Column + True + + + + + + True + False + Enable or Disable Path Column in the game list + Enable Path Column + True + + + + + + + + + + True + False + + + + + True + False + Open settings window + Settings + True + + + + + + + + + + True + False + Tools + True + + + + + True + False + Help + True + + + True + False + + + True + False + Check for updates to Ryujinx (requires Ryujinx Installer) + Check for Updates + True + + + + + + True + False + + + + + True + False + Open about window + About + True + + + + + + + + + + False + True + 0 + + + + + True + True + in + + + True + True + False + True + True + + + + + + + + + True + True + 1 + + + + + 1280 + 720 + True + True + False + + + True + True + 2 + + + + + + diff --git a/Ryujinx/Ui/NpadKeyboard.cs b/Ryujinx/Ui/NpadKeyboard.cs index 79d6330c6..ac739c086 100644 --- a/Ryujinx/Ui/NpadKeyboard.cs +++ b/Ryujinx/Ui/NpadKeyboard.cs @@ -45,12 +45,12 @@ namespace Ryujinx.UI.Input /// /// Left JoyCon Keyboard Bindings /// - public NpadKeyboardLeft LeftJoycon { get; private set; } + public NpadKeyboardLeft LeftJoycon { get; set; } /// /// Right JoyCon Keyboard Bindings /// - public NpadKeyboardRight RightJoycon { get; private set; } + public NpadKeyboardRight RightJoycon { get; set; } /// /// Hotkey Keyboard Bindings diff --git a/Ryujinx/Ui/SwitchSettings.cs b/Ryujinx/Ui/SwitchSettings.cs new file mode 100644 index 000000000..8f42fcbf9 --- /dev/null +++ b/Ryujinx/Ui/SwitchSettings.cs @@ -0,0 +1,424 @@ +using Gtk; +using GUI = Gtk.Builder.ObjectAttribute; +using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Input; +using Ryujinx.UI.Input; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Ryujinx.UI +{ + public class SwitchSettings : Window + { + internal static Configuration SwitchConfig { get; set; } + + internal HLE.Switch Device { get; set; } + + private static ListStore _gameDirsBoxStore; + + private static bool _listeningForKeypress; + +#pragma warning disable 649 + [GUI] Window _settingsWin; + [GUI] CheckButton _errorLogToggle; + [GUI] CheckButton _warningLogToggle; + [GUI] CheckButton _infoLogToggle; + [GUI] CheckButton _stubLogToggle; + [GUI] CheckButton _debugLogToggle; + [GUI] CheckButton _fileLogToggle; + [GUI] CheckButton _guestLogToggle; + [GUI] CheckButton _fsAccessLogToggle; + [GUI] Adjustment _fsLogSpinAdjustment; + [GUI] CheckButton _dockedModeToggle; + [GUI] CheckButton _discordToggle; + [GUI] CheckButton _vSyncToggle; + [GUI] CheckButton _multiSchedToggle; + [GUI] CheckButton _fsicToggle; + [GUI] CheckButton _legacyJitToggle; + [GUI] CheckButton _ignoreToggle; + [GUI] CheckButton _directKeyboardAccess; + [GUI] ComboBoxText _systemLanguageSelect; + [GUI] CheckButton _custThemeToggle; + [GUI] Entry _custThemePath; + [GUI] ToggleButton _browseThemePath; + [GUI] Label _custThemePathLabel; + [GUI] TreeView _gameDirsBox; + [GUI] Entry _addGameDirBox; + [GUI] ToggleButton _addDir; + [GUI] ToggleButton _browseDir; + [GUI] ToggleButton _removeDir; + [GUI] Entry _logPath; + [GUI] Entry _graphicsShadersDumpPath; + [GUI] Image _controllerImage; + + [GUI] ComboBoxText _controller1Type; + [GUI] ToggleButton _lStickUp1; + [GUI] ToggleButton _lStickDown1; + [GUI] ToggleButton _lStickLeft1; + [GUI] ToggleButton _lStickRight1; + [GUI] ToggleButton _lStickButton1; + [GUI] ToggleButton _dpadUp1; + [GUI] ToggleButton _dpadDown1; + [GUI] ToggleButton _dpadLeft1; + [GUI] ToggleButton _dpadRight1; + [GUI] ToggleButton _minus1; + [GUI] ToggleButton _l1; + [GUI] ToggleButton _zL1; + [GUI] ToggleButton _rStickUp1; + [GUI] ToggleButton _rStickDown1; + [GUI] ToggleButton _rStickLeft1; + [GUI] ToggleButton _rStickRight1; + [GUI] ToggleButton _rStickButton1; + [GUI] ToggleButton _a1; + [GUI] ToggleButton _b1; + [GUI] ToggleButton _x1; + [GUI] ToggleButton _y1; + [GUI] ToggleButton _plus1; + [GUI] ToggleButton _r1; + [GUI] ToggleButton _zR1; +#pragma warning restore 649 + + public static void ConfigureSettings(Configuration Instance) { SwitchConfig = Instance; } + + public SwitchSettings(HLE.Switch device) : this(new Builder("Ryujinx.Ui.SwitchSettings.glade"), device) { } + + private SwitchSettings(Builder builder, HLE.Switch device) : base(builder.GetObject("_settingsWin").Handle) + { + Device = device; + + builder.Autoconnect(this); + + _settingsWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.RyujinxIcon.png"); + _controllerImage.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyCon.png", 500, 500); + + //Bind Events + _lStickUp1.Clicked += (o, args) => Button_Pressed(o, args, _lStickUp1); + _lStickDown1.Clicked += (o, args) => Button_Pressed(o, args, _lStickDown1); + _lStickLeft1.Clicked += (o, args) => Button_Pressed(o, args, _lStickLeft1); + _lStickRight1.Clicked += (o, args) => Button_Pressed(o, args, _lStickRight1); + _lStickButton1.Clicked += (o, args) => Button_Pressed(o, args, _lStickButton1); + _dpadUp1.Clicked += (o, args) => Button_Pressed(o, args, _dpadUp1); + _dpadDown1.Clicked += (o, args) => Button_Pressed(o, args, _dpadDown1); + _dpadLeft1.Clicked += (o, args) => Button_Pressed(o, args, _dpadLeft1); + _dpadRight1.Clicked += (o, args) => Button_Pressed(o, args, _dpadRight1); + _minus1.Clicked += (o, args) => Button_Pressed(o, args, _minus1); + _l1.Clicked += (o, args) => Button_Pressed(o, args, _l1); + _zL1.Clicked += (o, args) => Button_Pressed(o, args, _zL1); + _rStickUp1.Clicked += (o, args) => Button_Pressed(o, args, _rStickUp1); + _rStickDown1.Clicked += (o, args) => Button_Pressed(o, args, _rStickDown1); + _rStickLeft1.Clicked += (o, args) => Button_Pressed(o, args, _rStickLeft1); + _rStickRight1.Clicked += (o, args) => Button_Pressed(o, args, _rStickRight1); + _rStickButton1.Clicked += (o, args) => Button_Pressed(o, args, _rStickButton1); + _a1.Clicked += (o, args) => Button_Pressed(o, args, _a1); + _b1.Clicked += (o, args) => Button_Pressed(o, args, _b1); + _x1.Clicked += (o, args) => Button_Pressed(o, args, _x1); + _y1.Clicked += (o, args) => Button_Pressed(o, args, _y1); + _plus1.Clicked += (o, args) => Button_Pressed(o, args, _plus1); + _r1.Clicked += (o, args) => Button_Pressed(o, args, _r1); + _zR1.Clicked += (o, args) => Button_Pressed(o, args, _zR1); + + //Setup Currents + if (SwitchConfig.EnableFileLog) { _fileLogToggle.Click(); } + if (SwitchConfig.LoggingEnableError) { _errorLogToggle.Click(); } + if (SwitchConfig.LoggingEnableWarn) { _warningLogToggle.Click(); } + if (SwitchConfig.LoggingEnableInfo) { _infoLogToggle.Click(); } + if (SwitchConfig.LoggingEnableStub) { _stubLogToggle.Click(); } + if (SwitchConfig.LoggingEnableDebug) { _debugLogToggle.Click(); } + if (SwitchConfig.LoggingEnableGuest) { _guestLogToggle.Click(); } + if (SwitchConfig.LoggingEnableFsAccessLog) { _fsAccessLogToggle.Click(); } + if (SwitchConfig.DockedMode) { _dockedModeToggle.Click(); } + if (SwitchConfig.EnableDiscordIntegration) { _discordToggle.Click(); } + if (SwitchConfig.EnableVsync) { _vSyncToggle.Click(); } + if (SwitchConfig.EnableMulticoreScheduling) { _multiSchedToggle.Click(); } + if (SwitchConfig.EnableFsIntegrityChecks) { _fsicToggle.Click(); } + if (SwitchConfig.EnableLegacyJit) { _legacyJitToggle.Click(); } + if (SwitchConfig.IgnoreMissingServices) { _ignoreToggle.Click(); } + if (SwitchConfig.EnableKeyboard) { _directKeyboardAccess.Click(); } + if (SwitchConfig.EnableCustomTheme) { _custThemeToggle.Click(); } + + _systemLanguageSelect.SetActiveId(SwitchConfig.SystemLanguage.ToString()); + _controller1Type .SetActiveId(SwitchConfig.ControllerType.ToString()); + + _lStickUp1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickUp.ToString(); + _lStickDown1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickDown.ToString(); + _lStickLeft1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickLeft.ToString(); + _lStickRight1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickRight.ToString(); + _lStickButton1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickButton.ToString(); + _dpadUp1.Label = SwitchConfig.KeyboardControls.LeftJoycon.DPadUp.ToString(); + _dpadDown1.Label = SwitchConfig.KeyboardControls.LeftJoycon.DPadDown.ToString(); + _dpadLeft1.Label = SwitchConfig.KeyboardControls.LeftJoycon.DPadLeft.ToString(); + _dpadRight1.Label = SwitchConfig.KeyboardControls.LeftJoycon.DPadRight.ToString(); + _minus1.Label = SwitchConfig.KeyboardControls.LeftJoycon.ButtonMinus.ToString(); + _l1.Label = SwitchConfig.KeyboardControls.LeftJoycon.ButtonL.ToString(); + _zL1.Label = SwitchConfig.KeyboardControls.LeftJoycon.ButtonZl.ToString(); + _rStickUp1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickUp.ToString(); + _rStickDown1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickDown.ToString(); + _rStickLeft1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickLeft.ToString(); + _rStickRight1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickRight.ToString(); + _rStickButton1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickButton.ToString(); + _a1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonA.ToString(); + _b1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonB.ToString(); + _x1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonX.ToString(); + _y1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonY.ToString(); + _plus1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonPlus.ToString(); + _r1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonR.ToString(); + _zR1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonZr.ToString(); + + _custThemePath.Buffer.Text = SwitchConfig.CustomThemePath; + _graphicsShadersDumpPath.Buffer.Text = SwitchConfig.GraphicsShadersDumpPath; + _fsLogSpinAdjustment.Value = SwitchConfig.FsGlobalAccessLogMode; + + _gameDirsBox.AppendColumn("", new CellRendererText(), "text", 0); + _gameDirsBoxStore = new ListStore(typeof(string)); + _gameDirsBox.Model = _gameDirsBoxStore; + foreach (string gameDir in SwitchConfig.GameDirs) + { + _gameDirsBoxStore.AppendValues(gameDir); + } + + if (_custThemeToggle.Active == false) + { + _custThemePath.Sensitive = false; + _custThemePathLabel.Sensitive = false; + _browseThemePath.Sensitive = false; + } + + _logPath.Buffer.Text = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.log"); + + _listeningForKeypress = false; + } + + //Events + private void Button_Pressed(object obj, EventArgs args, ToggleButton Button) + { + if (_listeningForKeypress == false) + { + KeyPressEvent += On_KeyPress; + + _listeningForKeypress = true; + + void On_KeyPress(object Obj, KeyPressEventArgs KeyPressed) + { + string key = KeyPressed.Event.Key.ToString(); + string capKey = key.First().ToString().ToUpper() + key.Substring(1); + + if (Enum.IsDefined(typeof(OpenTK.Input.Key), capKey)) + { + Button.Label = capKey; + } + else if (GdkToOpenTKInput.ContainsKey(key)) + { + Button.Label = GdkToOpenTKInput[key]; + } + else + { + Button.Label = "Space"; + } + + Button.SetStateFlags(0, true); + + KeyPressEvent -= On_KeyPress; + + _listeningForKeypress = false; + } + } + else + { + Button.SetStateFlags(0, true); + } + } + + private void AddDir_Pressed(object obj, EventArgs args) + { + if (Directory.Exists(_addGameDirBox.Buffer.Text)) + { + _gameDirsBoxStore.AppendValues(_addGameDirBox.Buffer.Text); + } + + _addDir.SetStateFlags(0, true); + } + + private void BrowseDir_Pressed(object obj, EventArgs args) + { + FileChooserDialog fileChooser = new FileChooserDialog("Choose the game directory to add to the list", this, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Add", ResponseType.Accept); + + if (fileChooser.Run() == (int)ResponseType.Accept) + { + _gameDirsBoxStore.AppendValues(fileChooser.Filename); + } + + fileChooser.Destroy(); + + _browseDir.SetStateFlags(0, true); + } + + private void RemoveDir_Pressed(object obj, EventArgs args) + { + TreeSelection selection = _gameDirsBox.Selection; + + selection.GetSelected(out TreeIter treeIter); + _gameDirsBoxStore.Remove(ref treeIter); + + _removeDir.SetStateFlags(0, true); + } + + private void CustThemeToggle_Activated(object obj, EventArgs args) + { + _custThemePath.Sensitive = _custThemeToggle.Active; + _custThemePathLabel.Sensitive = _custThemeToggle.Active; + _browseThemePath.Sensitive = _custThemeToggle.Active; + } + + private void BrowseThemeDir_Pressed(object obj, EventArgs args) + { + FileChooserDialog fileChooser = new FileChooserDialog("Choose the theme to load", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Select", ResponseType.Accept); + + fileChooser.Filter = new FileFilter(); + fileChooser.Filter.AddPattern("*.css"); + + if (fileChooser.Run() == (int)ResponseType.Accept) + { + _custThemePath.Buffer.Text = fileChooser.Filename; + } + + fileChooser.Destroy(); + + _browseThemePath.SetStateFlags(0, true); + } + + private void SaveToggle_Activated(object obj, EventArgs args) + { + List gameDirs = new List(); + + _gameDirsBoxStore.GetIterFirst(out TreeIter treeIter); + for (int i = 0; i < _gameDirsBoxStore.IterNChildren(); i++) + { + _gameDirsBoxStore.GetValue(treeIter, i); + + gameDirs.Add((string)_gameDirsBoxStore.GetValue(treeIter, 0)); + + _gameDirsBoxStore.IterNext(ref treeIter); + } + + SwitchConfig.LoggingEnableError = _errorLogToggle.Active; + SwitchConfig.LoggingEnableWarn = _warningLogToggle.Active; + SwitchConfig.LoggingEnableInfo = _infoLogToggle.Active; + SwitchConfig.LoggingEnableStub = _stubLogToggle.Active; + SwitchConfig.LoggingEnableDebug = _debugLogToggle.Active; + SwitchConfig.LoggingEnableGuest = _guestLogToggle.Active; + SwitchConfig.LoggingEnableFsAccessLog = _fsAccessLogToggle.Active; + SwitchConfig.EnableFileLog = _fileLogToggle.Active; + SwitchConfig.DockedMode = _dockedModeToggle.Active; + SwitchConfig.EnableDiscordIntegration = _discordToggle.Active; + SwitchConfig.EnableVsync = _vSyncToggle.Active; + SwitchConfig.EnableMulticoreScheduling = _multiSchedToggle.Active; + SwitchConfig.EnableFsIntegrityChecks = _fsicToggle.Active; + SwitchConfig.EnableLegacyJit = _legacyJitToggle.Active; + SwitchConfig.IgnoreMissingServices = _ignoreToggle.Active; + SwitchConfig.EnableKeyboard = _directKeyboardAccess.Active; + SwitchConfig.EnableCustomTheme = _custThemeToggle.Active; + + SwitchConfig.KeyboardControls.LeftJoycon = new NpadKeyboardLeft() + { + StickUp = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _lStickUp1.Label), + StickDown = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _lStickDown1.Label), + StickLeft = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _lStickLeft1.Label), + StickRight = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _lStickRight1.Label), + StickButton = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _lStickButton1.Label), + DPadUp = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _dpadUp1.Label), + DPadDown = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _dpadDown1.Label), + DPadLeft = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _dpadLeft1.Label), + DPadRight = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _dpadRight1.Label), + ButtonMinus = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _minus1.Label), + ButtonL = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _l1.Label), + ButtonZl = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _zL1.Label), + }; + + SwitchConfig.KeyboardControls.RightJoycon = new NpadKeyboardRight() + { + StickUp = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _rStickUp1.Label), + StickDown = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _rStickDown1.Label), + StickLeft = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _rStickLeft1.Label), + StickRight = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _rStickRight1.Label), + StickButton = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _rStickButton1.Label), + ButtonA = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _a1.Label), + ButtonB = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _b1.Label), + ButtonX = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _x1.Label), + ButtonY = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _y1.Label), + ButtonPlus = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _plus1.Label), + ButtonR = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _r1.Label), + ButtonZr = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _zR1.Label), + }; + + SwitchConfig.SystemLanguage = (SystemLanguage)Enum.Parse(typeof(SystemLanguage), _systemLanguageSelect.ActiveId); + SwitchConfig.ControllerType = (ControllerStatus)Enum.Parse(typeof(ControllerStatus), _controller1Type.ActiveId); + SwitchConfig.CustomThemePath = _custThemePath.Buffer.Text; + SwitchConfig.GraphicsShadersDumpPath = _graphicsShadersDumpPath.Buffer.Text; + SwitchConfig.GameDirs = gameDirs; + SwitchConfig.FsGlobalAccessLogMode = (int)_fsLogSpinAdjustment.Value; + + Configuration.SaveConfig(SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + Configuration.Configure(Device, SwitchConfig); + + MainWindow.ApplyTheme(); + MainWindow.UpdateGameTable(); + + Destroy(); + } + + private void CloseToggle_Activated(object obj, EventArgs args) + { + Destroy(); + } + + public readonly Dictionary GdkToOpenTKInput = new Dictionary() + { + { "Key_0", "Number0" }, + { "Key_1", "Number1" }, + { "Key_2", "Number2" }, + { "Key_3", "Number3" }, + { "Key_4", "Number4" }, + { "Key_5", "Number5" }, + { "Key_6", "Number6" }, + { "Key_7", "Number7" }, + { "Key_8", "Number8" }, + { "Key_9", "Number9" }, + { "equal", "Plus" }, + { "uparrow", "Up" }, + { "downarrow", "Down" }, + { "leftarrow", "Left" }, + { "rightarrow", "Right" }, + { "Control_L", "ControlLeft" }, + { "Control_R", "ControlRight" }, + { "Shift_L", "ShiftLeft" }, + { "Shift_R", "ShiftRight" }, + { "Alt_L", "AltLeft" }, + { "Alt_R", "AltRight" }, + { "Page_Up", "PageUp" }, + { "Page_Down", "PageDown" }, + { "KP_Enter", "KeypadEnter" }, + { "KP_Up", "Up" }, + { "KP_Down", "Down" }, + { "KP_Left", "Left" }, + { "KP_Right", "Right" }, + { "KP_Divide", "KeypadDivide" }, + { "KP_Multiply", "KeypadMultiply" }, + { "KP_Subtract", "KeypadSubtract" }, + { "KP_Add", "KeypadAdd" }, + { "KP_Decimal", "KeypadDecimal" }, + { "KP_0", "Keypad0" }, + { "KP_1", "Keypad1" }, + { "KP_2", "Keypad2" }, + { "KP_3", "Keypad3" }, + { "KP_4", "Keypad4" }, + { "KP_5", "Keypad5" }, + { "KP_6", "Keypad6" }, + { "KP_7", "Keypad7" }, + { "KP_8", "Keypad8" }, + { "KP_9", "Keypad9" }, + }; + } +} diff --git a/Ryujinx/Ui/SwitchSettings.glade b/Ryujinx/Ui/SwitchSettings.glade new file mode 100644 index 000000000..30a689a88 --- /dev/null +++ b/Ryujinx/Ui/SwitchSettings.glade @@ -0,0 +1,1989 @@ + + + + + + 3 + 1 + 10 + + + False + Ryujinx - Settings + True + center + 910 + 790 + dialog + + + + + + False + vertical + 2 + + + False + 5 + 3 + 3 + end + + + Save + True + True + True + + + + False + True + 0 + + + + + Close + True + True + True + + + + False + True + 5 + 1 + + + + + False + False + 0 + + + + + True + True + in + + + True + False + + + True + True + + + True + False + 5 + 10 + 5 + vertical + + + True + False + 5 + 5 + vertical + + + True + False + start + 5 + General + + + + + + False + True + 0 + + + + + True + False + vertical + + + True + False + + + True + False + Change System Language + end + System Language: + + + False + True + 0 + + + + + True + False + Change System Language + + American English + British English + Canadian French + Chinese + Dutch + French + German + Italian + Japanese + Korean + Latin American Spanish + Portuguese + Russian + Simplified Chinese + Spanish + Taiwanese + Traditional Chinese + + + + False + True + 1 + + + + + False + True + 0 + + + + + Enable Discord Integration + True + True + False + Enables or disables Discord Rich Presense + start + True + + + False + True + 5 + 1 + + + + + True + True + 1 + + + + + False + True + 5 + 1 + + + + + True + False + 5 + 5 + + + False + True + 5 + 2 + + + + + True + False + 5 + 5 + vertical + + + True + False + start + 5 + Game Directories + + + + + + False + True + 0 + + + + + True + False + 10 + 10 + vertical + + + True + True + 10 + in + + + True + True + False + False + + + + + + + + + True + True + 0 + + + + + True + False + + + True + True + Enter a game directroy to add to the list + + + True + True + 0 + + + + + Add + 80 + True + True + True + Add a game directory to the list + 5 + + + + False + True + 1 + + + + + Browse... + 80 + True + True + True + Browse for a game directory + 5 + + + + False + True + 2 + + + + + Remove + 80 + True + True + True + Remove selected game directory + 5 + + + + False + True + 3 + + + + + False + True + 1 + + + + + True + True + 1 + + + + + True + True + 5 + 4 + + + + + True + False + 5 + 5 + + + False + True + 5 + 5 + + + + + True + False + 5 + 5 + vertical + + + True + False + start + 5 + Themes + + + + + + False + True + 0 + + + + + True + False + 10 + 10 + vertical + + + Use Custom Theme + True + True + False + Enable or disable custom themes in the GUI + start + True + + + + False + True + 5 + 1 + + + + + True + False + + + True + False + Path to custom GUI theme + Custom Theme Path: + + + False + True + 5 + 0 + + + + + True + True + Path to custom GUI theme + center + + + True + True + 1 + + + + + Browse... + 80 + True + True + True + Browse for a custom GUI theme + 5 + + + + False + True + 2 + + + + + False + True + 10 + 2 + + + + + False + True + 1 + + + + + False + True + 5 + 6 + + + + + + + True + False + General + + + False + + + + + True + False + vertical + + + True + False + 5 + 10 + + + Enable Docked Mode + True + True + False + Enable or disable Docked Mode + True + + + False + True + 10 + 0 + + + + + Direct Keyboard Access + True + True + False + Enable or disable "direct keyboard access (HID) support" (Provides games access to your keyboard as a text entry device) + True + + + False + False + 10 + 1 + + + + + False + True + 5 + 0 + + + + + True + True + + + True + False + 5 + 5 + 5 + 5 + + + True + False + vertical + + + True + False + + + True + False + The primary controller's type + center + 10 + 10 + 5 + 5 + Controller Type: + + + False + True + 0 + + + + + True + False + The primary controller's type + 5 + 0 + + Handheld + Pro Controller + Paired Joycons + Left Joycon + Right Joycon + + + + True + True + 1 + + + + + True + True + 10 + 0 + + + + + True + False + 2 + 5 + + + True + False + LStick Up + + + 0 + 0 + + + + + True + False + LStick Down + + + 0 + 1 + + + + + True + False + LStick Left + + + 0 + 2 + + + + + True + False + LStick Right + + + 0 + 3 + + + + + True + False + LStick Button + + + 0 + 4 + + + + + True + False + Dpad Up + + + 0 + 5 + + + + + True + False + Dpad Down + + + 0 + 6 + + + + + True + False + Dpad Left + + + 0 + 7 + + + + + True + False + Dpad Right + + + 0 + 8 + + + + + True + False + - + + + 0 + 9 + + + + + True + False + L + + + 0 + 10 + + + + + True + False + ZL + + + 0 + 11 + + + + + True + False + ZR + + + 2 + 11 + + + + + True + False + R + + + 2 + 10 + + + + + True + False + + + + + 2 + 9 + + + + + True + False + Y + + + 2 + 8 + + + + + True + False + X + + + 2 + 7 + + + + + True + False + B + + + 2 + 6 + + + + + True + False + A + + + 2 + 5 + + + + + True + False + RStick Button + + + 2 + 4 + + + + + True + False + RStick Right + + + 2 + 3 + + + + + True + False + RStick Left + + + 2 + 2 + + + + + True + False + RStick Down + + + 2 + 1 + + + + + True + False + RStick Up + + + 2 + 0 + + + + + + True + True + True + + + 1 + 0 + + + + + + True + True + True + + + 1 + 1 + + + + + + True + True + True + + + 1 + 2 + + + + + + True + True + True + + + 1 + 3 + + + + + + True + True + True + + + 1 + 4 + + + + + + True + True + True + + + 1 + 5 + + + + + + True + True + True + + + 1 + 6 + + + + + + True + True + True + + + 1 + 7 + + + + + + True + True + True + + + 1 + 8 + + + + + + True + True + True + + + 1 + 9 + + + + + + True + True + True + + + 1 + 10 + + + + + + True + True + True + + + 1 + 11 + + + + + + True + True + True + + + 3 + 0 + + + + + + True + True + True + + + 3 + 1 + + + + + + True + True + True + + + 3 + 2 + + + + + + True + True + True + + + 3 + 3 + + + + + + True + True + True + + + 3 + 4 + + + + + + True + True + True + + + 3 + 5 + + + + + + True + True + True + + + 3 + 6 + + + + + + True + True + True + + + 3 + 7 + + + + + + True + True + True + + + 3 + 8 + + + + + + True + True + True + + + 3 + 9 + + + + + + True + True + True + + + 3 + 10 + + + + + + True + True + True + + + 3 + 11 + + + + + False + True + 10 + 1 + + + + + False + True + 0 + + + + + True + False + 5 + + + True + True + 1 + + + + + + + True + False + Controller 1 + + + False + + + + + True + False + Multiple controllers are not yet supported + + + 1 + True + + + + + True + False + Controller 2 + + + 1 + False + + + + + True + False + Multiple controllers are not yet supported + + + 2 + + + + + True + False + Controller 3 + + + 2 + False + + + + + True + False + Multiple controllers are not yet supported + + + 3 + + + + + True + False + Controller 4 + + + 3 + False + + + + + True + False + Multiple controllers are not yet supported + + + 4 + + + + + True + False + Controller 5 + + + 4 + False + + + + + True + False + Multiple controllers are not yet supported + + + 5 + + + + + True + False + Controller 6 + + + 5 + False + + + + + True + False + Multiple controllers are not yet supported + + + 6 + + + + + True + False + Controller 7 + + + 6 + False + + + + + True + False + Multiple controllers are not yet supported + + + 7 + + + + + True + False + Controller 8 + + + 7 + False + + + + + False + True + 2 + + + + + 1 + + + + + True + False + Input + + + 1 + False + + + + + True + False + 5 + 10 + 5 + vertical + + + True + False + start + 5 + 5 + vertical + + + True + False + start + 5 + 5 + Core + + + + + + False + True + 0 + + + + + True + False + 10 + 10 + vertical + + + Enable VSync + True + True + False + Enables or disables Vertical Sync + start + 5 + 5 + True + + + False + True + 0 + + + + + Enable Multicore Scheduling + True + True + False + Enables or disables multi-core scheduling of threads + start + 5 + 5 + True + + + False + True + 1 + + + + + Use old ChocolArm64 ARM emulator + True + True + False + Uses old ChocolArm64 ARM emulator rather then the new ARMeilleure + start + 5 + 5 + True + + + False + True + 2 + + + + + Enable FS Integrity Checks + True + True + False + Enables integrity checks on Game content files + start + 5 + 5 + True + + + False + True + 3 + + + + + True + False + + + True + False + Graphics Shaders Dump Path + Graphics Shaders Dump Path: + + + False + True + 5 + 0 + + + + + True + True + Graphics Shaders Dump Path + center + False + + + True + True + 1 + + + + + False + True + 5 + 4 + + + + + True + True + 1 + + + + + False + True + 5 + 0 + + + + + True + False + 5 + 5 + + + False + True + 5 + 1 + + + + + True + False + 5 + 5 + vertical + + + True + False + start + 5 + Logging + + + + + + False + True + 0 + + + + + True + False + 10 + 10 + vertical + + + Enable Logging to File + True + True + False + Enables or disables logging to a file on disk + start + 5 + 5 + True + + + False + True + 0 + + + + + True + False + 5 + 10 + + + True + False + Location of the log file + Log File Location: + + + False + True + 5 + 0 + + + + + True + True + Location of the log file + center + False + False + + + True + True + 1 + + + + + False + True + 5 + 1 + + + + + Enable Debug Logs + True + True + False + Enables printing debug log messages + start + 5 + 5 + True + + + False + True + 2 + + + + + Enable Stub Logs + True + True + False + Enables printing stub log messages + start + 5 + 5 + True + + + False + True + 3 + + + + + Enable Info Logs + True + True + False + Enables printing info log messages + start + 5 + 5 + True + + + False + True + 4 + + + + + Enable Warning Logs + True + True + False + Enables printing warning log messages + start + 5 + 5 + True + + + False + True + 5 + + + + + Enable Error Logs + True + True + False + Enables printing error log messages + start + 5 + 5 + True + + + False + True + 6 + + + + + Enable Guest Logs + True + True + False + Enables printing guest log messages + start + 5 + 5 + True + + + False + True + 7 + + + + + Enable Fs Access Logs + True + True + False + Enables printing fs access log messages + start + 5 + 5 + True + + + False + True + 8 + + + + + True + False + + + True + False + Enables FS access log output to the console. Possible modes are 0-3 + Fs Global Access Log Mode: + + + False + True + 5 + 0 + + + + + True + True + Enables FS access log output to the console. Possible modes are 0-3 + _fsLogSpinAdjustment + + + True + True + 1 + + + + + False + True + 5 + 9 + + + + + True + True + 1 + + + + + False + True + 5 + 2 + + + + + True + False + 5 + 5 + + + False + True + 5 + 3 + + + + + True + False + 5 + 5 + vertical + + + True + False + + + True + False + start + 5 + Hacks + + + + + + False + True + 0 + + + + + True + False + start + 5 + - These may cause instability + + + False + True + 1 + + + + + False + True + 1 + + + + + True + False + 10 + 10 + vertical + + + Ignore Missing Services + True + True + False + Enable or disable ignoring missing services + start + 5 + 5 + True + + + False + True + 0 + + + + + True + True + 2 + + + + + False + True + 5 + 4 + + + + + 2 + + + + + True + False + end + System + + + 2 + False + + + + + + + + + True + True + 1 + + + + + + diff --git a/Ryujinx/Ui/assets/DiscordLogo.png b/Ryujinx/Ui/assets/DiscordLogo.png new file mode 100644 index 000000000..85c46fd8d Binary files /dev/null and b/Ryujinx/Ui/assets/DiscordLogo.png differ diff --git a/Ryujinx/Ui/assets/GitHubLogo.png b/Ryujinx/Ui/assets/GitHubLogo.png new file mode 100644 index 000000000..192846a12 Binary files /dev/null and b/Ryujinx/Ui/assets/GitHubLogo.png differ diff --git a/Ryujinx/Ui/assets/JoyCon.png b/Ryujinx/Ui/assets/JoyCon.png new file mode 100644 index 000000000..ec8a8f993 Binary files /dev/null and b/Ryujinx/Ui/assets/JoyCon.png differ diff --git a/Ryujinx/Ui/assets/PatreonLogo.png b/Ryujinx/Ui/assets/PatreonLogo.png new file mode 100644 index 000000000..5b35572af Binary files /dev/null and b/Ryujinx/Ui/assets/PatreonLogo.png differ diff --git a/Ryujinx/Ui/assets/TwitterLogo.png b/Ryujinx/Ui/assets/TwitterLogo.png new file mode 100644 index 000000000..a2030bc6e Binary files /dev/null and b/Ryujinx/Ui/assets/TwitterLogo.png differ diff --git a/Ryujinx/Ui/assets/ryujinxIcon.png b/Ryujinx/Ui/assets/ryujinxIcon.png new file mode 100644 index 000000000..2fc7b0174 Binary files /dev/null and b/Ryujinx/Ui/assets/ryujinxIcon.png differ diff --git a/Ryujinx/Ui/assets/ryujinxNCAIcon.png b/Ryujinx/Ui/assets/ryujinxNCAIcon.png new file mode 100644 index 000000000..6d73c8c70 Binary files /dev/null and b/Ryujinx/Ui/assets/ryujinxNCAIcon.png differ diff --git a/Ryujinx/Ui/assets/ryujinxNROIcon.png b/Ryujinx/Ui/assets/ryujinxNROIcon.png new file mode 100644 index 000000000..bc6b65bf4 Binary files /dev/null and b/Ryujinx/Ui/assets/ryujinxNROIcon.png differ diff --git a/Ryujinx/Ui/assets/ryujinxNSOIcon.png b/Ryujinx/Ui/assets/ryujinxNSOIcon.png new file mode 100644 index 000000000..8782b3ea6 Binary files /dev/null and b/Ryujinx/Ui/assets/ryujinxNSOIcon.png differ diff --git a/Ryujinx/Ui/assets/ryujinxNSPIcon.png b/Ryujinx/Ui/assets/ryujinxNSPIcon.png new file mode 100644 index 000000000..d01dc4822 Binary files /dev/null and b/Ryujinx/Ui/assets/ryujinxNSPIcon.png differ diff --git a/Ryujinx/Ui/assets/ryujinxXCIIcon.png b/Ryujinx/Ui/assets/ryujinxXCIIcon.png new file mode 100644 index 000000000..08f783a80 Binary files /dev/null and b/Ryujinx/Ui/assets/ryujinxXCIIcon.png differ diff --git a/Ryujinx/_schema.json b/Ryujinx/_schema.json index c1a64c674..b9546a84b 100644 --- a/Ryujinx/_schema.json +++ b/Ryujinx/_schema.json @@ -494,6 +494,38 @@ false ] }, + "game_dirs": { + "$id": "#/properties/game_dirs", + "type": "string list", + "title": "List of Game Directories", + "description": "A list of directories containing games to be used to load games into the games list", + "default": [] + }, + "gui_columns": { + "$id": "#/properties/gui_columns", + "type": "bool list", + "title": "Used to toggle columns in the GUI", + "description": "Used to toggle columns in the GUI", + "default": [ true, true, true, true, true, true, true, true, true ] + }, + "enable_custom_theme": { + "$id": "#/properties/enable_custom_theme", + "type": "boolean", + "title": "Enable custom themes in the GUI", + "description": "Enable or disable custom themes in the GUI", + "default": false, + "examples": [ + true, + false + ] + }, + "custom_theme_path": { + "$id": "#/properties/custom_theme_path", + "type": "string", + "title": "Path to custom GUI theme", + "description": "Path to custom GUI theme", + "default": "" + }, "controller_type": { "$id": "#/properties/controller_type", "type": "string",