diff --git a/src/Client/ConfigWindow.java b/src/Client/ConfigWindow.java index f14aab37..811426b6 100644 --- a/src/Client/ConfigWindow.java +++ b/src/Client/ConfigWindow.java @@ -243,6 +243,7 @@ public class ConfigWindow { private JCheckBox generalPanelLogTimestampsCheckbox; private JCheckBox generalPanelLogForceLevelCheckbox; private JCheckBox generalPanelPrefersXdgOpenCheckbox; + private JCheckBox generalPanelMacOSConfirmQuitCheckBox; private JCheckBox generalPanelLogForceTimestampsCheckbox; private JCheckBox generalPanelDisableNatureRuneAlchCheckbox; private JCheckBox generalPanelCommandPatchQuestCheckbox; @@ -1794,6 +1795,15 @@ public void stateChanged(ChangeEvent e) { generalPanelPrefersXdgOpenCheckbox.setToolTipText( "Does nothing on Windows or Mac, may improve URL opening experience on Linux"); + if (Util.isMacOS()) { + generalPanelMacOSConfirmQuitCheckBox = + addCheckbox("Ask for confirmation when pressing cmd-Q on macOS", generalPanel); + generalPanelMacOSConfirmQuitCheckBox.setToolTipText( + "Prevents the application from immediately closing with cmd-Q by asking for confirmation"); + SearchUtils.addSearchMetadata( + generalPanelMacOSConfirmQuitCheckBox, "command", "quit", "exit", "imac", "darwin"); + } + generalPanelAutoScreenshotCheckbox = addCheckbox("Take a screenshot when you level up or complete a quest", generalPanel); generalPanelAutoScreenshotCheckbox.setToolTipText( @@ -6273,6 +6283,10 @@ private void executeSynchronizeGuiValues() { generalPanelLimitRanFPSSpinner.setValue( Settings.RAN_EFFECT_TARGET_FPS.get(Settings.currentProfile)); generalPanelLimitFPSSpinner.setValue(Settings.FPS_LIMIT.get(Settings.currentProfile)); + if (Util.isMacOS()) { + generalPanelMacOSConfirmQuitCheckBox.setSelected( + Settings.MACOS_CONFIRM_QUIT.get(Settings.currentProfile)); + } generalPanelAutoScreenshotCheckbox.setSelected( Settings.AUTO_SCREENSHOT.get(Settings.currentProfile)); generalPanelScreenshotsDirTextField.setText(Settings.SCREENSHOTS_STORAGE_PATH.get("custom")); @@ -6813,6 +6827,10 @@ private void saveSettings() { Settings.currentProfile, generalPanelShiftScrollCameraRotationCheckbox.isSelected()); Settings.TRACKPAD_ROTATION_SENSITIVITY.put( Settings.currentProfile, generalPanelTrackpadRotationSlider.getValue()); + if (Util.isMacOS()) { + Settings.MACOS_CONFIRM_QUIT.put( + Settings.currentProfile, generalPanelMacOSConfirmQuitCheckBox.isSelected()); + } Settings.AUTO_SCREENSHOT.put( Settings.currentProfile, generalPanelAutoScreenshotCheckbox.isSelected()); Settings.SCREENSHOTS_STORAGE_PATH.put( diff --git a/src/Client/Settings.java b/src/Client/Settings.java index f5bbdd0c..52f1d291 100644 --- a/src/Client/Settings.java +++ b/src/Client/Settings.java @@ -151,6 +151,7 @@ public class Settings { public static HashMap CUSTOM_RAN_CHAT_EFFECT = new HashMap(); public static HashMap RAN_EFFECT_TARGET_FPS = new HashMap(); + public static HashMap MACOS_CONFIRM_QUIT = new HashMap(); public static HashMap AUTO_SCREENSHOT = new HashMap(); public static HashMap SCREENSHOTS_STORAGE_PATH = new HashMap(); public static HashMap RS2HD_SKY = new HashMap(); @@ -964,6 +965,8 @@ public static void definePresets(Properties props) { VIEW_DISTANCE.put("all", 20000); VIEW_DISTANCE.put("custom", getPropInt(props, "view_distance", VIEW_DISTANCE.get("default"))); + defineStaticPreset(MACOS_CONFIRM_QUIT, getPropBoolean(props, "macos_confirm_quit", true)); + AUTO_SCREENSHOT.put("vanilla", true); AUTO_SCREENSHOT.put("vanilla_resizable", true); AUTO_SCREENSHOT.put("lite", true); @@ -3752,6 +3755,7 @@ public static synchronized void save(String preset) { "custom_ran_chat_effect", Integer.toString(CUSTOM_RAN_CHAT_EFFECT.get(preset).id())); props.setProperty( "ran_effect_target_fps", Integer.toString(RAN_EFFECT_TARGET_FPS.get(preset))); + props.setProperty("macos_confirm_quit", Boolean.toString(MACOS_CONFIRM_QUIT.get(preset))); props.setProperty("auto_screenshot", Boolean.toString(AUTO_SCREENSHOT.get(preset))); props.setProperty("screenshots_storage_path", SCREENSHOTS_STORAGE_PATH.get(preset)); props.setProperty("rs2hd_sky", Boolean.toString(RS2HD_SKY.get(preset))); diff --git a/src/Game/KeyboardHandler.java b/src/Game/KeyboardHandler.java index 31e8dcfe..fc4e5246 100644 --- a/src/Game/KeyboardHandler.java +++ b/src/Game/KeyboardHandler.java @@ -21,6 +21,7 @@ import Client.KeybindSet; import Client.KeybindSet.KeyModifier; import Client.Settings; +import Client.Util; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; @@ -103,6 +104,11 @@ public void keyPressed(KeyEvent e) { } } + // Handle ⌘ modifier on macOS + } else if (e.isMetaDown() && Util.isMacOS()) { + // Not supported for keybinds, so always consume + e.consume(); + // Handle all other keys } else { for (KeybindSet kbs : keybindSetList) { diff --git a/src/Game/MacOSHandler.java b/src/Game/MacOSHandler.java index 223991a2..c4310fac 100644 --- a/src/Game/MacOSHandler.java +++ b/src/Game/MacOSHandler.java @@ -20,6 +20,8 @@ import Client.ConfigWindow; import Client.Launcher; +import Client.Settings; +import Client.Util; import com.apple.eawt.AboutHandler; import com.apple.eawt.AppEvent; import com.apple.eawt.Application; @@ -27,6 +29,8 @@ import com.apple.eawt.QuitResponse; import java.awt.event.WindowEvent; import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; /** macOS-specific application handling */ public class MacOSHandler implements QuitHandler, AboutHandler { @@ -67,6 +71,27 @@ public void handleAbout(AppEvent.AboutEvent aboutEvent) { @Override public void handleQuitRequestWith(AppEvent.QuitEvent quitEvent, QuitResponse quitResponse) { // Used to handle the macOS ⌘Q event, to replicate the same behavior as closing the window + if (Settings.MACOS_CONFIRM_QUIT.get(Settings.currentProfile)) { + final Object[] options = {"Yes", "No"}; + JPanel confirmQuitPanel = + Util.createOptionMessagePanel("Really quit " + Launcher.binaryPrefix + "RSCPlus?"); + int choice = + JOptionPane.showOptionDialog( + Launcher.getInstance(), + confirmQuitPanel, // message + "Confirm Quit", // title + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[1]); + + if (choice == JOptionPane.CLOSED_OPTION || choice == JOptionPane.NO_OPTION) { + quitResponse.cancelQuit(); + return; + } + } + gameFrame.dispatchEvent(new WindowEvent(gameFrame, WindowEvent.WINDOW_CLOSING)); } }