From 0cb2c849681a265854e6b3cd6fd58ea74f0c8697 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Wed, 22 Dec 2021 19:29:29 -0700 Subject: [PATCH 01/38] wxPython GUI: Initial Commit --- .github/workflows/build-app-wxpython.yml | 32 + OpenCore-Patcher-GUI.command | 6 + OpenCore-Patcher-GUI.spec | 50 + gui/gui_main.py | 1754 ++++++++++++++++++++++ gui/menu_redirect.py | 34 + resources/sys_patch_detect.py | 166 ++ 6 files changed, 2042 insertions(+) create mode 100644 .github/workflows/build-app-wxpython.yml create mode 100755 OpenCore-Patcher-GUI.command create mode 100644 OpenCore-Patcher-GUI.spec create mode 100644 gui/gui_main.py create mode 100644 gui/menu_redirect.py create mode 100644 resources/sys_patch_detect.py diff --git a/.github/workflows/build-app-wxpython.yml b/.github/workflows/build-app-wxpython.yml new file mode 100644 index 000000000..6f8fb09e1 --- /dev/null +++ b/.github/workflows/build-app-wxpython.yml @@ -0,0 +1,32 @@ +name: CI - Build wxPython + +on: + push: + workflow_dispatch: + release: + types: [published] + +jobs: + build: + name: Build wxPython + runs-on: x86_64_mojave + steps: + - uses: actions/checkout@v2 + - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher-GUI.spec + - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' + - run: cd dist; zip -r ../OpenCore-Patcher-wxPython.app.zip OpenCore-Patcher.app + - run: ./../sign-wxpython.sh + - name: Upload App to Artifacts + uses: actions/upload-artifact@v2 + with: + name: OpenCore-Patcher-wxPython.app + path: OpenCore-Patcher-wxPython.app.zip + + - name: Upload to Release + if: github.event_name == 'release' + uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: OpenCore-Patcher-wxPython.app.zip + tag: ${{ github.ref }} + file_glob: true diff --git a/OpenCore-Patcher-GUI.command b/OpenCore-Patcher-GUI.command new file mode 100755 index 000000000..8a4b46e23 --- /dev/null +++ b/OpenCore-Patcher-GUI.command @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 +# Copyright (C) 2020-2021, Dhinak G, Mykola Grymalyuk +from resources import main + +if __name__ == '__main__': + main.OpenCoreLegacyPatcher(True) \ No newline at end of file diff --git a/OpenCore-Patcher-GUI.spec b/OpenCore-Patcher-GUI.spec new file mode 100644 index 000000000..82dd073da --- /dev/null +++ b/OpenCore-Patcher-GUI.spec @@ -0,0 +1,50 @@ +# -*- mode: python ; coding: utf-8 -*- + +import sys, os +sys.path.append(os.path.abspath(os.getcwd())) +from resources import constants +block_cipher = None + + +a = Analysis(['OpenCore-Patcher-GUI.command'], + pathex=['resources', 'data', 'gui'], + binaries=[], + datas=[('payloads', 'payloads')], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False) +pyz = PYZ(a.pure, a.zipped_data, + cipher=block_cipher) + +exe = EXE(pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='OpenCore-Patcher', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None ) +app = BUNDLE(exe, + name='OpenCore-Patcher.app', + icon="payloads/OC-Patcher.icns", + bundle_identifier=None, + info_plist={ + "CFBundleShortVersionString": constants.Constants().patcher_version, + "NSHumanReadableCopyright": "Copyright 2020-2021 Dortania" + }) diff --git a/gui/gui_main.py b/gui/gui_main.py new file mode 100644 index 000000000..db966d253 --- /dev/null +++ b/gui/gui_main.py @@ -0,0 +1,1754 @@ +# Setup GUI +# Implemented using wxPython +# Currently Work in Progress + +import wx +import sys +import webbrowser +from pathlib import Path +import subprocess +import time + +from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect +from data import model_array, os_data +from gui import menu_redirect + +class wx_python_gui: + def __init__(self, versions): + self.constants: constants.Constants = versions + self.computer = self.constants.computer + self.constants.gui_mode = True + self.walkthrough_mode = False + + # Backup stdout for usage with wxPython + self.stock_stdout = sys.stdout + + # Define Window Size + self.WINDOW_WIDTH_MAIN = 350 + self.WINDOW_HEIGHT_MAIN = 220 + self.WINDOW_WIDTH_BUILD = 400 + self.WINDOW_HEIGHT_BUILD = 500 + self.WINDOW_SETTINGS_WIDTH = 230 + self.WINDOW_SETTINGS_HEIGHT = 320 + + # Create Application + self.app = wx.App() + self.frame = wx.Frame( + None, title="OpenCore Legacy Patcher", + size=(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN), + style = wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX) + ) + self.frame.Centre(~wx.MAXIMIZE_BOX) + self.frame.Show() + + self.main_menu(None) + + wx.CallAfter(self.frame.Close) + + def reset_window(self): + self.frame.DestroyChildren() + self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN) + sys.stdout = self.stock_stdout + + def print_test(self, text): + print(text) + + def not_yet_implemented_menu(self, event=None): + self.frame.DestroyChildren() + self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN) + + # Header + self.header = wx.StaticText(self.frame, label="🚧 Not Yet Implemented") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Return to main menu + self.return_button = wx.Button(self.frame, label="Return to Main Menu") + self.return_button.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_button.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.return_button.Centre(wx.HORIZONTAL) + + def walkthrough_main_menu(self, event=None): + # Define Menu + # - Header: OpenCore Legacy Patcher v{self.constants.patcher_version} + # - Subheader: Model: {self.constants.custom_model or self.computer.real_model} + # - Options: + # - First Time Setup + # - Post-Install Setup + # - Advanced Menu + + self.frame.DestroyChildren() + self.walkthrough_mode = False + + # Header + self.header = wx.StaticText(self.frame, label=f"OpenCore Legacy Patcher v{self.constants.patcher_version}") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader + self.subheader = wx.StaticText(self.frame, label=f"Model: {self.constants.custom_model or self.computer.real_model}") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 5 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + # Button: First Time Setup + self.first_time_setup = wx.Button(self.frame, label="First Time Setup", size=(200,30)) + self.first_time_setup.Bind(wx.EVT_BUTTON, self.first_time_setup_menu) + self.first_time_setup.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 5 + ) + ) + self.first_time_setup.Centre(wx.HORIZONTAL) + + # Button: Post-Install Setup + self.post_install_setup = wx.Button(self.frame, label="Post-Install Setup", size=(200,30)) + self.post_install_setup.Bind(wx.EVT_BUTTON, self.not_yet_implemented_menu) + self.post_install_setup.SetPosition( + wx.Point( + -1, + self.first_time_setup.GetPosition().y + self.first_time_setup.GetSize().height + ) + ) + self.post_install_setup.Centre(wx.HORIZONTAL) + + # Button: Advanced Menu + self.advanced_menu = wx.Button(self.frame, label="Advanced Menu", size=(200,30)) + self.advanced_menu.Bind(wx.EVT_BUTTON, self.advanced_main_menu) + self.advanced_menu.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.post_install_setup.GetPosition().y + self.post_install_setup.GetSize().height + ) + ) + self.advanced_menu.Centre(wx.HORIZONTAL) + + # Help Button + self.help_button = wx.Button(self.frame, label="Help", size=(200,30)) + self.help_button.SetPosition( + wx.Point( + self.advanced_menu.GetPosition().x, + self.advanced_menu.GetPosition().y + self.advanced_menu.GetSize().height + ) + ) + self.help_button.Bind(wx.EVT_BUTTON, self.help_menu) + self.help_button.Centre(wx.HORIZONTAL) + + # Set the window size below help button + self.frame.SetSize( + self.WINDOW_WIDTH_MAIN, + self.help_button.GetPosition().y + self.help_button.GetSize().height + 40 + ) + + self.app.MainLoop() + + def first_time_setup_menu(self, event=None): + # Define Menu + # - Header: First Time Setup + # - Subheader: Model: {self.constants.custom_model or self.computer.real_model} + # - Label: Here we'll be downloading and create a macOS installer + # - Label: Then, install OpenCore onto the installer's drive (or any other bootable drive) + # - Button: Create macOS Installer + # - Button: Return to Main Menu + + self.frame.DestroyChildren() + self.walkthrough_mode = True + + # Header + self.header = wx.StaticText(self.frame, label="First Time Setup") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader + self.subheader = wx.StaticText(self.frame, label=f"Model: {self.constants.custom_model or self.computer.real_model}") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 5 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + # Label: Here we'll be downloading and create a macOS installer + self.label_1 = wx.StaticText(self.frame, label="Here we'll download and create a macOS installer") + self.label_1.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.label_1.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 5 + ) + ) + self.label_1.Centre(wx.HORIZONTAL) + + # Label: Then, install OpenCore onto the installer's drive (or any other bootable drive) + self.label_2 = wx.StaticText(self.frame, label="Then, install OpenCore onto the installer's drive") + self.label_2.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.label_2.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.label_1.GetPosition().y + self.label_1.GetSize().height + 5 + ) + ) + self.label_2.Centre(wx.HORIZONTAL) + + # Label: Once finished, we can reboot and install macOS! + self.label_3 = wx.StaticText(self.frame, label="Once finished, we can reboot and install macOS!") + self.label_3.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.label_3.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.label_2.GetPosition().y + self.label_2.GetSize().height + 5 + ) + ) + self.label_3.Centre(wx.HORIZONTAL) + + # Button: Create macOS Installer + self.create_macos_installer = wx.Button(self.frame, label="Create macOS Installer", size=(200,30)) + self.create_macos_installer.Bind(wx.EVT_BUTTON, self.not_yet_implemented_menu) + self.create_macos_installer.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.label_3.GetPosition().y + self.label_3.GetSize().height + 5 + ) + ) + self.create_macos_installer.Centre(wx.HORIZONTAL) + + # Button: Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu", size=(200,30)) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.SetPosition( + + wx.Point( + self.create_macos_installer.GetPosition().x, + self.create_macos_installer.GetPosition().y + self.create_macos_installer.GetSize().height + ) + ) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Set the window size below return to main menu button + self.frame.SetSize( + -1, + self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40 + ) + + def main_menu(self, event=None): + # Define Menu + # - Header: OpenCore Legacy Patcher v{self.constants.patcher_version} + # - Subheader: Model: {self.constants.custom_model or self.computer.real_model} + # - Options: + # - Build and Install OpenCore + # - Post Install Root Patch + # - Create macOS Installer + # - Settings + + # Reset Data in the event of re-run + self.reset_window() + + # Header + self.header = wx.StaticText(self.frame, label=f"OpenCore Legacy Patcher v{self.constants.patcher_version}") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader + self.subheader = wx.StaticText(self.frame, label=f"Model: {self.constants.custom_model or self.computer.real_model}") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 5 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + # Build and Install OpenCore + self.build_install = wx.Button(self.frame, label="Build and Install OpenCore", size=(200,30)) + self.build_install.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 3 + ) + ) + self.build_install.Bind(wx.EVT_BUTTON, self.build_install_menu) + self.build_install.Centre(wx.HORIZONTAL) + + # Disable button if real_model not in model_array.SupportedSMBIOS + if self.constants.allow_oc_everywhere is False and \ + self.constants.custom_model is None and \ + self.computer.real_model not in model_array.SupportedSMBIOS: + self.build_install.Disable() + self.build_install.SetToolTip(wx.ToolTip("""If building for a native Mac model, +select 'Allow Native Models' in Settings. +If building for another Mac, change model in Settings""")) + + # Post Install Root Patch + self.post_install = wx.Button(self.frame, label="Post Install Root Patch", size=(200,30)) + self.post_install.SetPosition( + wx.Point( + self.build_install.GetPosition().x, + self.build_install.GetPosition().y + self.build_install.GetSize().height + ) + ) + self.post_install.Bind(wx.EVT_BUTTON, self.root_patch_menu) + self.post_install.Centre(wx.HORIZONTAL) + if self.constants.detected_os in [os_data.os_data.mojave, os_data.os_data.catalina] and self.constants.moj_cat_accel == False: + self.post_install.SetToolTip(wx.ToolTip("""Graphics Acceleration fro Mojave and Catalina is currently experimental. +If you require this feature, enable '10.14/15 Accel' in Settings.""")) + self.post_install.Disable() + elif self.constants.detected_os < os_data.os_data.mojave: + self.post_install.SetToolTip(wx.ToolTip("""Root Patching is only available for Mojave and newer.""")) + self.post_install.Disable() + + # Create macOS Installer + self.create_installer = wx.Button(self.frame, label="Create macOS Installer", size=(200,30)) + self.create_installer.SetPosition( + wx.Point( + self.post_install.GetPosition().x, + self.post_install.GetPosition().y + self.post_install.GetSize().height + ) + ) + self.create_installer.Bind(wx.EVT_BUTTON, self.create_macos_menu) + self.create_installer.Centre(wx.HORIZONTAL) + + # Settings + self.settings = wx.Button(self.frame, label="Settings", size=(200,30)) + self.settings.SetPosition( + wx.Point( + self.create_installer.GetPosition().x, + self.create_installer.GetPosition().y + self.create_installer.GetSize().height + ) + ) + self.settings.Bind(wx.EVT_BUTTON, self.settings_menu) + self.settings.Centre(wx.HORIZONTAL) + + # Help Button + self.help_button = wx.Button(self.frame, label="Help", size=(200,30)) + self.help_button.SetPosition( + wx.Point( + self.settings.GetPosition().x, + self.settings.GetPosition().y + self.settings.GetSize().height + ) + ) + self.help_button.Bind(wx.EVT_BUTTON, self.help_menu) + self.help_button.Centre(wx.HORIZONTAL) + + + # Copyright Label + self.copyright = wx.StaticText(self.frame, label="Copyright © 2020-2021 Dortania") + self.copyright.SetFont(wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.copyright.SetPosition( + wx.Point( + self.help_button.GetPosition().x, + self.help_button.GetPosition().y + self.help_button.GetSize().height + 5 + ) + ) + self.copyright.Centre(wx.HORIZONTAL) + + # Set Window Size to below Copyright Label + self.frame.SetSize( + ( + -1, + self.copyright.GetPosition().y + self.copyright.GetSize().height + 40 + ) + ) + + if self.app.MainLoop() is None: + self.app.MainLoop() + + def help_menu(self, event=None): + # Define Menu + # Header: Get help with OpenCore Legacy Patcher + # Subheader: Following resources are available: + # Button: Official Guide + # Button: Offical Discord Server + + self.frame.DestroyChildren() + + # Header + self.header = wx.StaticText(self.frame, label="Patcher Resources") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader + self.subheader = wx.StaticText(self.frame, label="Following resources are available:") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 5 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + + # Official Guide + self.guide = wx.Button(self.frame, label="Official Guide", size=(200,30)) + self.guide.SetPosition( + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 5 + + ) + ) + self.guide.Bind(wx.EVT_BUTTON, lambda event: webbrowser.open(self.constants.guide_link)) + self.guide.Centre(wx.HORIZONTAL) + + # Official Discord Server + self.discord = wx.Button(self.frame, label="Official Discord Server", size=(200,30)) + self.discord.SetPosition( + wx.Point( + self.guide.GetPosition().x, + self.guide.GetPosition().y + self.guide.GetSize().height + ) + ) + self.discord.Bind(wx.EVT_BUTTON, lambda event: webbrowser.open(self.constants.discord_link)) + self.discord.Centre(wx.HORIZONTAL) + + # Overclock Button + self.overclock = wx.Button(self.frame, label="Offical Support Phone", size=(200,30)) + self.overclock.SetPosition( + wx.Point( + self.discord.GetPosition().x, + self.discord.GetPosition().y + self.discord.GetSize().height + ) + ) + self.overclock.Bind(wx.EVT_BUTTON, lambda event: webbrowser.open("https://www.youtube.com/watch?v=dQw4w9WgXcQ")) + self.overclock.Centre(wx.HORIZONTAL) + + + # Return to Main Menu + self.return_to_main = wx.Button(self.frame, label="Return to Main Menu", size=(150,30)) + self.return_to_main.SetPosition( + wx.Point( + self.overclock.GetPosition().x, + self.overclock.GetPosition().y + self.overclock.GetSize().height + 5 + ) + ) + self.return_to_main.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main.Centre(wx.HORIZONTAL) + + # Set Window Size to below Copyright Label + self.frame.SetSize( + ( + -1, + self.return_to_main.GetPosition().y + self.return_to_main.GetSize().height + 40 + ) + ) + + def build_install_menu(self, event=None): + # Define Menu + # - Header: Build and Install OpenCore + # - Subheader: Model: {self.constants.custom_model or self.computer.real_model} + # - Button: Build OpenCore + # - Textbox: stdout + # - Button: Return to Main Menu + + self.frame.DestroyChildren() + self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.WINDOW_HEIGHT_BUILD) + + # Header + self.header = wx.StaticText(self.frame, label="Build and Install OpenCore") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader + self.subheader = wx.StaticText(self.frame, label=f"Model: {self.constants.custom_model or self.computer.real_model}") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 5 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + # Build OpenCore + self.build_opencore = wx.Button(self.frame, label="🧱 Build OpenCore", size=(150,30)) + self.build_opencore.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 3 + ) + ) + self.build_opencore.Bind(wx.EVT_BUTTON, self.build_start) + self.build_opencore.Centre(wx.HORIZONTAL) + + # Textbox + # Redirect stdout to a text box + self.stdout_text = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE | wx.TE_READONLY) + self.stdout_text.SetPosition(wx.Point(self.build_opencore.GetPosition().x, self.build_opencore.GetPosition().y + self.build_opencore.GetSize().height + 10)) + self.stdout_text.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + # Set width to same as frame + self.stdout_text.SetSize(self.WINDOW_WIDTH_BUILD, 340) + # Centre the text box to top of window + self.stdout_text.Centre(wx.HORIZONTAL) + self.stdout_text.SetValue("") + sys.stdout=menu_redirect.RedirectText(self.stdout_text) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + wx.Point( + self.stdout_text.GetPosition().x, + self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + def build_start(self, event=None): + build.BuildOpenCore(self.constants.custom_model or self.constants.computer.real_model, self.constants).build_opencore() + # Once finished, change build_opencore button to "Install OpenCore" + self.build_opencore.SetLabel("🔩 Install OpenCore") + self.build_opencore.Bind(wx.EVT_BUTTON, self.install_menu) + + # Reset stdout + sys.stdout = self.stock_stdout + + def install_menu(self, event=None): + self.frame.DestroyChildren() + i = 0 + + # Header + self.header = wx.StaticText(self.frame, label="Install OpenCore") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader: Select Disk to install OpenCore onto + self.subheader = wx.StaticText(self.frame, label="Select Disk to install OpenCore onto") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 5 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + # Label: If you're missing disks, ensure they're either FAT32 or formatted as GUI/GPT + self.missing_disks = wx.StaticText(self.frame, label="Missing disks? Ensure they're FAT32 or formatted as GUID/GPT") + self.missing_disks.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.missing_disks.SetPosition( + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 5 + ) + ) + self.missing_disks.Centre(wx.HORIZONTAL) + + # Request Disks Present + list_disks = install.tui_disk_installation(self.constants).list_disks() + if list_disks: + for disk in list_disks: + # Create a button for each disk + print(f"{list_disks[disk]['disk']} - {list_disks[disk]['name']} - {list_disks[disk]['size']}") + self.install_button = wx.Button(self.frame, label=disk, size=(300,30)) + self.install_button.SetLabel(f"{list_disks[disk]['disk']} - {list_disks[disk]['name']} - {list_disks[disk]['size']}") + self.install_button.SetPosition( + wx.Point( + self.missing_disks.GetPosition().x, + self.missing_disks.GetPosition().y + self.missing_disks.GetSize().height + 3 + i + ) + ) + self.install_button.Bind(wx.EVT_BUTTON, lambda event, temp=disk: self.install_oc_disk_select(temp, list_disks)) + self.install_button.Centre(wx.HORIZONTAL) + i += self.install_button.GetSize().height + 3 + else: + # Label: No disks found + self.install_button = wx.StaticText(self.frame, label="Failed to find any applicable disks") + self.install_button.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.install_button.SetPosition( + wx.Point( + self.missing_disks.GetPosition().x, + self.missing_disks.GetPosition().y + self.missing_disks.GetSize().height + 3 + ) + ) + self.install_button.Centre(wx.HORIZONTAL) + + + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.install_button.GetPosition().x, + self.install_button.GetPosition().y + self.install_button.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + def install_oc_disk_select(self, disk, disk_data): + self.frame.DestroyChildren() + i = 0 + + # Header + self.header = wx.StaticText(self.frame, label="Install OpenCore") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader: Select Partition to install OpenCore onto + self.subheader = wx.StaticText(self.frame, label="Select Partition to install OpenCore onto") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 5 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + list_partitions = install.tui_disk_installation(self.constants).list_partitions(disk, disk_data) + for partition in list_partitions: + print(f"{list_partitions[partition]['partition']} - {list_partitions[partition]['name']} - {list_partitions[partition]['size']}") + self.install_button = wx.Button(self.frame, label=partition, size=(300,30)) + self.install_button.SetLabel(f"{list_partitions[partition]['partition']} - {list_partitions[partition]['name']} - {list_partitions[partition]['size']}") + self.install_button.SetPosition( + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 3 + i + ) + ) + self.install_button.Bind(wx.EVT_BUTTON, lambda event, temp=partition: self.install_oc_process(temp)) + self.install_button.Centre(wx.HORIZONTAL) + i += self.install_button.GetSize().height + 3 + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.install_button.GetPosition().x, + self.install_button.GetPosition().y + self.install_button.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + def install_oc_process(self, partition): + print(f"Installing OpenCore to {partition}") + self.frame.DestroyChildren() + self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.WINDOW_HEIGHT_BUILD) + + # Header + self.header = wx.StaticText(self.frame, label="Install OpenCore") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Textbox + # Redirect stdout to a text box + self.stdout_text = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE | wx.TE_READONLY) + self.stdout_text.SetPosition(wx.Point(self.header.GetPosition().x, self.header.GetPosition().y + self.header.GetSize().height + 10)) + self.stdout_text.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + # Set width to same as frame + self.stdout_text.SetSize(self.WINDOW_WIDTH_BUILD, 340) + # Centre the text box to top of window + self.stdout_text.Centre(wx.HORIZONTAL) + self.stdout_text.SetValue("") + sys.stdout=menu_redirect.RedirectText(self.stdout_text) + + # Update frame height to right below + self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 40) + + self.frame.Show() + + install.tui_disk_installation(self.constants).install_opencore(partition) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.stdout_text.GetPosition().x, + self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 10 + + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + def root_patch_menu(self, event=None): + # Define Menu + # Header: Post-Install Menu + # Subheader: Available patches for system: + # Label: Placeholder for patch name + # Button: Start Root Patching + # Button: Revert Root Patches + # Button: Return to Main Menu + self.frame.DestroyChildren() + + # Header + self.header = wx.StaticText(self.frame, label="Post-Install Menu") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader + self.subheader = wx.StaticText(self.frame, label="Available patches for system:") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + patches = sys_patch_detect.detect_root_patch(self.computer.real_model, self.constants).detect_patch_set() + + if not any(not patch.startswith("Settings") and patches[patch] is True for patch in patches): + print("- No applicable patches available") + patches = [] + + i = 0 + if patches: + for patch in patches: + # Add Label for each patch + if (not patch.startswith("Settings") and patches[patch] is True): + print(f"- Adding patch: {patch} - {patches[patch]}") + self.patch_label = wx.StaticText(self.frame, label=f"- {patch}") + self.patch_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.patch_label.SetPosition( + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 3 + i + ) + ) + i = i + self.patch_label.GetSize().height + 3 + else: + # Prompt user with no patches found + self.patch_label = wx.StaticText(self.frame, label="No patches found") + self.patch_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.patch_label.SetPosition( + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 3 + i + ) + ) + self.patch_label.Centre(wx.HORIZONTAL) + + # Start Root Patching + self.start_root_patching = wx.Button(self.frame, label="Start Root Patching", size=(170, -1)) + self.start_root_patching.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.patch_label.GetPosition().x, + self.patch_label.GetPosition().y + self.patch_label.GetSize().height + 10 + ) + ) + self.start_root_patching.Bind(wx.EVT_BUTTON, self.not_yet_implemented_menu) + self.start_root_patching.Centre(wx.HORIZONTAL) + if not patches: + self.start_root_patching.Disable() + + # Revert Root Patches + self.revert_root_patches = wx.Button(self.frame, label="Revert Root Patches", size=(170, -1)) + self.revert_root_patches.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.start_root_patching.GetPosition().x, + self.start_root_patching.GetPosition().y + self.start_root_patching.GetSize().height + 3 + ) + ) + self.revert_root_patches.Bind(wx.EVT_BUTTON, self.root_patch_revert) + self.revert_root_patches.Centre(wx.HORIZONTAL) + if self.constants.detected_os < os_data.os_data.big_sur: + self.revert_root_patches.Disable() + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.revert_root_patches.GetPosition().x, + self.revert_root_patches.GetPosition().y + self.revert_root_patches.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + def root_patch_revert(self, event=None): + self.frame.DestroyChildren() + + self.frame.SetSize(self.WINDOW_WIDTH_BUILD, -1) + + # Header + self.header = wx.StaticText(self.frame, label="Revert Root Patches") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader + if self.constants.detected_os == os_data.os_data.big_sur: + self.subheader = wx.StaticText(self.frame, label="Currently experimental in Big Sur") + else: + self.subheader = wx.StaticText(self.frame, label="Reverting to last sealed snapshot") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + # Text Box + self.text_box = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE | wx.TE_READONLY) + self.text_box.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.text_box.SetPosition( + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 3 + ) + ) + self.text_box.SetSize( + wx.Size( + self.frame.GetSize().width - 10, + self.frame.GetSize().height - self.text_box.GetPosition().y + 40 + ) + ) + self.text_box.Centre(wx.HORIZONTAL) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.text_box.GetPosition().x, + self.text_box.GetPosition().y + self.text_box.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + sys.stdout = menu_redirect.RedirectText(self.text_box) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + # Start reverting root patches + # Grab binary path, launch second instance as CLI + # This is the cleanest way to implement admin root patching without either seperating OCLP or including duplicate code + wx.GetApp().Yield() + if self.constants.launcher_script is None: + self.text_box.AppendText("- Starting OCLP-CLI via Binary\n") + args = [self.constants.oclp_helper_path, self.constants.launcher_binary, "--unpatch_sys_vol"] + else: + self.text_box.AppendText("- Starting OCLP-CLI via Python\n") + args = [self.constants.oclp_helper_path, self.constants.launcher_binary, self.constants.launcher_script, "--unpatch_sys_vol"] + # process = subprocess.Popen( + # args, + # stdout=subprocess.PIPE, + # # stderr=subprocess.PIPE + # ) + # # Print each line of output + # while process.wait() is None: + # for line in process.stdout: + # self.text_box.AppendText(line.decode("utf-8")) + # Wait for process to finish + self.text_box.AppendText("- Remaining code is not yet implemented\n") + + wx.GetApp().Yield() + # for line in process.stdout: + # self.text_box.AppendText(line.decode("utf-8")) + + + + def create_macos_menu(self, event=None): + # Define Menu + # Header: Create macOS Installer + # Options: + # - Download macOS Installer + # - Use existing macOS Installer + # - Return to Main Menu + + self.frame.DestroyChildren() + + # Header + self.header = wx.StaticText(self.frame, label="Create macOS Installer") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Button: Download macOS Installer + self.download_macos_installer = wx.Button(self.frame, label="Download macOS Installer", size=(200, 30)) + self.download_macos_installer.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.download_macos_installer.Bind(wx.EVT_BUTTON, self.grab_installer_data) + self.download_macos_installer.Centre(wx.HORIZONTAL) + + # Button: Use existing macOS Installer + self.use_existing_macos_installer = wx.Button(self.frame, label="Use existing macOS Installer", size=(200, 30)) + self.use_existing_macos_installer.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.download_macos_installer.GetPosition().x, + self.download_macos_installer.GetPosition().y + self.download_macos_installer.GetSize().height + ) + ) + self.use_existing_macos_installer.Bind(wx.EVT_BUTTON, self.flash_installer_menu) + self.use_existing_macos_installer.Centre(wx.HORIZONTAL) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.use_existing_macos_installer.GetPosition().x, + self.use_existing_macos_installer.GetPosition().y + self.use_existing_macos_installer.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + def grab_installer_data(self, event=None): + self.frame.DestroyChildren() + + # Header + self.header = wx.StaticText(self.frame, label="Pulling installer catalog") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Label: Download... + self.download_label = wx.StaticText(self.frame, label="Downloading installer catalog...") + self.download_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.download_label.SetPosition( + # Set Position below header + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.download_label.Centre(wx.HORIZONTAL) + # Redirect stdout to label + sys.stdout=menu_redirect.RedirectLabel(self.download_label) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.download_label.GetPosition().x, + self.download_label.GetPosition().y + self.download_label.GetSize().height + 30 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + self.frame.Show() + + # Download installer catalog + avalible_installers = installer.list_downloadable_macOS_installers(self.constants.payload_path, "PublicSeed") + + self.frame.DestroyChildren() + sys.stdout = self.stock_stdout + + # Header + self.header = wx.StaticText(self.frame, label="Download macOS Installer") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + i = -15 + for app in avalible_installers: + print(f"macOS {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']} - {utilities.human_fmt(avalible_installers[app]['Size'])} - {avalible_installers[app]['Source']})") + self.install_selection = wx.Button(self.frame, label=f"macOS {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']} - {utilities.human_fmt(avalible_installers[app]['Size'])})", size=(250, 30)) + i = i + 25 + self.install_selection.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + i + ) + ) + self.install_selection.Bind(wx.EVT_BUTTON, lambda event, temp=app: self.download_macos_click(f"macOS {avalible_installers[temp]['Version']} ({avalible_installers[temp]['Build']})", avalible_installers[temp]['Link'])) + self.install_selection.Centre(wx.HORIZONTAL) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.install_selection.GetPosition().x, + self.install_selection.GetPosition().y + self.install_selection.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + def download_macos_click(self, installer_name, installer_link): + self.frame.DestroyChildren() + + # Header + self.header = wx.StaticText(self.frame, label=f"Downloading {installer_name}") + self.frame.SetSize(self.header.GetSize().width + 200, -1) + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Label: Download... + self.download_label = wx.StaticText(self.frame, label="Downloading...") + self.download_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.download_label.SetPosition( + # Set Position below header + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.download_label.Centre(wx.HORIZONTAL) + # Redirect stdout to label + sys.stdout=menu_redirect.RedirectLabel(self.download_label) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.download_label.GetPosition().x, + self.download_label.GetPosition().y + self.download_label.GetSize().height + 30 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + # Download macOS install data + installer.download_install_assistant(self.constants.payload_path, installer_link) + + # Fix stdout + sys.stdout = self.stock_stdout + self.download_label.SetLabel(f"Finished Downloading {installer_name}") + self.download_label.Centre(wx.HORIZONTAL) + + # Update Label: + sys.stdout=menu_redirect.RedirectLabelAll(self.download_label) + installer.install_macOS_installer(self.constants.payload_path) + sys.stdout = self.stock_stdout + # Update Label: + self.download_label.SetLabel(f"Finished Installing {installer_name}") + self.download_label.Centre(wx.HORIZONTAL) + + # Set Return to Main Menu into flash_installer_menu + self.return_to_main_menu.SetLabel("Flash Installer") + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.flash_installer_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + def flash_installer_menu(self, event=None): + self.frame.DestroyChildren() + self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN) + # Header + self.header = wx.StaticText(self.frame, label="Select macOS Installer") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + i = -10 + avalible_installers = installer.list_local_macOS_installers() + if avalible_installers: + print("Installer found") + for app in avalible_installers: + print(f"{avalible_installers[app]['Short Name']}: {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']})") + self.install_selection = wx.Button(self.frame, label=f"{avalible_installers[app]['Short Name']}: {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']})", size=(300, 30)) + i = i + 25 + self.install_selection.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + i + ) + ) + self.install_selection.Bind(wx.EVT_BUTTON, lambda event, temp=app: self.format_usb_menu(avalible_installers[temp]['Path'])) + self.install_selection.Centre(wx.HORIZONTAL) + else: + print("No installers found") + # Label: No Installers Found + self.install_selection = wx.StaticText(self.frame, label="No Installers Found in Applications folder") + self.install_selection.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.install_selection.SetPosition( + # Set Position below header + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.install_selection.Centre(wx.HORIZONTAL) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.install_selection.GetPosition().x, + self.install_selection.GetPosition().y + self.install_selection.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + def format_usb_menu(self, installer_path): + self.frame.DestroyChildren() + print(installer_path) + + # Header + self.header = wx.StaticText(self.frame, label="Format USB") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader: Selected USB will be erased, please backup your data + self.subheader = wx.StaticText(self.frame, label="Selected USB will be erased, please backup your data") + self.subheader.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.subheader.SetPosition( + # Set Position below header + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + # Label: Select USB + self.usb_selection_label = wx.StaticText(self.frame, label="Missing drives? Ensure they're 14GB+ and removable") + self.usb_selection_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) + self.usb_selection_label.SetPosition( + # Set Position below header + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 10 + ) + ) + self.usb_selection_label.Centre(wx.HORIZONTAL) + + i = -15 + availible_disks = installer.list_disk_to_format() + if availible_disks: + print("Disks found") + for disk in availible_disks: + print(f"{disk}: {availible_disks[disk]['name']} - {availible_disks[disk]['size']}") + self.usb_selection = wx.Button(self.frame, label=f"{disk} - {availible_disks[disk]['name']} - {utilities.human_fmt(availible_disks[disk]['size'])}", size=(300, 30)) + i = i + 25 + self.usb_selection.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.usb_selection_label.GetPosition().x, + self.usb_selection_label.GetPosition().y + self.usb_selection_label.GetSize().height + i + ) + ) + self.usb_selection.Bind(wx.EVT_BUTTON, lambda event, temp=disk: self.format_usb_progress(availible_disks[temp]['identifier'], installer_path)) + self.usb_selection.Centre(wx.HORIZONTAL) + else: + print("No disks found") + # Label: No Disks Found + self.usb_selection = wx.StaticText(self.frame, label="No Disks Found") + self.usb_selection.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.usb_selection.SetPosition( + # Set Position below header + wx.Point( + self.usb_selection_label.GetPosition().x, + self.usb_selection_label.GetPosition().y + self.usb_selection_label.GetSize().height + 10 + ) + ) + self.usb_selection.Centre(wx.HORIZONTAL) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.usb_selection.GetPosition().x, + self.usb_selection.GetPosition().y + self.usb_selection.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + def format_usb_progress(self, disk, installer_path): + self.frame.DestroyChildren() + self.frame.SetSize(500, -1) + # Header + self.header = wx.StaticText(self.frame, label="Creating macOS Installer") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Label: Creating macOS Installer + self.creating_macos_installer_label = wx.StaticText(self.frame, label="Formatting and flashing installer to drive") + self.creating_macos_installer_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) + self.creating_macos_installer_label.SetPosition( + # Set Position below header + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.creating_macos_installer_label.Centre(wx.HORIZONTAL) + + # Label: Developer Note: createinstallmedia output currently not implemented + self.developer_note_label = wx.StaticText(self.frame, label="Developer Note: createinstallmedia output currently not implemented") + self.developer_note_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) + self.developer_note_label.SetPosition( + # Set Position below header + wx.Point( + self.creating_macos_installer_label.GetPosition().x, + self.creating_macos_installer_label.GetPosition().y + self.creating_macos_installer_label.GetSize().height + 10 + ) + ) + self.developer_note_label.Centre(wx.HORIZONTAL) + + # Textbox + # Redirect stdout to a text box + self.stdout_text = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE | wx.TE_READONLY) + self.stdout_text.SetPosition( + # Set Position below header + wx.Point( + self.developer_note_label.GetPosition().x, + self.developer_note_label.GetPosition().y + self.developer_note_label.GetSize().height + 10 + ) + ) + self.stdout_text.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + # Set width to same as frame + self.stdout_text.SetSize( + self.frame.GetSize().width, + 340) + # Centre the text box to top of window + self.stdout_text.Centre(wx.HORIZONTAL) + self.stdout_text.SetValue("") + sys.stdout=menu_redirect.RedirectText(self.stdout_text) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.stdout_text.GetPosition().x, + self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + self.frame.Show() + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + wx.GetApp().Yield() + # Create installer.sh script + print("- Creating installer.sh script") + print(f"- Disk: {disk}") + print(f"- Installer: {installer_path}") + if installer.generate_installer_creation_script(self.constants.installer_sh_path, installer_path, disk): + print("- Sucessfully generated creation script") + print("- Starting creation script as admin") + wx.GetApp().Yield() + time.sleep(1) + sys.stdout=menu_redirect.RedirectText(self.stdout_text) + cim_start = subprocess.run( + [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path], + stdout=subprocess.PIPE, + # stderr=subprocess.STDOUT + ) + + if cim_start.returncode == 0: + print("Installer created successfully!") + else: + print("Installer creation failed") + print(cim_start.returncode) + sys.stdout = self.stock_stdout + else: + print("- Failed to create installer script") + sys.stdout = self.stock_stdout + + + def settings_menu(self, event=None): + # Define Menu + # - Header: Settings + # - Dropdown: Model + # - Chechboxes: + # - Verbose + # - Kext Debug + # - OpenCore Debug + # - SIP + # - SecureBootModel + # - Show Boot Picker + # - Buttons: + # - Developer Settings + # - Return to Main Menu + + self.frame.DestroyChildren() + self.frame.SetSize(self.WINDOW_SETTINGS_WIDTH, self.WINDOW_SETTINGS_HEIGHT) + self.frame.SetLabel("Settings") + + # Header + self.header = wx.StaticText(self.frame, label="Settings") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Dropdown + self.dropdown_model = wx.Choice(self.frame) + for model in model_array.SupportedSMBIOS: + self.dropdown_model.Append(model) + if self.computer.real_model not in self.dropdown_model.GetItems(): + # In the event an unsupported model is loaded, add it to the dropdown + # Supported situation: If user wants to run on native model + self.dropdown_model.Append(self.computer.real_model) + self.dropdown_model.SetSelection(self.dropdown_model.GetItems().index(self.constants.custom_model or self.computer.real_model)) + self.dropdown_model.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + # Set size to largest item + self.dropdown_model.SetSize( + wx.Size( + self.dropdown_model.GetBestSize().width, + self.dropdown_model.GetBestSize().height + ) + ) + self.dropdown_model.Bind(wx.EVT_CHOICE, self.model_choice_click) + self.dropdown_model.Centre(wx.HORIZONTAL) + + # Checkboxes + # Checkbox: Allow native models + self.checkbox_allow_native_models = wx.CheckBox(self.frame, label="Allow native models") + self.checkbox_allow_native_models.SetValue(self.constants.allow_oc_everywhere) + self.checkbox_allow_native_models.SetPosition(wx.Point(self.dropdown_model.GetPosition().x, self.dropdown_model.GetPosition().y + self.dropdown_model.GetSize().height + 10)) + self.checkbox_allow_native_models.Bind(wx.EVT_CHECKBOX, self.allow_native_models_click) + + # Checkbox: Verbose + self.verbose_checkbox = wx.CheckBox(self.frame, label="Verbose") + self.verbose_checkbox.SetValue(self.constants.verbose_debug) + self.verbose_checkbox.SetPosition(wx.Point(self.checkbox_allow_native_models.GetPosition().x, self.checkbox_allow_native_models.GetPosition().y + self.checkbox_allow_native_models.GetSize().height)) + self.verbose_checkbox.Bind(wx.EVT_CHECKBOX, self.verbose_checkbox_click) + + # Checkbox: Kext Debug + self.kext_checkbox = wx.CheckBox(self.frame, label="Kext Debug") + self.kext_checkbox.SetValue(self.constants.kext_debug) + self.kext_checkbox.SetPosition(wx.Point(self.verbose_checkbox.GetPosition().x , self.verbose_checkbox.GetPosition().y + self.verbose_checkbox.GetSize().height)) + self.kext_checkbox.Bind(wx.EVT_CHECKBOX, self.kext_checkbox_click) + + # Checkbox: OpenCore Debug + self.opencore_checkbox = wx.CheckBox(self.frame, label="OpenCore Debug") + self.opencore_checkbox.SetValue(self.constants.opencore_debug) + self.opencore_checkbox.SetPosition(wx.Point(self.kext_checkbox.GetPosition().x , self.kext_checkbox.GetPosition().y + self.kext_checkbox.GetSize().height)) + self.opencore_checkbox.Bind(wx.EVT_CHECKBOX, self.oc_checkbox_click) + + # Checkbox: SIP + self.sip_checkbox = wx.CheckBox(self.frame, label="SIP") + self.sip_checkbox.SetValue(self.constants.sip_status) + self.sip_checkbox.SetPosition(wx.Point(self.opencore_checkbox.GetPosition().x , self.opencore_checkbox.GetPosition().y + self.opencore_checkbox.GetSize().height)) + self.sip_checkbox.Bind(wx.EVT_CHECKBOX, self.sip_checkbox_click) + + # Checkbox: SecureBootModel + self.secureboot_checkbox = wx.CheckBox(self.frame, label="SecureBootModel") + self.secureboot_checkbox.SetValue(self.constants.secure_status) + self.secureboot_checkbox.SetPosition(wx.Point(self.sip_checkbox.GetPosition().x , self.sip_checkbox.GetPosition().y + self.sip_checkbox.GetSize().height)) + self.secureboot_checkbox.Bind(wx.EVT_CHECKBOX, self.secureboot_checkbox_click) + + # Checkbox: Show Boot Picker + self.bootpicker_checkbox = wx.CheckBox(self.frame, label="Show Boot Picker") + self.bootpicker_checkbox.SetValue(self.constants.showpicker) + self.bootpicker_checkbox.SetPosition(wx.Point(self.secureboot_checkbox.GetPosition().x , self.secureboot_checkbox.GetPosition().y + self.secureboot_checkbox.GetSize().height)) + self.bootpicker_checkbox.Bind(wx.EVT_CHECKBOX, self.show_picker_checkbox_click) + + # Checkbox: Allow Accel on Mojave/Catalina + self.accel_checkbox = wx.CheckBox(self.frame, label="Allow Accel on 10.14/15") + self.accel_checkbox.SetValue(self.constants.moj_cat_accel) + self.accel_checkbox.SetPosition(wx.Point(self.bootpicker_checkbox.GetPosition().x , self.bootpicker_checkbox.GetPosition().y + self.bootpicker_checkbox.GetSize().height)) + self.accel_checkbox.Bind(wx.EVT_CHECKBOX, self.accel_checkbox_click) + + # Buttons + # Button: Developer Settings + self.miscellaneous_button = wx.Button(self.frame, label="Developer Settings", size=(150,30)) + self.miscellaneous_button.SetPosition(wx.Point(self.accel_checkbox.GetPosition().x , self.accel_checkbox.GetPosition().y + self.accel_checkbox.GetSize().height + 10)) + self.miscellaneous_button.Bind(wx.EVT_BUTTON, self.misc_settings_menu) + self.miscellaneous_button.Centre(wx.HORIZONTAL) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu", size=(150,30)) + self.return_to_main_menu.SetPosition( + wx.Point( + self.miscellaneous_button.GetPosition().x, + self.miscellaneous_button.GetPosition().y + self.miscellaneous_button.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Set frame size to below return_to_main_menu button + self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + def model_choice_click(self, event=None): + user_choice = self.dropdown_model.GetStringSelection() + if user_choice == self.computer.real_model: + print(f"Using Real Model: {user_choice}") + self.constants.custom_model = None + defaults.generate_defaults.probe(self.computer.real_model, True, self.constants) + else: + print(f"Using Custom Model: {user_choice}") + self.constants.custom_model = user_choice + defaults.generate_defaults.probe(self.constants.custom_model, False, self.constants) + # Reload Settings + self.settings_menu(None) + + def allow_native_models_click(self, event=None): + if self.checkbox_allow_native_models.GetValue(): + print("Allow Native Models") + self.constants.allow_oc_everywhere = True + self.constants.serial_settings = "None" + else: + print("Disallow Native Models") + self.constants.allow_oc_everywhere = False + self.constants.serial_settings = "Minimal" + + def verbose_checkbox_click(self, event=None): + if self.verbose_checkbox.GetValue(): + print("Verbose mode enabled") + self.constants.verbose_debug = True + else: + print("Verbose mode disabled") + self.constants.verbose_debug = False + + def kext_checkbox_click(self, event=None): + if self.kext_checkbox.GetValue(): + print("Kext mode enabled") + self.constants.kext_debug = True + else: + print("Kext mode disabled") + self.constants.kext_debug = False + + def oc_checkbox_click(self, event=None): + if self.opencore_checkbox.GetValue(): + print("OC mode enabled") + self.constants.opencore_debug = True + self.constants.opencore_build = "DEBUG" + else: + print("OC mode disabled") + self.constants.opencore_debug = False + self.constants.opencore_build = "RELEASE" + + def sip_checkbox_click(self, event=None): + if self.sip_checkbox.GetValue(): + print("SIP mode enabled") + self.constants.sip_status = True + else: + print("SIP mode disabled") + self.constants.sip_status = False + + def secureboot_checkbox_click(self, event=None): + if self.secureboot_checkbox.GetValue(): + print("SecureBoot mode enabled") + self.constants.secure_status = True + else: + print("SecureBoot mode disabled") + self.constants.secure_status = False + + def show_picker_checkbox_click(self, event=None): + if self.bootpicker_checkbox.GetValue(): + print("Show Picker mode enabled") + self.constants.showpicker = True + else: + print("Show Picker mode disabled") + self.constants.showpicker = False + + def accel_checkbox_click(self, event=None): + if self.accel_checkbox.GetValue(): + print("Legacy Accel mode enabled") + self.constants.moj_cat_accel = True + else: + print("Legacy Accel mode disabled") + self.constants.moj_cat_accel = False + + def misc_settings_menu(self, event=None): + self.frame.DestroyChildren() + + # Header + self.header = wx.StaticText(self.frame, label="Developer Settings", style=wx.ALIGN_CENTRE) + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.SetPosition(wx.Point(0, 10)) + self.header.SetSize(wx.Size(self.frame.GetSize().width, 30)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader: If unfamiliar with the following settings, please do not change them. + self.subheader = wx.StaticText(self.frame, label="Do not change if unfamiliar", style=wx.ALIGN_CENTRE) + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.subheader.SetPosition(wx.Point(0, self.header.GetPosition().y + self.header.GetSize().height + 10)) + self.subheader.SetSize(wx.Size(self.frame.GetSize().width, 30)) + self.subheader.Centre(wx.HORIZONTAL) + + + # Label: Set GPU Model for MXM iMacs + self.label_model = wx.StaticText(self.frame, label="Set GPU Model for MXM iMacs:", style=wx.ALIGN_CENTRE) + self.label_model.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.label_model.SetPosition(wx.Point(0, self.subheader.GetPosition().y + self.subheader.GetSize().height)) + self.label_model.SetSize(wx.Size(self.frame.GetSize().width, 30)) + self.label_model.Centre(wx.HORIZONTAL) + + # Dropdown: GPU Model + self.gpu_dropdown = wx.Choice(self.frame) + for gpu in ["None", "Nvidia Kepler", "AMD GCN", "AMD Polaris"]: + self.gpu_dropdown.Append(gpu) + self.gpu_dropdown.SetSelection(0) + self.gpu_dropdown.SetPosition(wx.Point( + self.label_model.GetPosition().x, + self.label_model.GetPosition().y + self.label_model.GetSize().height / 1.5)) + self.gpu_dropdown.Bind(wx.EVT_CHOICE, self.gpu_selection_click) + self.gpu_dropdown.Centre(wx.HORIZONTAL) + + # Checkbox List: + # FireWire Boot + # NVMe Boot + # Wake on WLAN + # Disable Thunderbolt + # Set TeraScale 2 Accel + # Windows GMUX + # Hibernation Workaround + # Disable Battery Throttling + # Software Demux + + # FireWire Boot + self.firewire_boot_checkbox = wx.CheckBox(self.frame, label="FireWire Boot") + self.firewire_boot_checkbox.SetValue(self.constants.firewire_boot) + self.firewire_boot_checkbox.Bind(wx.EVT_CHECKBOX, self.firewire_click) + self.firewire_boot_checkbox.SetPosition(wx.Point(30, self.gpu_dropdown.GetPosition().y + self.gpu_dropdown.GetSize().height + 5)) + + # NVMe Boot + self.nvme_boot_checkbox = wx.CheckBox(self.frame, label="NVMe Boot") + self.nvme_boot_checkbox.SetValue(self.constants.nvme_boot) + self.nvme_boot_checkbox.Bind(wx.EVT_CHECKBOX, self.nvme_click) + self.nvme_boot_checkbox.SetPosition(wx.Point(self.firewire_boot_checkbox.GetPosition().x, self.firewire_boot_checkbox.GetPosition().y + self.firewire_boot_checkbox.GetSize().height)) + + + # Wake on WLAN + self.wake_on_wlan_checkbox = wx.CheckBox(self.frame, label="Wake on WLAN") + self.wake_on_wlan_checkbox.SetValue(self.constants.enable_wake_on_wlan) + self.wake_on_wlan_checkbox.Bind(wx.EVT_CHECKBOX, self.wake_on_wlan_click) + self.wake_on_wlan_checkbox.SetPosition(wx.Point( + self.nvme_boot_checkbox.GetPosition().x, + self.nvme_boot_checkbox.GetPosition().y + self.nvme_boot_checkbox.GetSize().height)) + + # Disable Thunderbolt + self.disable_thunderbolt_checkbox = wx.CheckBox(self.frame, label="Disable Thunderbolt") + self.disable_thunderbolt_checkbox.SetValue(self.constants.disable_tb) + self.disable_thunderbolt_checkbox.Bind(wx.EVT_CHECKBOX, self.disable_tb_click) + self.disable_thunderbolt_checkbox.SetPosition(wx.Point( + self.wake_on_wlan_checkbox.GetPosition().x, + self.wake_on_wlan_checkbox.GetPosition().y + self.wake_on_wlan_checkbox.GetSize().height)) + + # Set TeraScale 2 Accel + self.set_terascale_accel_checkbox = wx.CheckBox(self.frame, label="Set TeraScale 2 Accel") + self.set_terascale_accel_checkbox.SetValue(self.constants.allow_ts2_accel) + self.set_terascale_accel_checkbox.Bind(wx.EVT_CHECKBOX, self.ts2_accel_click) + self.set_terascale_accel_checkbox.SetPosition(wx.Point( + self.disable_thunderbolt_checkbox.GetPosition().x, + self.disable_thunderbolt_checkbox.GetPosition().y + self.disable_thunderbolt_checkbox.GetSize().height)) + + # Windows GMUX + self.windows_gmux_checkbox = wx.CheckBox(self.frame, label="Windows GMUX") + self.windows_gmux_checkbox.SetValue(self.constants.dGPU_switch) + self.windows_gmux_checkbox.Bind(wx.EVT_CHECKBOX, self.windows_gmux_click) + self.windows_gmux_checkbox.SetPosition(wx.Point( + self.set_terascale_accel_checkbox.GetPosition().x, + self.set_terascale_accel_checkbox.GetPosition().y + self.set_terascale_accel_checkbox.GetSize().height)) + + # Hibernation Workaround + self.hibernation_checkbox = wx.CheckBox(self.frame, label="Hibernation Workaround") + self.hibernation_checkbox.SetValue(self.constants.disable_connectdrivers) + self.hibernation_checkbox.Bind(wx.EVT_CHECKBOX, self.hibernation_click) + self.hibernation_checkbox.SetPosition(wx.Point( + self.windows_gmux_checkbox.GetPosition().x, + self.windows_gmux_checkbox.GetPosition().y + self.windows_gmux_checkbox.GetSize().height)) + + # Disable Battery Throttling + self.disable_battery_throttling_checkbox = wx.CheckBox(self.frame, label="Disable Battery Throttling") + self.disable_battery_throttling_checkbox.SetValue(self.constants.disable_msr_power_ctl) + self.disable_battery_throttling_checkbox.Bind(wx.EVT_CHECKBOX, self.disable_battery_throttling_click) + self.disable_battery_throttling_checkbox.SetPosition(wx.Point( + self.hibernation_checkbox.GetPosition().x, + self.hibernation_checkbox.GetPosition().y + self.hibernation_checkbox.GetSize().height)) + + # Software Demux + self.software_demux_checkbox = wx.CheckBox(self.frame, label="Software Demux") + self.software_demux_checkbox.SetValue(self.constants.software_demux) + self.software_demux_checkbox.Bind(wx.EVT_CHECKBOX, self.software_demux_click) + self.software_demux_checkbox.SetPosition(wx.Point( + self.disable_battery_throttling_checkbox.GetPosition().x, + self.disable_battery_throttling_checkbox.GetPosition().y + self.disable_battery_throttling_checkbox.GetSize().height)) + + # Disable CPUFriend + self.disable_cpu_friend_checkbox = wx.CheckBox(self.frame, label="Disable CPUFriend") + self.disable_cpu_friend_checkbox.SetValue(self.constants.disallow_cpufriend) + self.disable_cpu_friend_checkbox.Bind(wx.EVT_CHECKBOX, self.disable_cpu_friend_click) + self.disable_cpu_friend_checkbox.SetPosition(wx.Point( + self.software_demux_checkbox.GetPosition().x, + self.software_demux_checkbox.GetPosition().y + self.software_demux_checkbox.GetSize().height)) + + # AppleALC Usage + self.apple_alc_checkbox = wx.CheckBox(self.frame, label="AppleALC Usage") + self.apple_alc_checkbox.SetValue(self.constants.set_alc_usage) + self.apple_alc_checkbox.Bind(wx.EVT_CHECKBOX, self.apple_alc_click) + self.apple_alc_checkbox.SetPosition(wx.Point( + self.disable_cpu_friend_checkbox.GetPosition().x, + self.disable_cpu_friend_checkbox.GetPosition().y + self.disable_cpu_friend_checkbox.GetSize().height)) + + + # Button: return to main menu + self.return_to_main_menu_button = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu_button.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu_button.SetPosition(wx.Point( + self.apple_alc_checkbox.GetPosition().x, + self.apple_alc_checkbox.GetPosition().y + self.apple_alc_checkbox.GetSize().height + 10)) + self.return_to_main_menu_button.Center(wx.HORIZONTAL) + + # set frame size below return to main menu button + self.frame.SetSize(wx.Size(-1, self.return_to_main_menu_button.GetPosition().y + self.return_to_main_menu_button.GetSize().height + 40)) + + def firewire_click(self, event=None): + if self.firewire_boot_checkbox.GetValue(): + print("Firewire Enabled") + self.constants.firewire_boot = True + else: + print("Firewire Disabled") + self.constants.firewire_boot = False + + def nvme_click(self, event=None): + if self.nvme_boot_checkbox.GetValue(): + print("NVMe Enabled") + self.constants.nvme_boot = True + else: + print("NVMe Disabled") + self.constants.nvme_boot = False + + def wake_on_wlan_click(self, event=None): + if self.wake_on_wlan_checkbox.GetValue(): + print("Wake on WLAN Enabled") + self.constants.enable_wake_on_wlan = True + else: + print("Wake on WLAN Disabled") + self.constants.enable_wake_on_wlan = False + + def disable_tb_click(self, event=None): + if self.disable_thunderbolt_checkbox.GetValue(): + print("Disable Thunderbolt Enabled") + self.constants.disable_tb = True + else: + print("Disable Thunderbolt Disabled") + self.constants.disable_tb = False + + def ts2_accel_click(self, event=None): + if self.set_terascale_accel_checkbox.GetValue(): + print("TS2 Acceleration Enabled") + self.constants.allow_ts2_accel = True + else: + print("TS2 Acceleration Disabled") + self.constants.allow_ts2_accel = False + + def windows_gmux_click(self, event=None): + if self.windows_gmux_checkbox.GetValue(): + print("Windows GMUX Enabled") + self.constants.dGPU_switch = True + else: + print("Windows GMUX Disabled") + self.constants.dGPU_switch = False + + def hibernation_click(self, event=None): + if self.hibernation_checkbox.GetValue(): + print("Hibernation Enabled") + self.constants.disable_connectdrivers = True + else: + print("Hibernation Disabled") + self.constants.disable_connectdrivers = False + + def disable_battery_throttling_click(self, event=None): + if self.disable_battery_throttling_checkbox.GetValue(): + print("Disable Battery Throttling Enabled") + self.constants.disable_msr_power_ctl = True + else: + print("Disable Battery Throttling Disabled") + self.constants.disable_msr_power_ctl = False + + def software_demux_click(self, event=None): + if self.software_demux_checkbox.GetValue(): + print("Software Demux Enabled") + self.constants.software_demux = True + else: + print("Software Demux Disabled") + self.constants.software_demux = False + + def disable_cpu_friend_click(self, event=None): + if self.disable_cpu_friend_checkbox.GetValue(): + print("Disable CPUFriend Enabled") + self.constants.disallow_cpufriend = True + else: + print("Disable CPUFriend Disabled") + self.constants.disallow_cpufriend = False + + def apple_alc_click(self, event=None): + if self.apple_alc_checkbox.GetValue(): + print("AppleALC Usage Enabled") + self.constants.set_alc_usage = True + else: + print("AppleALC Usage Disabled") + self.constants.set_alc_usage = False + + def gpu_selection_click(self, event=None): + gpu_choice = self.gpu_dropdown.GetStringSelection() + print(f"GPU Selection: {gpu_choice}") + if "AMD" in gpu_choice: + self.constants.imac_vendor = "AMD" + self.constants.metal_build = True + if "Polaris" in gpu_choice: + self.constants.imac_model = "Polaris" + elif "GCN" in gpu_choice: + self.constants.imac_model = "Legacy GCN" + else: + raise Exception("Unknown GPU Model") + elif "Nvidia" in gpu_choice: + self.constants.imac_vendor = "Nvidia" + self.constants.metal_build = True + if "Kepler" in gpu_choice: + self.constants.imac_model = "Kepler" + elif "GT" in gpu_choice: + self.constants.imac_model = "GT" + else: + raise Exception("Unknown GPU Model") + else: + self.constants.imac_vendor = "None" + self.constants.metal_build = False + + print(f"GPU Vendor: {self.constants.imac_vendor}") + print(f"GPU Model: {self.constants.imac_model}") \ No newline at end of file diff --git a/gui/menu_redirect.py b/gui/menu_redirect.py new file mode 100644 index 000000000..d3e76738c --- /dev/null +++ b/gui/menu_redirect.py @@ -0,0 +1,34 @@ +import wx + +class RedirectText(object): + def __init__(self,aWxTextCtrl): + self.out=aWxTextCtrl + + def write(self,string): + self.out.WriteText(string) + wx.GetApp().Yield() + + def fileno(self): + return 1 + + def flush(self): + pass + +class RedirectLabel(object): + def __init__(self,aWxTextCtrl): + self.out=aWxTextCtrl + + def write(self,string): + if string.endswith("MB/s"): + self.out.SetLabel(string) + self.out.Centre(wx.HORIZONTAL) + wx.GetApp().Yield() + +class RedirectLabelAll(object): + def __init__(self,aWxTextCtrl): + self.out=aWxTextCtrl + + def write(self,string): + self.out.SetLabel(string) + self.out.Centre(wx.HORIZONTAL) + wx.GetApp().Yield() \ No newline at end of file diff --git a/resources/sys_patch_detect.py b/resources/sys_patch_detect.py new file mode 100644 index 000000000..7d8ff4ef0 --- /dev/null +++ b/resources/sys_patch_detect.py @@ -0,0 +1,166 @@ +from resources import constants, device_probe, utilities +from data import model_array, os_data, smbios_data, cpu_data + +class detect_root_patch: + def __init__(self, model, versions): + self.model = model + self.constants: constants.Constants() = versions + self.computer = self.constants.computer + + # GPU Patch Detection + self.nvidia_legacy= False + self.kepler_gpu= False + self.amd_ts1= False + self.amd_ts2= False + self.iron_gpu= False + self.sandy_gpu= False + self.ivy_gpu= False + + # Misc Patch Detection + self.brightness_legacy= False + self.legacy_audio= False + self.legacy_wifi= False + self.legacy_gmux= False + self.legacy_keyboard_backlight= False + + # Patch Requirements + self.amfi_must_disable= False + self.check_board_id= False + self.supports_metal= False + + self.root_patch_dict = { + "Graphics: Nvidia Tesla": self.nvidia_legacy, + "Graphics: Nvidia Kepler": self.kepler_gpu, + "Graphics: AMD TeraScale 1": self.amd_ts1, + "Graphics: AMD TeraScale 2": self.amd_ts2, + "Graphics: Intel Ironlake": self.iron_gpu, + "Graphics: Intel Sandy Bridge": self.sandy_gpu, + "Graphics: Intel Ivy Bridge": self.ivy_gpu, + "Brightness: Legacy Backlight Control": self.brightness_legacy, + "Audio: Legacy Realtek": self.legacy_audio, + "Networking: Legacy Wireless": self.legacy_wifi, + "Miscellaneous: Legacy GMUX": self.legacy_gmux, + "Miscellaneous: Legacy Keyboard Backlight": self.legacy_keyboard_backlight, + "Settings: Requires AMFI exemption": self.amfi_must_disable, + "Settings: Requires Board ID validation": self.check_board_id, + } + + def detect_gpus(self): + gpus = self.constants.computer.gpus + if self.constants.moj_cat_accel is True: + non_metal_os = os_data.os_data.high_sierra + else: + non_metal_os = os_data.os_data.catalina + for i, gpu in enumerate(gpus): + if gpu.class_code and gpu.class_code != 0xFFFFFFFF: + print(f"- Found GPU ({i}): {utilities.friendly_hex(gpu.vendor_id)}:{utilities.friendly_hex(gpu.device_id)}") + if gpu.arch in [device_probe.NVIDIA.Archs.Tesla, device_probe.NVIDIA.Archs.Fermi]: + if self.constants.detected_os > non_metal_os: + self.nvidia_legacy = True + self.amfi_must_disable = True + # self.legacy_keyboard_backlight = self.check_legacy_keyboard_backlight() + elif gpu.arch == device_probe.NVIDIA.Archs.Kepler: + if self.constants.detected_os > os_data.os_data.big_sur: + # Kepler drivers were dropped with Beta 7 + # 12.0 Beta 5: 21.0.0 - 21A5304g + # 12.0 Beta 6: 21.1.0 - 21A5506j + # 12.0 Beta 7: 21.1.0 - 21A5522h + if self.constants.detected_os == os_data.os_data.monterey and self.constants.detected_os_minor > 0: + if "21A5506j" not in self.constants.detected_os_build: + self.kepler_gpu = True + self.supports_metal = True + elif gpu.arch == device_probe.AMD.Archs.TeraScale_1: + if self.constants.detected_os > non_metal_os: + self.amd_ts1 = True + self.amfi_must_disable = True + elif gpu.arch == device_probe.AMD.Archs.TeraScale_2: + if self.constants.detected_os > non_metal_os: + self.amd_ts2 = True + self.amfi_must_disable = True + elif gpu.arch == device_probe.Intel.Archs.Iron_Lake: + if self.constants.detected_os > non_metal_os: + self.iron_gpu = True + self.amfi_must_disable = True + elif gpu.arch == device_probe.Intel.Archs.Sandy_Bridge: + if self.constants.detected_os > non_metal_os: + self.sandy_gpu = True + self.amfi_must_disable = True + self.check_board_id = True + elif gpu.arch == device_probe.Intel.Archs.Ivy_Bridge: + if self.constants.detected_os > os_data.os_data.big_sur: + self.ivy_gpu = True + self.supports_metal = True + if self.supports_metal is True: + # Avoid patching Metal and non-Metal GPUs if both present, prioritize Metal GPU + # Main concerns are for iMac12,x with Sandy iGPU and Kepler dGPU + self.nvidia_legacy = False + self.amd_ts1 = False + self.amd_ts2 = False + self.iron_gpu = False + self.sandy_gpu = False + + def check_dgpu_status(self): + dgpu = self.constants.computer.dgpu + if dgpu: + if dgpu.class_code and dgpu.class_code == 0xFFFFFFFF: + # If dGPU is disabled via class-codes, assume demuxed + return False + return True + return False + + def detect_demux(self): + # If GFX0 is missing, assume machine was demuxed + # -wegnoegpu would also trigger this, so ensure arg is not present + if not "-wegnoegpu" in (utilities.get_nvram("boot-args") or ""): + igpu = self.constants.computer.igpu + dgpu = self.check_dgpu_status() + if igpu and not dgpu: + return True + return False + + def check_legacy_keyboard_backlight(self): + # With Big Sur and newer, Skylight patch set unfortunately breaks native keyboard backlight + # Penryn Macs are able to re-enable the keyboard backlight by simply running '/usr/libexec/TouchBarServer' + # For Arrendale and newer, this has no effect. + if self.model.startswith("MacBookPro") or self.model.startswith("MacBookAir"): + # non-Metal MacBooks never had keyboard backlight + if smbios_data.smbios_dictionary[self.model]["CPU Generation"] <= cpu_data.cpu_data.penryn.value: + if self.constants.detected_os > os_data.os_data.catalina: + return True + return False + + def detect_patch_set(self): + self.detect_gpus() + if self.model in model_array.LegacyBrightness: + if self.constants.detected_os > os_data.os_data.catalina: + self.brightness_legacy = True + + if self.model in ["iMac7,1", "iMac8,1"] or (self.model in model_array.LegacyAudio and utilities.check_kext_loaded("AppleALC", self.constants.detected_os) is False): + # Special hack for systems with botched GOPs + # TL;DR: No Boot Screen breaks Lilu, therefore breaking audio + if self.constants.detected_os > os_data.os_data.catalina: + self.legacy_audio = True + + if ( + isinstance(self.constants.computer.wifi, device_probe.Broadcom) + and self.constants.computer.wifi.chipset in [device_probe.Broadcom.Chipsets.AirPortBrcm4331, device_probe.Broadcom.Chipsets.AirPortBrcm43224] + ) or (isinstance(self.constants.computer.wifi, device_probe.Atheros) and self.constants.computer.wifi.chipset == device_probe.Atheros.Chipsets.AirPortAtheros40): + if self.constants.detected_os > os_data.os_data.big_sur: + self.legacy_wifi = True + + # if self.model in ["MacBookPro5,1", "MacBookPro5,2", "MacBookPro5,3", "MacBookPro8,2", "MacBookPro8,3"]: + if self.model in ["MacBookPro8,2", "MacBookPro8,3"]: + # Sierra uses a legacy GMUX control method needed for dGPU switching on MacBookPro5,x + # Same method is also used for demuxed machines + # Note that MacBookPro5,x machines are extremely unstable with this patch set, so disabled until investigated further + # Ref: https://github.com/dortania/OpenCore-Legacy-Patcher/files/7360909/KP-b10-030.txt + if self.constants.detected_os > os_data.os_data.high_sierra: + if self.model in ["MacBookPro8,2", "MacBookPro8,3"]: + # Ref: https://doslabelectronics.com/Demux.html + if self.detect_demux() is True: + self.legacy_gmux = True + else: + self.legacy_gmux = True + + + return self.root_patch_dict \ No newline at end of file From a17ca2c3305cd53d3928f4459adfedd2f4596999 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Wed, 22 Dec 2021 19:55:40 -0700 Subject: [PATCH 02/38] Exclude wxPython from non-GUI workflows --- .github/workflows/build-app-offline.yml | 2 +- .github/workflows/build-app.yml | 2 +- .github/workflows/build-gui.yml | 2 +- resources/sys_patch.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-app-offline.yml b/.github/workflows/build-app-offline.yml index 976994fc3..d98fe4596 100644 --- a/.github/workflows/build-app-offline.yml +++ b/.github/workflows/build-app-offline.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: python3 create_offline_build.py - - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec + - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec --exclude-module wxpython - run: ./after_pyinstaller.sh - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' - run: cd dist; zip -r ../OpenCore-Patcher-TUI-Offline.app.zip OpenCore-Patcher.app diff --git a/.github/workflows/build-app.yml b/.github/workflows/build-app.yml index 3a8014e6a..084c9ba1e 100644 --- a/.github/workflows/build-app.yml +++ b/.github/workflows/build-app.yml @@ -12,7 +12,7 @@ jobs: runs-on: x86_64_mojave steps: - uses: actions/checkout@v2 - - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec + - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec --exclude-module wxpython - run: ./after_pyinstaller.sh - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' - run: cd dist; zip -r ../OpenCore-Patcher-TUI.app.zip OpenCore-Patcher.app diff --git a/.github/workflows/build-gui.yml b/.github/workflows/build-gui.yml index 915cc3b1b..a5a126e4d 100644 --- a/.github/workflows/build-gui.yml +++ b/.github/workflows/build-gui.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec + - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec --exclude-module wxpython - run: cd dist; cp OpenCore-Patcher ../; cd ..; mv OpenCore-Patcher OCLP-CLI - name: Download latest nightly OCLP-GUI run: curl -S -L https://nightly.link/dortania/OCLP-GUI/workflows/build-app/master/OpenCore-Patcher-GUI.app.zip --output ./OpenCore-Patcher-GUI.app.zip --insecure diff --git a/resources/sys_patch.py b/resources/sys_patch.py index 92c84e516..f7dddeff1 100644 --- a/resources/sys_patch.py +++ b/resources/sys_patch.py @@ -952,7 +952,7 @@ set million colour before rebooting""" # Entry Function def start_patch(self): print("- Starting Patch Process") - print(f"- Determinging Required Patch set for Darwin {self.constants.detected_os}") + print(f"- Determining Required Patch set for Darwin {self.constants.detected_os}") self.detect_patch_set() if self.no_patch is True: change_menu = None From 3c081270130d69319379ecf6078d9b2fadd4baff Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Wed, 22 Dec 2021 20:14:06 -0700 Subject: [PATCH 03/38] Resolve wxPython bundling --- .github/workflows/build-app-offline.yml | 2 +- .github/workflows/build-app.yml | 2 +- .github/workflows/build-gui.yml | 2 +- OpenCore-Patcher.spec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-app-offline.yml b/.github/workflows/build-app-offline.yml index d98fe4596..976994fc3 100644 --- a/.github/workflows/build-app-offline.yml +++ b/.github/workflows/build-app-offline.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: python3 create_offline_build.py - - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec --exclude-module wxpython + - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec - run: ./after_pyinstaller.sh - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' - run: cd dist; zip -r ../OpenCore-Patcher-TUI-Offline.app.zip OpenCore-Patcher.app diff --git a/.github/workflows/build-app.yml b/.github/workflows/build-app.yml index 084c9ba1e..3a8014e6a 100644 --- a/.github/workflows/build-app.yml +++ b/.github/workflows/build-app.yml @@ -12,7 +12,7 @@ jobs: runs-on: x86_64_mojave steps: - uses: actions/checkout@v2 - - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec --exclude-module wxpython + - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec - run: ./after_pyinstaller.sh - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' - run: cd dist; zip -r ../OpenCore-Patcher-TUI.app.zip OpenCore-Patcher.app diff --git a/.github/workflows/build-gui.yml b/.github/workflows/build-gui.yml index a5a126e4d..915cc3b1b 100644 --- a/.github/workflows/build-gui.yml +++ b/.github/workflows/build-gui.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec --exclude-module wxpython + - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec - run: cd dist; cp OpenCore-Patcher ../; cd ..; mv OpenCore-Patcher OCLP-CLI - name: Download latest nightly OCLP-GUI run: curl -S -L https://nightly.link/dortania/OCLP-GUI/workflows/build-app/master/OpenCore-Patcher-GUI.app.zip --output ./OpenCore-Patcher-GUI.app.zip --insecure diff --git a/OpenCore-Patcher.spec b/OpenCore-Patcher.spec index 49695bf1c..02bf741a0 100644 --- a/OpenCore-Patcher.spec +++ b/OpenCore-Patcher.spec @@ -12,7 +12,7 @@ a = Analysis(['OpenCore-Patcher.command'], hiddenimports=[], hookspath=[], runtime_hooks=[], - excludes=[], + excludes=['wxPython', 'wxpython'], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, From ee0b04f05be435234673d13751b8ad92ae3a2085 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Wed, 22 Dec 2021 21:41:41 -0700 Subject: [PATCH 04/38] gui_main.py: Add SMBIOS settings --- gui/gui_main.py | 104 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index db966d253..fb1d5c945 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -10,7 +10,7 @@ import subprocess import time from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect -from data import model_array, os_data +from data import model_array, os_data, smbios_data from gui import menu_redirect class wx_python_gui: @@ -40,11 +40,19 @@ class wx_python_gui: ) self.frame.Centre(~wx.MAXIMIZE_BOX) self.frame.Show() + self.frame.Bind(wx.EVT_CLOSE, self.OnCloseFrame) self.main_menu(None) wx.CallAfter(self.frame.Close) + def OnCloseFrame(self, event): + print("Cleaning up on close") + self.frame.DestroyChildren() + self.frame.Destroy() + self.app.ExitMainLoop() + sys.exit() + def reset_window(self): self.frame.DestroyChildren() self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN) @@ -1341,6 +1349,7 @@ If you require this feature, enable '10.14/15 Accel' in Settings.""")) ) self.dropdown_model.Bind(wx.EVT_CHOICE, self.model_choice_click) self.dropdown_model.Centre(wx.HORIZONTAL) + self.dropdown_model.ToolTip = wx.ToolTip("Select the model you want to build for") # Checkboxes # Checkbox: Allow native models @@ -1348,53 +1357,72 @@ If you require this feature, enable '10.14/15 Accel' in Settings.""")) self.checkbox_allow_native_models.SetValue(self.constants.allow_oc_everywhere) self.checkbox_allow_native_models.SetPosition(wx.Point(self.dropdown_model.GetPosition().x, self.dropdown_model.GetPosition().y + self.dropdown_model.GetSize().height + 10)) self.checkbox_allow_native_models.Bind(wx.EVT_CHECKBOX, self.allow_native_models_click) + self.checkbox_allow_native_models.ToolTip = wx.ToolTip("""Select to allow OpenCore to be installed on native models +Generally used for enabling OS features Apple locks out of native Macs +ie. AirPlay to Mac, Sidecar.""") # Checkbox: Verbose self.verbose_checkbox = wx.CheckBox(self.frame, label="Verbose") self.verbose_checkbox.SetValue(self.constants.verbose_debug) self.verbose_checkbox.SetPosition(wx.Point(self.checkbox_allow_native_models.GetPosition().x, self.checkbox_allow_native_models.GetPosition().y + self.checkbox_allow_native_models.GetSize().height)) self.verbose_checkbox.Bind(wx.EVT_CHECKBOX, self.verbose_checkbox_click) + self.verbose_checkbox.ToolTip = wx.ToolTip("""Add -v (verbose) to boot-args during build""") # Checkbox: Kext Debug self.kext_checkbox = wx.CheckBox(self.frame, label="Kext Debug") self.kext_checkbox.SetValue(self.constants.kext_debug) self.kext_checkbox.SetPosition(wx.Point(self.verbose_checkbox.GetPosition().x , self.verbose_checkbox.GetPosition().y + self.verbose_checkbox.GetSize().height)) self.kext_checkbox.Bind(wx.EVT_CHECKBOX, self.kext_checkbox_click) + self.kext_checkbox.ToolTip = wx.ToolTip("""Enables additional kext logging, including expanded message buffer""") # Checkbox: OpenCore Debug self.opencore_checkbox = wx.CheckBox(self.frame, label="OpenCore Debug") self.opencore_checkbox.SetValue(self.constants.opencore_debug) self.opencore_checkbox.SetPosition(wx.Point(self.kext_checkbox.GetPosition().x , self.kext_checkbox.GetPosition().y + self.kext_checkbox.GetSize().height)) self.opencore_checkbox.Bind(wx.EVT_CHECKBOX, self.oc_checkbox_click) + self.opencore_checkbox.ToolTip = wx.ToolTip("""Enables OpenCore logging, can heavily impact boot times""") # Checkbox: SIP self.sip_checkbox = wx.CheckBox(self.frame, label="SIP") self.sip_checkbox.SetValue(self.constants.sip_status) self.sip_checkbox.SetPosition(wx.Point(self.opencore_checkbox.GetPosition().x , self.opencore_checkbox.GetPosition().y + self.opencore_checkbox.GetSize().height)) self.sip_checkbox.Bind(wx.EVT_CHECKBOX, self.sip_checkbox_click) + self.sip_checkbox.ToolTip = wx.ToolTip("""Sets SIP, disable to allow root patching""") # Checkbox: SecureBootModel self.secureboot_checkbox = wx.CheckBox(self.frame, label="SecureBootModel") self.secureboot_checkbox.SetValue(self.constants.secure_status) self.secureboot_checkbox.SetPosition(wx.Point(self.sip_checkbox.GetPosition().x , self.sip_checkbox.GetPosition().y + self.sip_checkbox.GetSize().height)) self.secureboot_checkbox.Bind(wx.EVT_CHECKBOX, self.secureboot_checkbox_click) + self.secureboot_checkbox.ToolTip = wx.ToolTip("""Sets SecureBootModel, useful for models spoofing T2 Macs to get OTA updates""") # Checkbox: Show Boot Picker self.bootpicker_checkbox = wx.CheckBox(self.frame, label="Show Boot Picker") self.bootpicker_checkbox.SetValue(self.constants.showpicker) self.bootpicker_checkbox.SetPosition(wx.Point(self.secureboot_checkbox.GetPosition().x , self.secureboot_checkbox.GetPosition().y + self.secureboot_checkbox.GetSize().height)) self.bootpicker_checkbox.Bind(wx.EVT_CHECKBOX, self.show_picker_checkbox_click) + self.bootpicker_checkbox.ToolTip = wx.ToolTip("""Shows OpenCore's Boot Picker on machine start +Toggling this off will hide the picker, and only load when holding either Option or Escape""") # Checkbox: Allow Accel on Mojave/Catalina self.accel_checkbox = wx.CheckBox(self.frame, label="Allow Accel on 10.14/15") self.accel_checkbox.SetValue(self.constants.moj_cat_accel) self.accel_checkbox.SetPosition(wx.Point(self.bootpicker_checkbox.GetPosition().x , self.bootpicker_checkbox.GetPosition().y + self.bootpicker_checkbox.GetSize().height)) self.accel_checkbox.Bind(wx.EVT_CHECKBOX, self.accel_checkbox_click) + self.accel_checkbox.ToolTip = wx.ToolTip("""Allows Root Patching on Mojave/Catalina +Useful for enabling TeraScale 2 Acceleration when not provided by dosdude1's patcher""") + # Buttons + # Button: SMBIOS Settings + self.smbios_button = wx.Button(self.frame, label="SMBIOS Settings", size=(150,30)) + self.smbios_button.SetPosition(wx.Point(self.accel_checkbox.GetPosition().x , self.accel_checkbox.GetPosition().y + self.accel_checkbox.GetSize().height + 10)) + self.smbios_button.Bind(wx.EVT_BUTTON, self.smbios_settings_menu) + self.smbios_button.Center(wx.HORIZONTAL) + # Button: Developer Settings self.miscellaneous_button = wx.Button(self.frame, label="Developer Settings", size=(150,30)) - self.miscellaneous_button.SetPosition(wx.Point(self.accel_checkbox.GetPosition().x , self.accel_checkbox.GetPosition().y + self.accel_checkbox.GetSize().height + 10)) + self.miscellaneous_button.SetPosition(wx.Point(self.smbios_button.GetPosition().x , self.smbios_button.GetPosition().y + self.smbios_button.GetSize().height)) self.miscellaneous_button.Bind(wx.EVT_BUTTON, self.misc_settings_menu) self.miscellaneous_button.Centre(wx.HORIZONTAL) @@ -1751,4 +1779,74 @@ If you require this feature, enable '10.14/15 Accel' in Settings.""")) self.constants.metal_build = False print(f"GPU Vendor: {self.constants.imac_vendor}") - print(f"GPU Model: {self.constants.imac_model}") \ No newline at end of file + print(f"GPU Model: {self.constants.imac_model}") + + def smbios_settings_menu(self, event=None): + self.frame.DestroyChildren() + + # Header: SMBIOS Settings + self.smbios_settings_header = wx.StaticText(self.frame, label="SMBIOS Settings", pos=wx.Point(10, 10)) + self.smbios_settings_header.SetFont(wx.Font(16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.smbios_settings_header.Center(wx.HORIZONTAL) + + # Label: SMBIOS Spoof Level + self.smbios_spoof_level_label = wx.StaticText(self.frame, label="SMBIOS Spoof Level") + self.smbios_spoof_level_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.smbios_spoof_level_label.SetPosition( + wx.Point(self.smbios_settings_header.GetPosition().x, self.smbios_settings_header.GetPosition().y + self.smbios_settings_header.GetSize().height + 10) + ) + self.smbios_spoof_level_label.Center(wx.HORIZONTAL) + + # Dropdown: SMBIOS Spoof Level + self.smbios_dropdown = wx.Choice(self.frame) + self.smbios_dropdown.SetPosition( + wx.Point(self.smbios_spoof_level_label.GetPosition().x, self.smbios_spoof_level_label.GetPosition().y + self.smbios_spoof_level_label.GetSize().height + 10) + ) + self.smbios_dropdown.AppendItems(["None", "Minimal", "Moderate", "Advanced"]) + self.smbios_dropdown.SetStringSelection(self.constants.serial_settings) + self.smbios_dropdown.Bind(wx.EVT_CHOICE, self.smbios_spoof_level_click) + self.smbios_dropdown.Center(wx.HORIZONTAL) + + # Label: SMBIOS Spoof Model + self.smbios_spoof_model_label = wx.StaticText(self.frame, label="SMBIOS Spoof Model") + self.smbios_spoof_model_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.smbios_spoof_model_label.SetPosition( + wx.Point(self.smbios_dropdown.GetPosition().x, self.smbios_dropdown.GetPosition().y + self.smbios_dropdown.GetSize().height + 10) + ) + self.smbios_spoof_model_label.Center(wx.HORIZONTAL) + + # Dropdown: SMBIOS Spoof Model + self.smbios_model_dropdown = wx.Choice(self.frame) + self.smbios_model_dropdown.SetPosition( + wx.Point(self.smbios_spoof_model_label.GetPosition().x, self.smbios_spoof_model_label.GetPosition().y + self.smbios_spoof_model_label.GetSize().height + 10) + ) + for model in smbios_data.smbios_dictionary: + if "_" not in model and " " not in model: + if smbios_data.smbios_dictionary[model]["Board ID"] is not None: + self.smbios_model_dropdown.Append(model) + self.smbios_model_dropdown.Append("Default") + self.smbios_model_dropdown.SetStringSelection(self.constants.override_smbios) + self.smbios_model_dropdown.Bind(wx.EVT_CHOICE, self.smbios_model_click) + self.smbios_model_dropdown.Center(wx.HORIZONTAL) + + # Button: Return to Main Menu + self.return_to_main_menu_button = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu_button.SetPosition( + wx.Point(self.smbios_model_dropdown.GetPosition().x, self.smbios_model_dropdown.GetPosition().y + self.smbios_model_dropdown.GetSize().height + 10) + ) + self.return_to_main_menu_button.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu_button.Center(wx.HORIZONTAL) + + self.frame.SetSize(wx.Size(-1, self.return_to_main_menu_button.GetPosition().y + self.return_to_main_menu_button.GetSize().height + 40)) + + + + def smbios_spoof_level_click(self, event=None): + selection = self.smbios_dropdown.GetStringSelection() + print(f"SMBIOS Spoof Level: {selection}") + self.constants.serial_settings = selection + + def smbios_model_click(self, event=None): + selection = self.smbios_model_dropdown.GetStringSelection() + print(f"SMBIOS Spoof Model: {selection}") + self.constants.override_smbios = selection From 0e25f2f3cf63cea662c160e2fd2fd0d5e5be1cba Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Thu, 23 Dec 2021 19:27:12 -0700 Subject: [PATCH 05/38] GUI.spec: Add Minimum version Ensure users do not launch wxPython binary on 10.9, due to missing dylib concerns --- OpenCore-Patcher-GUI.spec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenCore-Patcher-GUI.spec b/OpenCore-Patcher-GUI.spec index 82dd073da..4ddd078f1 100644 --- a/OpenCore-Patcher-GUI.spec +++ b/OpenCore-Patcher-GUI.spec @@ -46,5 +46,6 @@ app = BUNDLE(exe, bundle_identifier=None, info_plist={ "CFBundleShortVersionString": constants.Constants().patcher_version, - "NSHumanReadableCopyright": "Copyright 2020-2021 Dortania" + "NSHumanReadableCopyright": "Copyright 2020-2021 Dortania", + "LSMinimumSystemVersion": "10.10.0", }) From 3c929edd4bde6ad29a0f07bc99d5e3ce4c7a9e14 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 24 Dec 2021 10:21:46 -0700 Subject: [PATCH 06/38] gui_main: Add WriteFlash Configurability --- gui/gui_main.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index fb1d5c945..5caa97414 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -1653,13 +1653,20 @@ Useful for enabling TeraScale 2 Acceleration when not provided by dosdude1's pat self.disable_cpu_friend_checkbox.GetPosition().x, self.disable_cpu_friend_checkbox.GetPosition().y + self.disable_cpu_friend_checkbox.GetSize().height)) + # Set WriteFlash + self.set_writeflash_checkbox = wx.CheckBox(self.frame, label="Set NVRAM WriteFlash") + self.set_writeflash_checkbox.SetValue(self.constants.nvram_write) + self.set_writeflash_checkbox.Bind(wx.EVT_CHECKBOX, self.set_writeflash_click) + self.set_writeflash_checkbox.SetPosition(wx.Point( + self.apple_alc_checkbox.GetPosition().x, + self.apple_alc_checkbox.GetPosition().y + self.apple_alc_checkbox.GetSize().height)) # Button: return to main menu self.return_to_main_menu_button = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu_button.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu_button.SetPosition(wx.Point( - self.apple_alc_checkbox.GetPosition().x, - self.apple_alc_checkbox.GetPosition().y + self.apple_alc_checkbox.GetSize().height + 10)) + self.set_writeflash_checkbox.GetPosition().x, + self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height + 10)) self.return_to_main_menu_button.Center(wx.HORIZONTAL) # set frame size below return to main menu button @@ -1780,6 +1787,14 @@ Useful for enabling TeraScale 2 Acceleration when not provided by dosdude1's pat print(f"GPU Vendor: {self.constants.imac_vendor}") print(f"GPU Model: {self.constants.imac_model}") + + def set_writeflash_click(self, event=None): + if self.set_writeflash_checkbox.GetValue(): + print("Write Flash Enabled") + self.constants.nvram_write = True + else: + print("Write Flash Disabled") + self.constants.nvram_write = False def smbios_settings_menu(self, event=None): self.frame.DestroyChildren() From 5b97685274e5cee25a68b84714c3a528082d4537 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 24 Dec 2021 10:22:51 -0700 Subject: [PATCH 07/38] GUI.spec: Add Dark Mode support for binaries Running from source will launch as lightmode due to older SDK used in Python --- OpenCore-Patcher-GUI.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenCore-Patcher-GUI.spec b/OpenCore-Patcher-GUI.spec index 4ddd078f1..bd16c7dd3 100644 --- a/OpenCore-Patcher-GUI.spec +++ b/OpenCore-Patcher-GUI.spec @@ -48,4 +48,6 @@ app = BUNDLE(exe, "CFBundleShortVersionString": constants.Constants().patcher_version, "NSHumanReadableCopyright": "Copyright 2020-2021 Dortania", "LSMinimumSystemVersion": "10.10.0", + "NSRequiresAquaSystemAppearance": False, + "NSHighResolutionCapable": True, }) From 86af9e96f4e4b0a1cc5fa09ae4fbe4772f21fe7d Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 24 Dec 2021 12:38:51 -0700 Subject: [PATCH 08/38] wxPython Workflow: Add legacy binary --- .github/workflows/build-app-wxpython.yml | 23 ++++++++++++++++++++++- merge_gui_legacy.py | 10 ++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 merge_gui_legacy.py diff --git a/.github/workflows/build-app-wxpython.yml b/.github/workflows/build-app-wxpython.yml index 6f8fb09e1..a7e74f951 100644 --- a/.github/workflows/build-app-wxpython.yml +++ b/.github/workflows/build-app-wxpython.yml @@ -13,14 +13,24 @@ jobs: steps: - uses: actions/checkout@v2 - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher-GUI.spec + - run: cp -r dist/OpenCore-Patcher.app OpenCore-Patcher-Legacy.app + - run: cp payloads/launcher.sh dist/OpenCore-Patcher-Legacy.app/Contents/MacOS/Launcher + - run: python3 merge_gui_legacy.py - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' + - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher-Legacy.app"' - run: cd dist; zip -r ../OpenCore-Patcher-wxPython.app.zip OpenCore-Patcher.app + - run: cd dist; zip -r ../OpenCore-Patcher-wxPython-Legacy.app.zip OpenCore-Patcher-Legacy.app - run: ./../sign-wxpython.sh - name: Upload App to Artifacts uses: actions/upload-artifact@v2 with: - name: OpenCore-Patcher-wxPython.app + name: OpenCore-Patcher-wxPython.app (macOS 10.13 and newer) path: OpenCore-Patcher-wxPython.app.zip + - name: Upload Legacy App to Artifacts + uses: actions/upload-artifact@v2 + with: + name: OpenCore-Patcher-wxPython.app (macOS 10.12 and older) + path: OpenCore-Patcher-wxPython-Legacy.app.zip - name: Upload to Release if: github.event_name == 'release' @@ -30,3 +40,14 @@ jobs: file: OpenCore-Patcher-wxPython.app.zip tag: ${{ github.ref }} file_glob: true + asset_name: OpenCore-Patcher-wxPython.app (macOS 10.13 and newer) + + - name: Upload Legacy to Release + if: github.event_name == 'release' + uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: OpenCore-Patcher-wxPython-Legacy.app.zip + tag: ${{ github.ref }} + file_glob: true + asset_name: OpenCore-Patcher-wxPython.app (macOS 10.12 and older) diff --git a/merge_gui_legacy.py b/merge_gui_legacy.py new file mode 100644 index 000000000..d545af9e5 --- /dev/null +++ b/merge_gui_legacy.py @@ -0,0 +1,10 @@ +# Updates build version in OCLP-GUI during CI builds +# Copyright (C) 2021 Mykola Grymalyuk +import plistlib +from pathlib import Path +from resources import constants + +app_path = Path.cwd() / Path ("OpenCore-Patcher-Legacy.app/Contents/Info.plist") +info = plistlib.load(Path(app_path).open("rb")) +info["CFBundleExecutable"] = "Launcher" +plistlib.dump(info, Path(app_path).open("wb"), sort_keys=True) \ No newline at end of file From 5ed5f3aa15658a39310b995a7453c1fa08e578be Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 24 Dec 2021 12:44:08 -0700 Subject: [PATCH 09/38] Fix run --- .github/workflows/build-app-wxpython.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-app-wxpython.yml b/.github/workflows/build-app-wxpython.yml index a7e74f951..ac4cfc6aa 100644 --- a/.github/workflows/build-app-wxpython.yml +++ b/.github/workflows/build-app-wxpython.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher-GUI.spec - - run: cp -r dist/OpenCore-Patcher.app OpenCore-Patcher-Legacy.app + - run: cp -r dist/OpenCore-Patcher.app dist/OpenCore-Patcher-Legacy.app - run: cp payloads/launcher.sh dist/OpenCore-Patcher-Legacy.app/Contents/MacOS/Launcher - run: python3 merge_gui_legacy.py - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' From 66a2d67ed95b4bc0918209e791217242cf786531 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 24 Dec 2021 12:48:31 -0700 Subject: [PATCH 10/38] Temp kill additional runs --- ...{build-app-offline.yml => build-app-offline.disable-yml.yml} | 0 .github/workflows/{build-app.yml => build-app.disable-yml.yml} | 0 .github/workflows/{build-gui.yml => build-gui.disable-yml.yml} | 0 .../workflows/{build-site.yml => build-site.disable-yml.yml} | 0 merge_gui_legacy.py | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{build-app-offline.yml => build-app-offline.disable-yml.yml} (100%) rename .github/workflows/{build-app.yml => build-app.disable-yml.yml} (100%) rename .github/workflows/{build-gui.yml => build-gui.disable-yml.yml} (100%) rename .github/workflows/{build-site.yml => build-site.disable-yml.yml} (100%) diff --git a/.github/workflows/build-app-offline.yml b/.github/workflows/build-app-offline.disable-yml.yml similarity index 100% rename from .github/workflows/build-app-offline.yml rename to .github/workflows/build-app-offline.disable-yml.yml diff --git a/.github/workflows/build-app.yml b/.github/workflows/build-app.disable-yml.yml similarity index 100% rename from .github/workflows/build-app.yml rename to .github/workflows/build-app.disable-yml.yml diff --git a/.github/workflows/build-gui.yml b/.github/workflows/build-gui.disable-yml.yml similarity index 100% rename from .github/workflows/build-gui.yml rename to .github/workflows/build-gui.disable-yml.yml diff --git a/.github/workflows/build-site.yml b/.github/workflows/build-site.disable-yml.yml similarity index 100% rename from .github/workflows/build-site.yml rename to .github/workflows/build-site.disable-yml.yml diff --git a/merge_gui_legacy.py b/merge_gui_legacy.py index d545af9e5..156e5f765 100644 --- a/merge_gui_legacy.py +++ b/merge_gui_legacy.py @@ -4,7 +4,7 @@ import plistlib from pathlib import Path from resources import constants -app_path = Path.cwd() / Path ("OpenCore-Patcher-Legacy.app/Contents/Info.plist") +app_path = Path.cwd() / Path ("dist/OpenCore-Patcher-Legacy.app/Contents/Info.plist") info = plistlib.load(Path(app_path).open("rb")) info["CFBundleExecutable"] = "Launcher" plistlib.dump(info, Path(app_path).open("wb"), sort_keys=True) \ No newline at end of file From 3884ca77d5e7e35db841dfc5cc548a6df7409575 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 24 Dec 2021 16:02:06 -0700 Subject: [PATCH 11/38] gui.py: Ensure emojis supports 10.10-10.13 --- ...{build-app-offline.disable-yml.yml => build-app-offline.yml} | 0 .github/workflows/{build-app.disable-yml.yml => build-app.yml} | 0 .github/workflows/{build-gui.disable-yml.yml => build-gui.yml} | 0 .../workflows/{build-site.disable-yml.yml => build-site.yml} | 0 gui/gui_main.py | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{build-app-offline.disable-yml.yml => build-app-offline.yml} (100%) rename .github/workflows/{build-app.disable-yml.yml => build-app.yml} (100%) rename .github/workflows/{build-gui.disable-yml.yml => build-gui.yml} (100%) rename .github/workflows/{build-site.disable-yml.yml => build-site.yml} (100%) diff --git a/.github/workflows/build-app-offline.disable-yml.yml b/.github/workflows/build-app-offline.yml similarity index 100% rename from .github/workflows/build-app-offline.disable-yml.yml rename to .github/workflows/build-app-offline.yml diff --git a/.github/workflows/build-app.disable-yml.yml b/.github/workflows/build-app.yml similarity index 100% rename from .github/workflows/build-app.disable-yml.yml rename to .github/workflows/build-app.yml diff --git a/.github/workflows/build-gui.disable-yml.yml b/.github/workflows/build-gui.yml similarity index 100% rename from .github/workflows/build-gui.disable-yml.yml rename to .github/workflows/build-gui.yml diff --git a/.github/workflows/build-site.disable-yml.yml b/.github/workflows/build-site.yml similarity index 100% rename from .github/workflows/build-site.disable-yml.yml rename to .github/workflows/build-site.yml diff --git a/gui/gui_main.py b/gui/gui_main.py index 5caa97414..24c6886e7 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -482,7 +482,7 @@ If you require this feature, enable '10.14/15 Accel' in Settings.""")) self.subheader.Centre(wx.HORIZONTAL) # Build OpenCore - self.build_opencore = wx.Button(self.frame, label="🧱 Build OpenCore", size=(150,30)) + self.build_opencore = wx.Button(self.frame, label="🔨 Build OpenCore", size=(150,30)) self.build_opencore.SetPosition( wx.Point( self.header.GetPosition().x, From 0d72f46cb4e0d7c955a568aa3eeb8198c286bdf3 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 24 Dec 2021 16:25:19 -0700 Subject: [PATCH 12/38] gui.py: Keep string in one line Avoids some IDEs incorrectly collapsing functions (ie. VSCode) --- gui/gui_main.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index 24c6886e7..73d134119 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -296,9 +296,7 @@ class wx_python_gui: self.constants.custom_model is None and \ self.computer.real_model not in model_array.SupportedSMBIOS: self.build_install.Disable() - self.build_install.SetToolTip(wx.ToolTip("""If building for a native Mac model, -select 'Allow Native Models' in Settings. -If building for another Mac, change model in Settings""")) + self.build_install.SetToolTip(wx.ToolTip("""If building for a native Mac model, \nselect 'Allow Native Models' in Settings.\nIf building for another Mac, change model in Settings""")) # Post Install Root Patch self.post_install = wx.Button(self.frame, label="Post Install Root Patch", size=(200,30)) @@ -311,8 +309,7 @@ If building for another Mac, change model in Settings""")) self.post_install.Bind(wx.EVT_BUTTON, self.root_patch_menu) self.post_install.Centre(wx.HORIZONTAL) if self.constants.detected_os in [os_data.os_data.mojave, os_data.os_data.catalina] and self.constants.moj_cat_accel == False: - self.post_install.SetToolTip(wx.ToolTip("""Graphics Acceleration fro Mojave and Catalina is currently experimental. -If you require this feature, enable '10.14/15 Accel' in Settings.""")) + self.post_install.SetToolTip(wx.ToolTip("""Graphics Acceleration fro Mojave and Catalina is currently experimental. \nIf you require this feature, enable '10.14/15 Accel' in Settings.""")) self.post_install.Disable() elif self.constants.detected_os < os_data.os_data.mojave: self.post_install.SetToolTip(wx.ToolTip("""Root Patching is only available for Mojave and newer.""")) @@ -1357,9 +1354,7 @@ If you require this feature, enable '10.14/15 Accel' in Settings.""")) self.checkbox_allow_native_models.SetValue(self.constants.allow_oc_everywhere) self.checkbox_allow_native_models.SetPosition(wx.Point(self.dropdown_model.GetPosition().x, self.dropdown_model.GetPosition().y + self.dropdown_model.GetSize().height + 10)) self.checkbox_allow_native_models.Bind(wx.EVT_CHECKBOX, self.allow_native_models_click) - self.checkbox_allow_native_models.ToolTip = wx.ToolTip("""Select to allow OpenCore to be installed on native models -Generally used for enabling OS features Apple locks out of native Macs -ie. AirPlay to Mac, Sidecar.""") + self.checkbox_allow_native_models.ToolTip = wx.ToolTip("""Select to allow OpenCore to be installed on native models\nGenerally used for enabling OS features Apple locks out of native Macs\nie. AirPlay to Mac, Sidecar.""") # Checkbox: Verbose self.verbose_checkbox = wx.CheckBox(self.frame, label="Verbose") @@ -1401,16 +1396,14 @@ ie. AirPlay to Mac, Sidecar.""") self.bootpicker_checkbox.SetValue(self.constants.showpicker) self.bootpicker_checkbox.SetPosition(wx.Point(self.secureboot_checkbox.GetPosition().x , self.secureboot_checkbox.GetPosition().y + self.secureboot_checkbox.GetSize().height)) self.bootpicker_checkbox.Bind(wx.EVT_CHECKBOX, self.show_picker_checkbox_click) - self.bootpicker_checkbox.ToolTip = wx.ToolTip("""Shows OpenCore's Boot Picker on machine start -Toggling this off will hide the picker, and only load when holding either Option or Escape""") + self.bootpicker_checkbox.ToolTip = wx.ToolTip("""Shows OpenCore's Boot Picker on machine start\nToggling this off will hide the picker, and only load when holding either Option or Escape""") # Checkbox: Allow Accel on Mojave/Catalina self.accel_checkbox = wx.CheckBox(self.frame, label="Allow Accel on 10.14/15") self.accel_checkbox.SetValue(self.constants.moj_cat_accel) self.accel_checkbox.SetPosition(wx.Point(self.bootpicker_checkbox.GetPosition().x , self.bootpicker_checkbox.GetPosition().y + self.bootpicker_checkbox.GetSize().height)) self.accel_checkbox.Bind(wx.EVT_CHECKBOX, self.accel_checkbox_click) - self.accel_checkbox.ToolTip = wx.ToolTip("""Allows Root Patching on Mojave/Catalina -Useful for enabling TeraScale 2 Acceleration when not provided by dosdude1's patcher""") + self.accel_checkbox.ToolTip = wx.ToolTip("""Allows Root Patching on Mojave/Catalina\nUseful for enabling TeraScale 2 Acceleration when not provided by dosdude1's patcher""") # Buttons From c9cb6db0e464ceb99aaa8960b6f56f64e6a02f04 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sat, 25 Dec 2021 13:55:16 -0700 Subject: [PATCH 13/38] gui.py: Add better stdout printing --- gui/gui_main.py | 53 ++++++++++++++++++++++++------------------ resources/installer.py | 7 +++--- resources/main.py | 2 ++ 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index 73d134119..be7f8fed5 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -848,8 +848,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - sys.stdout = menu_redirect.RedirectText(self.text_box) - # Update frame height to right below return_to_main_menu self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) @@ -863,23 +861,22 @@ class wx_python_gui: else: self.text_box.AppendText("- Starting OCLP-CLI via Python\n") args = [self.constants.oclp_helper_path, self.constants.launcher_binary, self.constants.launcher_script, "--unpatch_sys_vol"] - # process = subprocess.Popen( - # args, - # stdout=subprocess.PIPE, - # # stderr=subprocess.PIPE - # ) - # # Print each line of output - # while process.wait() is None: - # for line in process.stdout: - # self.text_box.AppendText(line.decode("utf-8")) - # Wait for process to finish - self.text_box.AppendText("- Remaining code is not yet implemented\n") - + process = subprocess.Popen( + args, + stdout=subprocess.PIPE, + # stderr=subprocess.PIPE + ) wx.GetApp().Yield() - # for line in process.stdout: - # self.text_box.AppendText(line.decode("utf-8")) - - + while True: + line = process.stdout.readline() + wx.GetApp().Yield() + if line.strip() == "": + pass + else: + self.text_box.AppendText(line) + if not line: break + + process.wait() def create_macos_menu(self, event=None): # Define Menu @@ -1223,7 +1220,7 @@ class wx_python_gui: self.creating_macos_installer_label.Centre(wx.HORIZONTAL) # Label: Developer Note: createinstallmedia output currently not implemented - self.developer_note_label = wx.StaticText(self.frame, label="Developer Note: createinstallmedia output currently not implemented") + self.developer_note_label = wx.StaticText(self.frame, label="Developer Note: createinstallmedia output will print after finishing") self.developer_note_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) self.developer_note_label.SetPosition( # Set Position below header @@ -1252,7 +1249,7 @@ class wx_python_gui: # Centre the text box to top of window self.stdout_text.Centre(wx.HORIZONTAL) self.stdout_text.SetValue("") - sys.stdout=menu_redirect.RedirectText(self.stdout_text) + # sys.stdout=menu_redirect.RedirectText(self.stdout_text) # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") @@ -1281,17 +1278,29 @@ class wx_python_gui: wx.GetApp().Yield() time.sleep(1) sys.stdout=menu_redirect.RedirectText(self.stdout_text) - cim_start = subprocess.run( + cim_start = subprocess.Popen( [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path], stdout=subprocess.PIPE, # stderr=subprocess.STDOUT ) + wx.GetApp().Yield() + while True: + line = cim_start.stdout.readline() + wx.GetApp().Yield() + if line.strip() == "": + pass + else: + self.stdout_text.AppendText(line) + if not line: break + + cim_start.wait() + if cim_start.returncode == 0: print("Installer created successfully!") else: print("Installer creation failed") - print(cim_start.returncode) + print(f"Return Code {cim_start.returncode}") sys.stdout = self.stock_stdout else: print("- Failed to create installer script") diff --git a/resources/installer.py b/resources/installer.py index 261a4d0eb..2b6822d77 100644 --- a/resources/installer.py +++ b/resources/installer.py @@ -245,8 +245,9 @@ def generate_installer_creation_script(script_location, installer_path, disk): with script_location.open("w") as script: script.write(f'''#!/bin/bash -diskutil eraseDisk HFS+ OCLP-Installer {disk} -"{createinstallmedia_path}" --volume /Volumes/OCLP-Installer --nointeraction +earse_disk='diskutil eraseDisk HFS+ OCLP-Installer {disk}' +if $earse_disk; then + "{createinstallmedia_path}" --volume /Volumes/OCLP-Installer --nointeraction +fi ''') - return True \ No newline at end of file diff --git a/resources/main.py b/resources/main.py index 6bcce3169..acc715681 100644 --- a/resources/main.py +++ b/resources/main.py @@ -33,6 +33,8 @@ class OpenCoreLegacyPatcher: if "python" in launcher_binary: # We're running from source launcher_script = __file__ + if "main.py" in launcher_script: + launcher_script = launcher_script.replace("/resources/main.py", "/OpenCore-Patcher-GUI.command") self.constants.launcher_binary = launcher_binary self.constants.launcher_script = launcher_script defaults.generate_defaults.probe(self.computer.real_model, True, self.constants) From 6d917fbc29b72b15fa6c0ea721c3826c5cf78371 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sat, 25 Dec 2021 18:54:54 -0700 Subject: [PATCH 14/38] gui.py: Adjust Download IA page subheader --- gui/gui_main.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index be7f8fed5..ec45d5bd0 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -979,7 +979,19 @@ class wx_python_gui: self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.header.Centre(wx.HORIZONTAL) - i = -15 + # Subheader: + self.subheader = wx.StaticText(self.frame, label="Installers currently available from Apple:") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.subheader.SetPosition( + # Set Position below header + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + i = -20 for app in avalible_installers: print(f"macOS {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']} - {utilities.human_fmt(avalible_installers[app]['Size'])} - {avalible_installers[app]['Source']})") self.install_selection = wx.Button(self.frame, label=f"macOS {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']} - {utilities.human_fmt(avalible_installers[app]['Size'])})", size=(250, 30)) @@ -987,8 +999,8 @@ class wx_python_gui: self.install_selection.SetPosition( # Set Position right above bottom of frame wx.Point( - self.header.GetPosition().x, - self.header.GetPosition().y + self.header.GetSize().height + i + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + i ) ) self.install_selection.Bind(wx.EVT_BUTTON, lambda event, temp=app: self.download_macos_click(f"macOS {avalible_installers[temp]['Version']} ({avalible_installers[temp]['Build']})", avalible_installers[temp]['Link'])) From a2500e50c26f7995fe34e6bca0bb6274c16f436d Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sat, 25 Dec 2021 19:24:52 -0700 Subject: [PATCH 15/38] Add error handling for failed downloads --- gui/gui_main.py | 58 ++++++++++++++++++++++------------- gui/menu_redirect.py | 3 ++ resources/cli_menu.py | 13 ++++---- resources/installer.py | 68 ++++++++++++++++++++++-------------------- resources/utilities.py | 2 +- 5 files changed, 84 insertions(+), 60 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index ec45d5bd0..44048ef8d 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -992,9 +992,22 @@ class wx_python_gui: self.subheader.Centre(wx.HORIZONTAL) i = -20 - for app in avalible_installers: - print(f"macOS {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']} - {utilities.human_fmt(avalible_installers[app]['Size'])} - {avalible_installers[app]['Source']})") - self.install_selection = wx.Button(self.frame, label=f"macOS {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']} - {utilities.human_fmt(avalible_installers[app]['Size'])})", size=(250, 30)) + if avalible_installers: + for app in avalible_installers: + print(f"macOS {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']} - {utilities.human_fmt(avalible_installers[app]['Size'])} - {avalible_installers[app]['Source']})") + self.install_selection = wx.Button(self.frame, label=f"macOS {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']} - {utilities.human_fmt(avalible_installers[app]['Size'])})", size=(250, 30)) + i = i + 25 + self.install_selection.SetPosition( + # Set Position right above bottom of frame + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + i + ) + ) + self.install_selection.Bind(wx.EVT_BUTTON, lambda event, temp=app: self.download_macos_click(f"macOS {avalible_installers[temp]['Version']} ({avalible_installers[temp]['Build']})", avalible_installers[temp]['Link'])) + self.install_selection.Centre(wx.HORIZONTAL) + else: + self.install_selection = wx.StaticText(self.frame, label="No installers available") i = i + 25 self.install_selection.SetPosition( # Set Position right above bottom of frame @@ -1003,7 +1016,7 @@ class wx_python_gui: self.subheader.GetPosition().y + self.subheader.GetSize().height + i ) ) - self.install_selection.Bind(wx.EVT_BUTTON, lambda event, temp=app: self.download_macos_click(f"macOS {avalible_installers[temp]['Version']} ({avalible_installers[temp]['Build']})", avalible_installers[temp]['Link'])) + self.install_selection.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.install_selection.Centre(wx.HORIZONTAL) # Return to Main Menu @@ -1058,25 +1071,28 @@ class wx_python_gui: self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) # Download macOS install data - installer.download_install_assistant(self.constants.payload_path, installer_link) + if installer.download_install_assistant(self.constants.payload_path, installer_link): + # Fix stdout + sys.stdout = self.stock_stdout + self.download_label.SetLabel(f"Finished Downloading {installer_name}") + self.download_label.Centre(wx.HORIZONTAL) - # Fix stdout - sys.stdout = self.stock_stdout - self.download_label.SetLabel(f"Finished Downloading {installer_name}") - self.download_label.Centre(wx.HORIZONTAL) + # Update Label: + sys.stdout=menu_redirect.RedirectLabelAll(self.download_label) + installer.install_macOS_installer(self.constants.payload_path) + sys.stdout = self.stock_stdout + # Update Label: + self.download_label.SetLabel(f"Finished Installing {installer_name}") + self.download_label.Centre(wx.HORIZONTAL) - # Update Label: - sys.stdout=menu_redirect.RedirectLabelAll(self.download_label) - installer.install_macOS_installer(self.constants.payload_path) - sys.stdout = self.stock_stdout - # Update Label: - self.download_label.SetLabel(f"Finished Installing {installer_name}") - self.download_label.Centre(wx.HORIZONTAL) - - # Set Return to Main Menu into flash_installer_menu - self.return_to_main_menu.SetLabel("Flash Installer") - self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.flash_installer_menu) - self.return_to_main_menu.Centre(wx.HORIZONTAL) + # Set Return to Main Menu into flash_installer_menu + self.return_to_main_menu.SetLabel("Flash Installer") + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.flash_installer_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + else: + sys.stdout = self.stock_stdout + self.download_label.SetLabel(f"Failed to download {installer_name}") + self.download_label.Centre(wx.HORIZONTAL) def flash_installer_menu(self, event=None): self.frame.DestroyChildren() diff --git a/gui/menu_redirect.py b/gui/menu_redirect.py index d3e76738c..b6e79d8a9 100644 --- a/gui/menu_redirect.py +++ b/gui/menu_redirect.py @@ -23,6 +23,9 @@ class RedirectLabel(object): self.out.SetLabel(string) self.out.Centre(wx.HORIZONTAL) wx.GetApp().Yield() + + def flush(self): + pass class RedirectLabelAll(object): def __init__(self,aWxTextCtrl): diff --git a/resources/cli_menu.py b/resources/cli_menu.py index 156c5168a..e228295f6 100644 --- a/resources/cli_menu.py +++ b/resources/cli_menu.py @@ -1165,11 +1165,14 @@ B. Exit self.download_macOS() def download_install_assistant(self, link): - installer.download_install_assistant(self.constants.payload_path, link) - installer.install_macOS_installer(self.constants.payload_path) - input("Press any key to continue...") - # To avoid selecting the wrong installer by mistake, let user select the correct one - self.find_local_installer() + if installer.download_install_assistant(self.constants.payload_path, link): + installer.install_macOS_installer(self.constants.payload_path) + input("Press any key to continue...") + # To avoid selecting the wrong installer by mistake, let user select the correct one + self.find_local_installer() + else: + print("Failed to start download") + input("Press any key to continue...") def download_macOS_installer(self): diff --git a/resources/installer.py b/resources/installer.py index 2b6822d77..560a18c9a 100644 --- a/resources/installer.py +++ b/resources/installer.py @@ -54,7 +54,9 @@ def create_installer(installer_path, volume_name): def download_install_assistant(download_path, ia_link): # Downloads InstallAssistant.pkg - utilities.download_file(ia_link, (Path(download_path) / Path("InstallAssistant.pkg"))) + if utilities.download_file(ia_link, (Path(download_path) / Path("InstallAssistant.pkg"))): + return True + return False def install_macOS_installer(download_path): args = [ @@ -85,41 +87,41 @@ def list_downloadable_macOS_installers(download_path, catalog): link = "https://swscan.apple.com/content/catalogs/others/index-12customerseed-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog.gz" # Download and unzip the catalog - utilities.download_file(link, (Path(download_path) / Path("seed.sucatalog.gz"))) - subprocess.run(["gunzip", "-d", "-f", Path(download_path) / Path("seed.sucatalog.gz")]) - catalog_plist = plistlib.load((Path(download_path) / Path("seed.sucatalog")).open("rb")) + if utilities.download_file(link, (Path(download_path) / Path("seed.sucatalog.gz"))): + subprocess.run(["gunzip", "-d", "-f", Path(download_path) / Path("seed.sucatalog.gz")]) + catalog_plist = plistlib.load((Path(download_path) / Path("seed.sucatalog")).open("rb")) - for item in catalog_plist["Products"]: - try: - # Check if entry has SharedSupport and BuildManifest - # Ensures only Big Sur and newer Installers are listed - catalog_plist["Products"][item]["ExtendedMetaInfo"]["InstallAssistantPackageIdentifiers"]["SharedSupport"] - catalog_plist["Products"][item]["ExtendedMetaInfo"]["InstallAssistantPackageIdentifiers"]["BuildManifest"] + for item in catalog_plist["Products"]: + try: + # Check if entry has SharedSupport and BuildManifest + # Ensures only Big Sur and newer Installers are listed + catalog_plist["Products"][item]["ExtendedMetaInfo"]["InstallAssistantPackageIdentifiers"]["SharedSupport"] + catalog_plist["Products"][item]["ExtendedMetaInfo"]["InstallAssistantPackageIdentifiers"]["BuildManifest"] - for bm_package in catalog_plist["Products"][item]["Packages"]: - if "BuildManifest.plist" in bm_package["URL"]: - utilities.download_file(bm_package["URL"], (Path(download_path) / Path("BuildManifest.plist"))) - build_plist = plistlib.load((Path(download_path) / Path("BuildManifest.plist")).open("rb")) - version = build_plist["ProductVersion"] - build = build_plist["ProductBuildVersion"] - for ia_package in catalog_plist["Products"][item]["Packages"]: - if "InstallAssistant.pkg" in ia_package["URL"]: - download_link = ia_package["URL"] - size = ia_package["Size"] - integrity = ia_package["IntegrityDataURL"] + for bm_package in catalog_plist["Products"][item]["Packages"]: + if "BuildManifest.plist" in bm_package["URL"]: + utilities.download_file(bm_package["URL"], (Path(download_path) / Path("BuildManifest.plist"))) + build_plist = plistlib.load((Path(download_path) / Path("BuildManifest.plist")).open("rb")) + version = build_plist["ProductVersion"] + build = build_plist["ProductBuildVersion"] + for ia_package in catalog_plist["Products"][item]["Packages"]: + if "InstallAssistant.pkg" in ia_package["URL"]: + download_link = ia_package["URL"] + size = ia_package["Size"] + integrity = ia_package["IntegrityDataURL"] - avalible_apps.update({ - item: { - "Version": version, - "Build": build, - "Link": download_link, - "Size": size, - "integrity": integrity, - "Source": "Apple Inc.", - } - }) - except KeyError: - pass + avalible_apps.update({ + item: { + "Version": version, + "Build": build, + "Link": download_link, + "Size": size, + "integrity": integrity, + "Source": "Apple Inc.", + } + }) + except KeyError: + pass return avalible_apps def format_drive(disk_id): diff --git a/resources/utilities.py b/resources/utilities.py index 4cabdfb91..115b2d7e1 100644 --- a/resources/utilities.py +++ b/resources/utilities.py @@ -373,7 +373,7 @@ def download_file(link, location, is_gui=None): print(f"https://github.com/dortania/OpenCore-Legacy-Patcher/releases/download/{constants.Constants().patcher_version}/OpenCore-Patcher-TUI-Offline.app.zip") else: print(link) - sys.exit() + return None def elevated(*args, **kwargs) -> subprocess.CompletedProcess: # When runnign through our GUI, we run as root, however we do not get uid 0 From e9e72d9641c7070aa8c45461a3753e1af8cea5e8 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sun, 26 Dec 2021 09:50:27 -0700 Subject: [PATCH 16/38] gui.py: Sort Installer dl before presenting --- gui/gui_main.py | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index 44048ef8d..f40881dc2 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -586,7 +586,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.install_button.GetPosition().x, self.install_button.GetPosition().y + self.install_button.GetSize().height + 10 @@ -636,7 +635,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.install_button.GetPosition().x, self.install_button.GetPosition().y + self.install_button.GetSize().height + 10 @@ -680,7 +678,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.stdout_text.GetPosition().x, self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 10 @@ -755,7 +752,6 @@ class wx_python_gui: # Start Root Patching self.start_root_patching = wx.Button(self.frame, label="Start Root Patching", size=(170, -1)) self.start_root_patching.SetPosition( - # Set Position right above bottom of frame wx.Point( self.patch_label.GetPosition().x, self.patch_label.GetPosition().y + self.patch_label.GetSize().height + 10 @@ -769,7 +765,6 @@ class wx_python_gui: # Revert Root Patches self.revert_root_patches = wx.Button(self.frame, label="Revert Root Patches", size=(170, -1)) self.revert_root_patches.SetPosition( - # Set Position right above bottom of frame wx.Point( self.start_root_patching.GetPosition().x, self.start_root_patching.GetPosition().y + self.start_root_patching.GetSize().height + 3 @@ -783,7 +778,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.revert_root_patches.GetPosition().x, self.revert_root_patches.GetPosition().y + self.revert_root_patches.GetSize().height + 10 @@ -839,7 +833,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.text_box.GetPosition().x, self.text_box.GetPosition().y + self.text_box.GetSize().height + 10 @@ -864,7 +857,7 @@ class wx_python_gui: process = subprocess.Popen( args, stdout=subprocess.PIPE, - # stderr=subprocess.PIPE + stderr=subprocess.PIPE ) wx.GetApp().Yield() while True: @@ -896,7 +889,6 @@ class wx_python_gui: # Button: Download macOS Installer self.download_macos_installer = wx.Button(self.frame, label="Download macOS Installer", size=(200, 30)) self.download_macos_installer.SetPosition( - # Set Position right above bottom of frame wx.Point( self.header.GetPosition().x, self.header.GetPosition().y + self.header.GetSize().height + 10 @@ -908,7 +900,6 @@ class wx_python_gui: # Button: Use existing macOS Installer self.use_existing_macos_installer = wx.Button(self.frame, label="Use existing macOS Installer", size=(200, 30)) self.use_existing_macos_installer.SetPosition( - # Set Position right above bottom of frame wx.Point( self.download_macos_installer.GetPosition().x, self.download_macos_installer.GetPosition().y + self.download_macos_installer.GetSize().height @@ -920,7 +911,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.use_existing_macos_installer.GetPosition().x, self.use_existing_macos_installer.GetPosition().y + self.use_existing_macos_installer.GetSize().height + 10 @@ -957,7 +947,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.download_label.GetPosition().x, self.download_label.GetPosition().y + self.download_label.GetSize().height + 30 @@ -991,6 +980,11 @@ class wx_python_gui: ) self.subheader.Centre(wx.HORIZONTAL) + + # Sort Installers by 'Version' + # By default Apple adds new builds to the end of the list, so we need to sort them by version + avalible_installers = {k: v for k, v in sorted(avalible_installers.items(), key=lambda x: x[1]['Version'])} + i = -20 if avalible_installers: for app in avalible_installers: @@ -998,7 +992,6 @@ class wx_python_gui: self.install_selection = wx.Button(self.frame, label=f"macOS {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']} - {utilities.human_fmt(avalible_installers[app]['Size'])})", size=(250, 30)) i = i + 25 self.install_selection.SetPosition( - # Set Position right above bottom of frame wx.Point( self.subheader.GetPosition().x, self.subheader.GetPosition().y + self.subheader.GetSize().height + i @@ -1010,7 +1003,6 @@ class wx_python_gui: self.install_selection = wx.StaticText(self.frame, label="No installers available") i = i + 25 self.install_selection.SetPosition( - # Set Position right above bottom of frame wx.Point( self.subheader.GetPosition().x, self.subheader.GetPosition().y + self.subheader.GetSize().height + i @@ -1022,7 +1014,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.install_selection.GetPosition().x, self.install_selection.GetPosition().y + self.install_selection.GetSize().height + 10 @@ -1060,7 +1051,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.download_label.GetPosition().x, self.download_label.GetPosition().y + self.download_label.GetSize().height + 30 @@ -1111,7 +1101,6 @@ class wx_python_gui: self.install_selection = wx.Button(self.frame, label=f"{avalible_installers[app]['Short Name']}: {avalible_installers[app]['Version']} ({avalible_installers[app]['Build']})", size=(300, 30)) i = i + 25 self.install_selection.SetPosition( - # Set Position right above bottom of frame wx.Point( self.header.GetPosition().x, self.header.GetPosition().y + self.header.GetSize().height + i @@ -1136,7 +1125,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.install_selection.GetPosition().x, self.install_selection.GetPosition().y + self.install_selection.GetSize().height + 10 @@ -1190,7 +1178,6 @@ class wx_python_gui: self.usb_selection = wx.Button(self.frame, label=f"{disk} - {availible_disks[disk]['name']} - {utilities.human_fmt(availible_disks[disk]['size'])}", size=(300, 30)) i = i + 25 self.usb_selection.SetPosition( - # Set Position right above bottom of frame wx.Point( self.usb_selection_label.GetPosition().x, self.usb_selection_label.GetPosition().y + self.usb_selection_label.GetSize().height + i @@ -1215,7 +1202,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.usb_selection.GetPosition().x, self.usb_selection.GetPosition().y + self.usb_selection.GetSize().height + 10 @@ -1282,7 +1268,6 @@ class wx_python_gui: # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( - # Set Position right above bottom of frame wx.Point( self.stdout_text.GetPosition().x, self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 10 From 78f191dd5b6ff348fb3557f0373cac1577c60ec9 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sun, 26 Dec 2021 10:51:53 -0700 Subject: [PATCH 17/38] gui.py: Remove pathlib import --- gui/gui_main.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index f40881dc2..ffede67b4 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -5,7 +5,6 @@ import wx import sys import webbrowser -from pathlib import Path import subprocess import time @@ -1294,7 +1293,7 @@ class wx_python_gui: cim_start = subprocess.Popen( [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path], stdout=subprocess.PIPE, - # stderr=subprocess.STDOUT + stderr=subprocess.STDOUT ) wx.GetApp().Yield() From 7a7f1ce090bc2caf773cf9341e13afcce0ede4ae Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sun, 26 Dec 2021 18:01:14 -0700 Subject: [PATCH 18/38] sys_patch_detect.py: Fix detection return --- resources/sys_patch_detect.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/resources/sys_patch_detect.py b/resources/sys_patch_detect.py index 7d8ff4ef0..ede406305 100644 --- a/resources/sys_patch_detect.py +++ b/resources/sys_patch_detect.py @@ -28,22 +28,6 @@ class detect_root_patch: self.check_board_id= False self.supports_metal= False - self.root_patch_dict = { - "Graphics: Nvidia Tesla": self.nvidia_legacy, - "Graphics: Nvidia Kepler": self.kepler_gpu, - "Graphics: AMD TeraScale 1": self.amd_ts1, - "Graphics: AMD TeraScale 2": self.amd_ts2, - "Graphics: Intel Ironlake": self.iron_gpu, - "Graphics: Intel Sandy Bridge": self.sandy_gpu, - "Graphics: Intel Ivy Bridge": self.ivy_gpu, - "Brightness: Legacy Backlight Control": self.brightness_legacy, - "Audio: Legacy Realtek": self.legacy_audio, - "Networking: Legacy Wireless": self.legacy_wifi, - "Miscellaneous: Legacy GMUX": self.legacy_gmux, - "Miscellaneous: Legacy Keyboard Backlight": self.legacy_keyboard_backlight, - "Settings: Requires AMFI exemption": self.amfi_must_disable, - "Settings: Requires Board ID validation": self.check_board_id, - } def detect_gpus(self): gpus = self.constants.computer.gpus @@ -161,6 +145,22 @@ class detect_root_patch: self.legacy_gmux = True else: self.legacy_gmux = True - + + self.root_patch_dict = { + "Graphics: Nvidia Tesla": self.nvidia_legacy, + "Graphics: Nvidia Kepler": self.kepler_gpu, + "Graphics: AMD TeraScale 1": self.amd_ts1, + "Graphics: AMD TeraScale 2": self.amd_ts2, + "Graphics: Intel Ironlake": self.iron_gpu, + "Graphics: Intel Sandy Bridge": self.sandy_gpu, + "Graphics: Intel Ivy Bridge": self.ivy_gpu, + "Brightness: Legacy Backlight Control": self.brightness_legacy, + "Audio: Legacy Realtek": self.legacy_audio, + "Networking: Legacy Wireless": self.legacy_wifi, + "Miscellaneous: Legacy GMUX": self.legacy_gmux, + "Miscellaneous: Legacy Keyboard Backlight": self.legacy_keyboard_backlight, + "Settings: Requires AMFI exemption": self.amfi_must_disable, + "Settings: Requires Board ID validation": self.check_board_id, + } return self.root_patch_dict \ No newline at end of file From 98b08432fa8ecc949a69becbd18a46d073de5cff Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sun, 26 Dec 2021 18:03:25 -0700 Subject: [PATCH 19/38] gui.py: Add dev notes --- gui/gui_main.py | 100 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index ffede67b4..f305f36de 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -716,7 +716,6 @@ class wx_python_gui: self.subheader.Centre(wx.HORIZONTAL) patches = sys_patch_detect.detect_root_patch(self.computer.real_model, self.constants).detect_patch_set() - if not any(not patch.startswith("Settings") and patches[patch] is True for patch in patches): print("- No applicable patches available") patches = [] @@ -788,6 +787,91 @@ class wx_python_gui: # Update frame height to right below return_to_main_menu self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + def root_patch_start(self, event=None): + self.frame.DestroyChildren() + + self.frame.SetSize(self.WINDOW_WIDTH_BUILD, -1) + + # Header + self.header = wx.StaticText(self.frame, label="Root Patching") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Subheader + self.subheader = wx.StaticText(self.frame, label="Starting root volume patching") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + 10 + ) + ) + self.subheader.Centre(wx.HORIZONTAL) + + self.developer_note = wx.StaticText(self.frame, label="Developer Note: OCLP-CLI output will print after finishing") + self.developer_note.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.developer_note.SetPosition( + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 3 + ) + ) + self.developer_note.Centre(wx.HORIZONTAL) + + # Text Box + self.text_box = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE | wx.TE_READONLY) + self.text_box.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.text_box.SetPosition( + wx.Point( + self.developer_note.GetPosition().x, + self.developer_note.GetPosition().y + self.developer_note.GetSize().height + 3 + ) + ) + self.text_box.SetSize( + wx.Size( + self.frame.GetSize().width - 10, + self.frame.GetSize().height - self.text_box.GetPosition().y + 40 + ) + ) + self.text_box.Centre(wx.HORIZONTAL) + + # Return to Main Menu + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu.SetPosition( + wx.Point( + self.text_box.GetPosition().x, + self.text_box.GetPosition().y + self.text_box.GetSize().height + 10 + ) + ) + self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu.Centre(wx.HORIZONTAL) + + # Update frame height to right below return_to_main_menu + self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) + + wx.GetApp().Yield() + if self.constants.launcher_script is None: + self.text_box.AppendText("- Starting OCLP-CLI via Binary\n") + args = [self.constants.oclp_helper_path, self.constants.launcher_binary, "--patch_sys_vol"] + else: + self.text_box.AppendText("- Starting OCLP-CLI via Python\n") + args = [self.constants.oclp_helper_path, self.constants.launcher_binary, self.constants.launcher_script, "--patch_sys_vol"] + process = subprocess.Popen( + args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + wx.GetApp().Yield() + while True: + line = process.stdout.readline() + wx.GetApp().Yield() + if line.strip() == "": + pass + else: + self.text_box.AppendText(line) + if not line: break + process.wait() + def root_patch_revert(self, event=None): self.frame.DestroyChildren() @@ -812,13 +896,23 @@ class wx_python_gui: ) self.subheader.Centre(wx.HORIZONTAL) + self.developer_note = wx.StaticText(self.frame, label="Developer Note: OCLP-CLI output will print after finishing") + self.developer_note.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.developer_note.SetPosition( + wx.Point( + self.subheader.GetPosition().x, + self.subheader.GetPosition().y + self.subheader.GetSize().height + 3 + ) + ) + self.developer_note.Centre(wx.HORIZONTAL) + # Text Box self.text_box = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE | wx.TE_READONLY) self.text_box.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.text_box.SetPosition( wx.Point( - self.subheader.GetPosition().x, - self.subheader.GetPosition().y + self.subheader.GetSize().height + 3 + self.developer_note.GetPosition().x, + self.developer_note.GetPosition().y + self.developer_note.GetSize().height + 3 ) ) self.text_box.SetSize( From e626c79c8122b51764be36d6267adefa54bdb7d0 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sun, 26 Dec 2021 18:23:55 -0700 Subject: [PATCH 20/38] gui.py: Reroute stderr --- gui/gui_main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index f305f36de..787878cf0 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -859,7 +859,7 @@ class wx_python_gui: process = subprocess.Popen( args, stdout=subprocess.PIPE, - stderr=subprocess.PIPE + stderr=subprocess.STDOUT ) wx.GetApp().Yield() while True: @@ -950,7 +950,7 @@ class wx_python_gui: process = subprocess.Popen( args, stdout=subprocess.PIPE, - stderr=subprocess.PIPE + stderr=subprocess.STDOUT ) wx.GetApp().Yield() while True: From f512b7336a3a9e1cf64cf088075ce6045c3a2eaf Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sat, 1 Jan 2022 15:18:01 -0700 Subject: [PATCH 21/38] gui.py: Resolve Root Volume Support --- gui/gui_main.py | 327 ++++++++++++++++++++++++++++++----------- gui/menu_redirect.py | 6 +- resources/run.py | 155 +++++++++++++++++++ resources/sys_patch.py | 7 +- 4 files changed, 410 insertions(+), 85 deletions(-) create mode 100644 resources/run.py diff --git a/gui/gui_main.py b/gui/gui_main.py index 787878cf0..23fc62ced 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -7,8 +7,10 @@ import sys import webbrowser import subprocess import time +import os +import wx.adv -from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect +from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect, sys_patch, run from data import model_array, os_data, smbios_data from gui import menu_redirect @@ -21,6 +23,7 @@ class wx_python_gui: # Backup stdout for usage with wxPython self.stock_stdout = sys.stdout + self.stock_stderr = sys.stderr # Define Window Size self.WINDOW_WIDTH_MAIN = 350 @@ -56,9 +59,94 @@ class wx_python_gui: self.frame.DestroyChildren() self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN) sys.stdout = self.stock_stdout + sys.stderr = self.stock_stderr - def print_test(self, text): - print(text) + def relaunch_as_root(self, event=None): + + # Add Dialog Box asking if it's ok to relaunch as root + # If yes, relaunch as root + # If no, do nothing + + # Create Dialog Box + self.dialog = wx.MessageDialog( + self.frame, + "OpenCore Legacy Patcher needs to relaunch as admin to continue. You will be prompted to enter your password.", + "Relaunch as root?", + wx.YES_NO | wx.ICON_QUESTION + ) + + # Show Dialog Box + if self.dialog.ShowModal() == wx.ID_YES: + print("Relaunching as root") + if self.constants.launcher_script is None: + args_string = f"{self.constants.launcher_binary}""" + else: + args_string = f"{self.constants.launcher_binary} {self.constants.launcher_script}" + + args = [ + "osascript", + "-e", + f'''do shell script "{args_string}"''' + ' with prompt "OpenCore Legacy Patcher needs administrator privileges to mount your EFI."' + " with administrator privileges" + " without altering line endings", + ] + + self.frame.DestroyChildren() + self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN) + + # Header + self.header = wx.StaticText(self.frame, label="Relaunching as root") + self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.header.Centre(wx.HORIZONTAL) + + # Add count down label + self.countdown_label = wx.StaticText(self.frame, label="Closing old process in 15 seconds") + self.countdown_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + # Set below header + self.countdown_label.SetPosition( + ( + self.header.GetPosition().x + 3, + self.header.GetPosition().y + self.header.GetSize().height + 3 + ) + ) + self.countdown_label.Centre(wx.HORIZONTAL) + # Label: You can close this window if app finished relaunching + self.countdown_label2 = wx.StaticText(self.frame, label="You can close this window if app finished relaunching") + self.countdown_label2.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + # Set below countdown label + self.countdown_label2.SetPosition( + ( + self.countdown_label.GetPosition().x, + self.countdown_label.GetPosition().y + self.countdown_label.GetSize().height + 3 + ) + ) + self.countdown_label2.Centre(wx.HORIZONTAL) + + # Set frame right below countdown label + self.frame.SetSize( + ( + -1, + self.countdown_label2.GetPosition().y + self.countdown_label2.GetSize().height + 40 + ) + ) + + wx.GetApp().Yield() + subprocess.Popen( + args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT + ) + timer_val = 15 + while True: + wx.GetApp().Yield() + self.countdown_label.SetLabel(f"Closing old process in {timer_val} seconds") + time.sleep(1) + timer_val -= 1 + if timer_val == 0: + break + # Close Current Application + self.frame.Close() def not_yet_implemented_menu(self, event=None): self.frame.DestroyChildren() @@ -263,6 +351,8 @@ class wx_python_gui: # Reset Data in the event of re-run self.reset_window() + # Set header text + self.frame.SetTitle(f"OpenCore Legacy Patcher v{self.constants.patcher_version}") # Header self.header = wx.StaticText(self.frame, label=f"OpenCore Legacy Patcher v{self.constants.patcher_version}") self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) @@ -499,6 +589,7 @@ class wx_python_gui: self.stdout_text.Centre(wx.HORIZONTAL) self.stdout_text.SetValue("") sys.stdout=menu_redirect.RedirectText(self.stdout_text) + sys.stderr=menu_redirect.RedirectText(self.stdout_text) # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") @@ -519,6 +610,7 @@ class wx_python_gui: # Reset stdout sys.stdout = self.stock_stdout + sys.stderr = self.stock_stderr def install_menu(self, event=None): self.frame.DestroyChildren() @@ -666,6 +758,7 @@ class wx_python_gui: self.stdout_text.Centre(wx.HORIZONTAL) self.stdout_text.SetValue("") sys.stdout=menu_redirect.RedirectText(self.stdout_text) + sys.stderr=menu_redirect.RedirectText(self.stdout_text) # Update frame height to right below self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 40) @@ -700,7 +793,7 @@ class wx_python_gui: self.frame.DestroyChildren() # Header - self.header = wx.StaticText(self.frame, label="Post-Install Menu") + self.header = wx.StaticText(self.frame, label=f"Post-Install Menu") self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.header.Centre(wx.HORIZONTAL) @@ -755,7 +848,12 @@ class wx_python_gui: self.patch_label.GetPosition().y + self.patch_label.GetSize().height + 10 ) ) - self.start_root_patching.Bind(wx.EVT_BUTTON, self.not_yet_implemented_menu) + uid = os.geteuid() + print(f"Effective UID: {uid}") + if uid == 0: + self.start_root_patching.Bind(wx.EVT_BUTTON, self.root_patch_start) + else: + self.start_root_patching.Bind(wx.EVT_BUTTON, self.relaunch_as_root) self.start_root_patching.Centre(wx.HORIZONTAL) if not patches: self.start_root_patching.Disable() @@ -768,7 +866,10 @@ class wx_python_gui: self.start_root_patching.GetPosition().y + self.start_root_patching.GetSize().height + 3 ) ) - self.revert_root_patches.Bind(wx.EVT_BUTTON, self.root_patch_revert) + if uid == 0: + self.revert_root_patches.Bind(wx.EVT_BUTTON, self.root_patch_revert) + else: + self.revert_root_patches.Bind(wx.EVT_BUTTON, self.relaunch_as_root) self.revert_root_patches.Centre(wx.HORIZONTAL) if self.constants.detected_os < os_data.os_data.big_sur: self.revert_root_patches.Disable() @@ -808,7 +909,7 @@ class wx_python_gui: ) self.subheader.Centre(wx.HORIZONTAL) - self.developer_note = wx.StaticText(self.frame, label="Developer Note: OCLP-CLI output will print after finishing") + self.developer_note = wx.StaticText(self.frame, label="Starting shortly") self.developer_note.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.developer_note.SetPosition( wx.Point( @@ -830,7 +931,7 @@ class wx_python_gui: self.text_box.SetSize( wx.Size( self.frame.GetSize().width - 10, - self.frame.GetSize().height - self.text_box.GetPosition().y + 40 + self.frame.GetSize().height + self.text_box.GetPosition().y + 80 ) ) self.text_box.Centre(wx.HORIZONTAL) @@ -850,27 +951,16 @@ class wx_python_gui: self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) wx.GetApp().Yield() - if self.constants.launcher_script is None: - self.text_box.AppendText("- Starting OCLP-CLI via Binary\n") - args = [self.constants.oclp_helper_path, self.constants.launcher_binary, "--patch_sys_vol"] - else: - self.text_box.AppendText("- Starting OCLP-CLI via Python\n") - args = [self.constants.oclp_helper_path, self.constants.launcher_binary, self.constants.launcher_script, "--patch_sys_vol"] - process = subprocess.Popen( - args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT - ) + + sys.stdout = menu_redirect.RedirectText(self.text_box) + sys.stderr = menu_redirect.RedirectText(self.text_box) + wx.GetApp().Yield() + self.frame.Show() + sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants).start_patch() + sys.stdout = self.stock_stdout + sys.stderr = self.stock_stderr + wx.GetApp().Yield() - while True: - line = process.stdout.readline() - wx.GetApp().Yield() - if line.strip() == "": - pass - else: - self.text_box.AppendText(line) - if not line: break - process.wait() def root_patch_revert(self, event=None): self.frame.DestroyChildren() @@ -896,7 +986,7 @@ class wx_python_gui: ) self.subheader.Centre(wx.HORIZONTAL) - self.developer_note = wx.StaticText(self.frame, label="Developer Note: OCLP-CLI output will print after finishing") + self.developer_note = wx.StaticText(self.frame, label="Starting shortly") self.developer_note.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.developer_note.SetPosition( wx.Point( @@ -918,7 +1008,7 @@ class wx_python_gui: self.text_box.SetSize( wx.Size( self.frame.GetSize().width - 10, - self.frame.GetSize().height - self.text_box.GetPosition().y + 40 + self.frame.GetSize().height + self.text_box.GetPosition().y + 80 ) ) self.text_box.Centre(wx.HORIZONTAL) @@ -938,31 +1028,14 @@ class wx_python_gui: self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) # Start reverting root patches - # Grab binary path, launch second instance as CLI - # This is the cleanest way to implement admin root patching without either seperating OCLP or including duplicate code + sys.stdout = menu_redirect.RedirectText(self.text_box) + sys.stderr = menu_redirect.RedirectText(self.text_box) wx.GetApp().Yield() - if self.constants.launcher_script is None: - self.text_box.AppendText("- Starting OCLP-CLI via Binary\n") - args = [self.constants.oclp_helper_path, self.constants.launcher_binary, "--unpatch_sys_vol"] - else: - self.text_box.AppendText("- Starting OCLP-CLI via Python\n") - args = [self.constants.oclp_helper_path, self.constants.launcher_binary, self.constants.launcher_script, "--unpatch_sys_vol"] - process = subprocess.Popen( - args, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT - ) + sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants).start_unpatch() + sys.stdout = self.stock_stdout + sys.stderr = self.stock_stderr + wx.GetApp().Yield() - while True: - line = process.stdout.readline() - wx.GetApp().Yield() - if line.strip() == "": - pass - else: - self.text_box.AppendText(line) - if not line: break - - process.wait() def create_macos_menu(self, event=None): # Define Menu @@ -1162,8 +1235,10 @@ class wx_python_gui: # Update Label: sys.stdout=menu_redirect.RedirectLabelAll(self.download_label) + sys.stderr=menu_redirect.RedirectLabelAll(self.download_label) installer.install_macOS_installer(self.constants.payload_path) sys.stdout = self.stock_stdout + sys.stderr = self.stock_stderr # Update Label: self.download_label.SetLabel(f"Finished Installing {installer_name}") self.download_label.Centre(wx.HORIZONTAL) @@ -1383,34 +1458,14 @@ class wx_python_gui: print("- Starting creation script as admin") wx.GetApp().Yield() time.sleep(1) - sys.stdout=menu_redirect.RedirectText(self.stdout_text) - cim_start = subprocess.Popen( - [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT - ) - - wx.GetApp().Yield() - while True: - line = cim_start.stdout.readline() - wx.GetApp().Yield() - if line.strip() == "": - pass - else: - self.stdout_text.AppendText(line) - if not line: break - - cim_start.wait() - - if cim_start.returncode == 0: - print("Installer created successfully!") - else: - print("Installer creation failed") - print(f"Return Code {cim_start.returncode}") - sys.stdout = self.stock_stdout + args = [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path] + sys.stdout = menu_redirect.RedirectText(self.stdout_text) + sys.stderr = menu_redirect.RedirectText(self.stdout_text) + run.Run()._stream_output(comm=args) else: print("- Failed to create installer script") - sys.stdout = self.stock_stdout + sys.stdout = self.stock_stdout + sys.stderr = self.stock_stderr def settings_menu(self, event=None): @@ -1430,7 +1485,7 @@ class wx_python_gui: self.frame.DestroyChildren() self.frame.SetSize(self.WINDOW_SETTINGS_WIDTH, self.WINDOW_SETTINGS_HEIGHT) - self.frame.SetLabel("Settings") + self.frame.SetTitle("Settings") # Header self.header = wx.StaticText(self.frame, label="Settings") @@ -1769,12 +1824,20 @@ class wx_python_gui: self.apple_alc_checkbox.GetPosition().x, self.apple_alc_checkbox.GetPosition().y + self.apple_alc_checkbox.GetSize().height)) + # Button: Developer Debug Info + self.debug_button = wx.Button(self.frame, label="Developer Debug Info") + self.debug_button.Bind(wx.EVT_BUTTON, self.additional_info_menu) + self.debug_button.SetPosition(wx.Point( + self.set_writeflash_checkbox.GetPosition().x, + self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height)) + self.debug_button.Center(wx.HORIZONTAL) + # Button: return to main menu self.return_to_main_menu_button = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu_button.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu_button.SetPosition(wx.Point( - self.set_writeflash_checkbox.GetPosition().x, - self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height + 10)) + self.debug_button.GetPosition().x, + self.debug_button.GetPosition().y + self.debug_button.GetSize().height + 10)) self.return_to_main_menu_button.Center(wx.HORIZONTAL) # set frame size below return to main menu button @@ -1973,3 +2036,103 @@ class wx_python_gui: selection = self.smbios_model_dropdown.GetStringSelection() print(f"SMBIOS Spoof Model: {selection}") self.constants.override_smbios = selection + + def additional_info_menu(self, event=None): + # Define Menu: + + # Header: Additional Info + # Label: Model Dump + # Textbox: Model Dump + # Label: Real User ID + # Label: Effective User ID + # Label: Launcher Binary + # Textbox: Launcher Binary + # Label: Launcher Script + # Textbox: Launcher Script + + self.frame.DestroyChildren() + + # Header: Additional Info + self.additional_info_header = wx.StaticText(self.frame, label="Developer Debug Info", pos=wx.Point(10, 10)) + self.additional_info_header.SetFont(wx.Font(16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.additional_info_header.Center(wx.HORIZONTAL) + + # Label: Real User ID + self.real_user_id_label = wx.StaticText(self.frame, label=f"Current UID: {os.getuid()} - ({os.geteuid()})") + self.real_user_id_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.real_user_id_label.SetPosition( + wx.Point(self.additional_info_header.GetPosition().x, self.additional_info_header.GetPosition().y + self.additional_info_header.GetSize().height + 10) + ) + self.real_user_id_label.Center(wx.HORIZONTAL) + + # Label: Model Dump + self.model_dump_label = wx.StaticText(self.frame, label="Model Dump") + self.model_dump_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.model_dump_label.SetPosition( + wx.Point(self.real_user_id_label.GetPosition().x, self.real_user_id_label.GetPosition().y + self.real_user_id_label.GetSize().height + 10) + ) + self.model_dump_label.Center(wx.HORIZONTAL) + + # Textbox: Model Dump + self.model_dump_textbox = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE, pos=wx.Point(self.model_dump_label.GetPosition().x, self.model_dump_label.GetPosition().y + self.model_dump_label.GetSize().height + 10)) + self.model_dump_textbox.SetValue(str(self.constants.computer)) + self.model_dump_textbox.SetPosition( + wx.Point(self.model_dump_label.GetPosition().x, self.model_dump_label.GetPosition().y + self.model_dump_label.GetSize().height + 10) + ) + self.model_dump_textbox.SetSize( + wx.Size( + self.frame.GetSize().width - 5, + self.model_dump_textbox.GetSize().height + self.model_dump_textbox.GetSize().height + ) + ) + self.model_dump_textbox.Center(wx.HORIZONTAL) + self.model_dump_textbox.SetEditable(False) + + + + # Label: Launcher Binary + self.launcher_binary_label = wx.StaticText(self.frame, label="Launcher Binary") + self.launcher_binary_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.launcher_binary_label.SetPosition( + wx.Point(self.model_dump_textbox.GetPosition().x, self.model_dump_textbox.GetPosition().y + self.model_dump_textbox.GetSize().height + 10) + ) + self.launcher_binary_label.Center(wx.HORIZONTAL) + + # Textbox: Launcher Binary + self.launcher_binary_textbox = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE, pos=wx.Point(self.launcher_binary_label.GetPosition().x, self.launcher_binary_label.GetPosition().y + self.launcher_binary_label.GetSize().height + 10)) + self.launcher_binary_textbox.SetValue(self.constants.launcher_binary) + self.launcher_binary_textbox.SetPosition( + wx.Point(self.launcher_binary_label.GetPosition().x, self.launcher_binary_label.GetPosition().y + self.launcher_binary_label.GetSize().height + 10) + ) + self.launcher_binary_textbox.SetSize(wx.Size(self.frame.GetSize().width - 5, 50)) + self.launcher_binary_textbox.Center(wx.HORIZONTAL) + self.launcher_binary_textbox.SetEditable(False) + + # Label: Launcher Script + self.launcher_script_label = wx.StaticText(self.frame, label="Launcher Script") + self.launcher_script_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.launcher_script_label.SetPosition( + wx.Point(self.launcher_binary_textbox.GetPosition().x, self.launcher_binary_textbox.GetPosition().y + self.launcher_binary_textbox.GetSize().height + 10) + ) + self.launcher_script_label.Center(wx.HORIZONTAL) + + # Textbox: Launcher Script + self.launcher_script_textbox = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE, pos=wx.Point(self.launcher_script_label.GetPosition().x, self.launcher_script_label.GetPosition().y + self.launcher_script_label.GetSize().height + 10)) + self.launcher_script_textbox.SetValue(str(self.constants.launcher_script)) + self.launcher_script_textbox.SetPosition( + wx.Point(self.launcher_script_label.GetPosition().x, self.launcher_script_label.GetPosition().y + self.launcher_script_label.GetSize().height + 10) + ) + self.launcher_script_textbox.SetSize(wx.Size(self.frame.GetSize().width - 5, 60)) + self.launcher_script_textbox.Center(wx.HORIZONTAL) + self.launcher_script_textbox.SetEditable(False) + + # Return to Main Menu Button + self.return_to_main_menu_button = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu_button.SetPosition( + wx.Point(self.launcher_script_textbox.GetPosition().x, self.launcher_script_textbox.GetPosition().y + self.launcher_script_textbox.GetSize().height + 10) + ) + self.return_to_main_menu_button.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu_button.Center(wx.HORIZONTAL) + + # Set frame below return to main menu button + self.frame.SetSize(wx.Size(-1, self.return_to_main_menu_button.GetPosition().y + self.return_to_main_menu_button.GetSize().height + 40)) \ No newline at end of file diff --git a/gui/menu_redirect.py b/gui/menu_redirect.py index b6e79d8a9..4fe58f779 100644 --- a/gui/menu_redirect.py +++ b/gui/menu_redirect.py @@ -1,4 +1,5 @@ import wx +import time class RedirectText(object): def __init__(self,aWxTextCtrl): @@ -7,6 +8,7 @@ class RedirectText(object): def write(self,string): self.out.WriteText(string) wx.GetApp().Yield() + time.sleep(0.01) def fileno(self): return 1 @@ -23,6 +25,7 @@ class RedirectLabel(object): self.out.SetLabel(string) self.out.Centre(wx.HORIZONTAL) wx.GetApp().Yield() + time.sleep(0.01) def flush(self): pass @@ -34,4 +37,5 @@ class RedirectLabelAll(object): def write(self,string): self.out.SetLabel(string) self.out.Centre(wx.HORIZONTAL) - wx.GetApp().Yield() \ No newline at end of file + wx.GetApp().Yield() + time.sleep(0.01) \ No newline at end of file diff --git a/resources/run.py b/resources/run.py new file mode 100644 index 000000000..7d38a2dbe --- /dev/null +++ b/resources/run.py @@ -0,0 +1,155 @@ +# Module for running processes with real time output +# Written by CorpNewt +# Source: https://github.com/corpnewt/pymodules/blob/884c3de15b6a2570afde52fe8a14a3e946ffb18a/run.py + +import sys, subprocess, time, threading, shlex +try: + from Queue import Queue, Empty +except: + from queue import Queue, Empty + +ON_POSIX = 'posix' in sys.builtin_module_names + +class Run: + + def __init__(self): + return + + def _read_output(self, pipe, q): + try: + for line in iter(lambda: pipe.read(1), b''): + q.put(line) + except ValueError: + pass + pipe.close() + + def _create_thread(self, output): + # Creates a new queue and thread object to watch based on the output pipe sent + q = Queue() + t = threading.Thread(target=self._read_output, args=(output, q)) + t.daemon = True + return (q,t) + + def _stream_output(self, comm, shell = False): + output = error = "" + p = None + try: + if shell and type(comm) is list: + comm = " ".join(shlex.quote(x) for x in comm) + if not shell and type(comm) is str: + comm = shlex.split(comm) + p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, universal_newlines=True, close_fds=ON_POSIX) + # Setup the stdout thread/queue + q,t = self._create_thread(p.stdout) + qe,te = self._create_thread(p.stderr) + # Start both threads + t.start() + te.start() + + while True: + c = z = "" + try: c = q.get_nowait() + except Empty: pass + else: + sys.stdout.write(c) + output += c + sys.stdout.flush() + try: z = qe.get_nowait() + except Empty: pass + else: + sys.stderr.write(z) + error += z + sys.stderr.flush() + if not c==z=="": continue # Keep going until empty + # No output - see if still running + p.poll() + if p.returncode != None: + # Subprocess ended + break + # No output, but subprocess still running - stall for 20ms + time.sleep(0.02) + + o, e = p.communicate() + return (output+o, error+e, p.returncode) + except: + if p: + try: o, e = p.communicate() + except: o = e = "" + return (output+o, error+e, p.returncode) + return ("", "Command not found!", 1) + + def _decode(self, value, encoding="utf-8", errors="ignore"): + # Helper method to only decode if bytes type + if sys.version_info >= (3,0) and isinstance(value, bytes): + return value.decode(encoding,errors) + return value + + def _run_command(self, comm, shell = False): + c = None + try: + if shell and type(comm) is list: + comm = " ".join(shlex.quote(x) for x in comm) + if not shell and type(comm) is str: + comm = shlex.split(comm) + p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + c = p.communicate() + except: + if c == None: + return ("", "Command not found!", 1) + return (self._decode(c[0]), self._decode(c[1]), p.returncode) + + def run(self, command_list, leave_on_fail = False): + # Command list should be an array of dicts + if type(command_list) is dict: + # We only have one command + command_list = [command_list] + output_list = [] + for comm in command_list: + args = comm.get("args", []) + shell = comm.get("shell", False) + stream = comm.get("stream", False) + sudo = comm.get("sudo", False) + stdout = comm.get("stdout", False) + stderr = comm.get("stderr", False) + mess = comm.get("message", None) + show = comm.get("show", False) + + if not mess == None: + print(mess) + + if not len(args): + # nothing to process + continue + if sudo: + # Check if we have sudo + out = self._run_command(["which", "sudo"]) + if "sudo" in out[0]: + # Can sudo + if type(args) is list: + args.insert(0, out[0].replace("\n", "")) # add to start of list + elif type(args) is str: + args = out[0].replace("\n", "") + " " + args # add to start of string + + if show: + print(" ".join(args)) + + if stream: + # Stream it! + out = self._stream_output(args, shell) + else: + # Just run and gather output + out = self._run_command(args, shell) + if stdout and len(out[0]): + print(out[0]) + if stderr and len(out[1]): + print(out[1]) + # Append output + output_list.append(out) + # Check for errors + if leave_on_fail and out[2] != 0: + # Got an error - leave + break + if len(output_list) == 1: + # We only ran one command - just return that output + return output_list[0] + return output_list \ No newline at end of file diff --git a/resources/sys_patch.py b/resources/sys_patch.py index f7dddeff1..e6857b778 100644 --- a/resources/sys_patch.py +++ b/resources/sys_patch.py @@ -83,9 +83,12 @@ class PatchSysVolume: self.unpatch_root_vol() return True else: + print(f"User ID: {os.getuid()} - {os.geteuid()}") if self.constants.detected_os > os_data.os_data.catalina: print("- Mounting APFS Snapshot as writable") - utilities.elevated(["mount", "-o", "nobrowse", "-t", "apfs", f"/dev/{self.root_mount_path}", self.mount_location], stdout=subprocess.PIPE).stdout.decode().strip().encode() + result = utilities.elevated(["mount", "-o", "nobrowse", "-t", "apfs", f"/dev/{self.root_mount_path}", self.mount_location], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + if result.returncode == 0: + print(f"- Mounted APFS Snapshot as writable at: {self.mount_location}") if Path(self.mount_extensions).exists(): print("- Successfully mounted the Root Volume") if patch is True: @@ -272,7 +275,7 @@ class PatchSysVolume: print(bless.stdout.decode()) if "Can't use last-sealed-snapshot or create-snapshot on non system volume" in bless.stdout.decode(): print("- This is an APFS bug with Monterey! Perform a clean installation to ensure your APFS volume is built correctly") - sys.exit(1) + return else: self.unmount_drive() else: From c37e035b6decabf2b3e7d49b96d384a836839485 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sat, 1 Jan 2022 17:03:00 -0700 Subject: [PATCH 22/38] Copyright: 2022 --- OpenCore-Patcher-GUI.command | 2 +- OpenCore-Patcher-GUI.spec | 2 +- gui/gui_main.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenCore-Patcher-GUI.command b/OpenCore-Patcher-GUI.command index 8a4b46e23..b076e5aed 100755 --- a/OpenCore-Patcher-GUI.command +++ b/OpenCore-Patcher-GUI.command @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (C) 2020-2021, Dhinak G, Mykola Grymalyuk +# Copyright (C) 2020-2022, Dhinak G, Mykola Grymalyuk from resources import main if __name__ == '__main__': diff --git a/OpenCore-Patcher-GUI.spec b/OpenCore-Patcher-GUI.spec index bd16c7dd3..024506607 100644 --- a/OpenCore-Patcher-GUI.spec +++ b/OpenCore-Patcher-GUI.spec @@ -46,7 +46,7 @@ app = BUNDLE(exe, bundle_identifier=None, info_plist={ "CFBundleShortVersionString": constants.Constants().patcher_version, - "NSHumanReadableCopyright": "Copyright 2020-2021 Dortania", + "NSHumanReadableCopyright": "Copyright 2020-2022 Dortania", "LSMinimumSystemVersion": "10.10.0", "NSRequiresAquaSystemAppearance": False, "NSHighResolutionCapable": True, diff --git a/gui/gui_main.py b/gui/gui_main.py index 23fc62ced..1debf1a6c 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -439,7 +439,7 @@ class wx_python_gui: # Copyright Label - self.copyright = wx.StaticText(self.frame, label="Copyright © 2020-2021 Dortania") + self.copyright = wx.StaticText(self.frame, label="Copyright © 2020-2022 Dortania") self.copyright.SetFont(wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.copyright.SetPosition( wx.Point( From 3fc7424086485d40950e9e38cad6448a5fc61265 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sat, 1 Jan 2022 17:18:00 -0700 Subject: [PATCH 23/38] GA: Clean up build scripts --- .../workflows/build-app-wxpython-offline.yml | 43 +++++++++++++++ .github/workflows/build-app-wxpython.yml | 8 +-- .github/workflows/build-gui.yml | 52 ------------------- 3 files changed, 47 insertions(+), 56 deletions(-) create mode 100644 .github/workflows/build-app-wxpython-offline.yml delete mode 100644 .github/workflows/build-gui.yml diff --git a/.github/workflows/build-app-wxpython-offline.yml b/.github/workflows/build-app-wxpython-offline.yml new file mode 100644 index 000000000..854a0b9ee --- /dev/null +++ b/.github/workflows/build-app-wxpython-offline.yml @@ -0,0 +1,43 @@ +name: CI - Build wxPython + +on: + push: + workflow_dispatch: + release: + types: [published] + +name: CI - Build Offline wxPython + +on: + push: + workflow_dispatch: + release: + types: [published] + +jobs: + build: + name: Build wxPython Offline + runs-on: x86_64_mojave + steps: + - uses: actions/checkout@v2 + - run: python3 create_offline_build.py + - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher-GUI.spec + - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' + - run: cd dist; zip -r ../OpenCore-Patcher-wxPython.app.zip OpenCore-Patcher.app + - run: ./../sign-wxpython.sh + - name: Upload App to Artifacts + uses: actions/upload-artifact@v2 + with: + name: OpenCore-Patcher.app (GUI Offline, macOS 10.13 and newer) + path: OpenCore-Patcher-wxPython.app.zip + - name: Upload to Release + if: github.event_name == 'release' + uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: OpenCore-Patcher-wxPython.app.zip + tag: ${{ github.ref }} + file_glob: true + asset_name: OpenCore-Patcher.app (GUI Offline, macOS 10.13 and newer) + - name: Validate OpenCore + run: ./OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher --validate \ No newline at end of file diff --git a/.github/workflows/build-app-wxpython.yml b/.github/workflows/build-app-wxpython.yml index ac4cfc6aa..6f1275580 100644 --- a/.github/workflows/build-app-wxpython.yml +++ b/.github/workflows/build-app-wxpython.yml @@ -24,12 +24,12 @@ jobs: - name: Upload App to Artifacts uses: actions/upload-artifact@v2 with: - name: OpenCore-Patcher-wxPython.app (macOS 10.13 and newer) + name: OpenCore-Patcher.app (GUI, macOS 10.13 and newer) path: OpenCore-Patcher-wxPython.app.zip - name: Upload Legacy App to Artifacts uses: actions/upload-artifact@v2 with: - name: OpenCore-Patcher-wxPython.app (macOS 10.12 and older) + name: OpenCore-Patcher.app (GUI, macOS 10.12 and older) path: OpenCore-Patcher-wxPython-Legacy.app.zip - name: Upload to Release @@ -40,7 +40,7 @@ jobs: file: OpenCore-Patcher-wxPython.app.zip tag: ${{ github.ref }} file_glob: true - asset_name: OpenCore-Patcher-wxPython.app (macOS 10.13 and newer) + asset_name: OpenCore-Patcher.app (GUI, macOS 10.13 and newer) - name: Upload Legacy to Release if: github.event_name == 'release' @@ -50,4 +50,4 @@ jobs: file: OpenCore-Patcher-wxPython-Legacy.app.zip tag: ${{ github.ref }} file_glob: true - asset_name: OpenCore-Patcher-wxPython.app (macOS 10.12 and older) + asset_name: OpenCore-Patcher.app (GUI, macOS 10.12 and older) diff --git a/.github/workflows/build-gui.yml b/.github/workflows/build-gui.yml deleted file mode 100644 index 915cc3b1b..000000000 --- a/.github/workflows/build-gui.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: CI - Build GUI - -on: - push: - workflow_dispatch: - release: - types: [published] - -jobs: - build: - name: Build GUI - runs-on: x86_64_mojave - steps: - - uses: actions/checkout@v2 - - - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec - - run: cd dist; cp OpenCore-Patcher ../; cd ..; mv OpenCore-Patcher OCLP-CLI - - name: Download latest nightly OCLP-GUI - run: curl -S -L https://nightly.link/dortania/OCLP-GUI/workflows/build-app/master/OpenCore-Patcher-GUI.app.zip --output ./OpenCore-Patcher-GUI.app.zip --insecure - - run: unzip -o OpenCore-Patcher-GUI.app.zip - - run: unzip OpenCore-Patcher-GUI.app.zip; rm OpenCore-Patcher-GUI.app.zip - - name: Merge new GUI - run: cp OCLP-CLI OpenCore\ Patcher.app/Contents/Resources/ - - run: python3 merge_gui.py - - name: Code Sign Binaries - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "OpenCore Patcher.app/Contents/Resources/OCLP-CLI"' - - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "OpenCore Patcher.app/Contents/Resources/oclpd"' - - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "OpenCore Patcher.app"' - - run: ditto -c -k --sequesterRsrc --keepParent OpenCore\ Patcher.app OpenCore-Patcher-GUI.app.zip - - name: Notarize Binaries for release - if: github.event_name == 'release' - run: ./../sign-gui.sh - - name: Upload GUI to Artifacts - uses: actions/upload-artifact@v2 - with: - name: OpenCore-Patcher-GUI.app - path: OpenCore-Patcher-GUI.app.zip - - name: Upload CLI to Artifacts - uses: actions/upload-artifact@v2 - with: - name: OCLP-CLI - path: OCLP-CLI - - name: Upload to Release - if: github.event_name == 'release' - uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: OpenCore-Patcher-GUI.app.zip - tag: ${{ github.ref }} - file_glob: true - - name: Validate OpenCore - run: ./OCLP-CLI --validate From 4b6125d5832616a8f6ef7a707338ea23baaa3a19 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Mon, 3 Jan 2022 13:33:46 -0700 Subject: [PATCH 24/38] GA: Fix offline GUI building --- .github/workflows/build-app-wxpython-offline.yml | 4 +--- gui/gui_main.py | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-app-wxpython-offline.yml b/.github/workflows/build-app-wxpython-offline.yml index 854a0b9ee..73affca15 100644 --- a/.github/workflows/build-app-wxpython-offline.yml +++ b/.github/workflows/build-app-wxpython-offline.yml @@ -1,5 +1,3 @@ -name: CI - Build wxPython - on: push: workflow_dispatch: @@ -16,7 +14,7 @@ on: jobs: build: - name: Build wxPython Offline + name: Build Offline wxPython runs-on: x86_64_mojave steps: - uses: actions/checkout@v2 diff --git a/gui/gui_main.py b/gui/gui_main.py index 1debf1a6c..d939acf86 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -1829,7 +1829,7 @@ class wx_python_gui: self.debug_button.Bind(wx.EVT_BUTTON, self.additional_info_menu) self.debug_button.SetPosition(wx.Point( self.set_writeflash_checkbox.GetPosition().x, - self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height)) + self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height + 3)) self.debug_button.Center(wx.HORIZONTAL) # Button: return to main menu @@ -2052,6 +2052,8 @@ class wx_python_gui: self.frame.DestroyChildren() + self.frame.SetSize(wx.Size(500, -1)) + # Header: Additional Info self.additional_info_header = wx.StaticText(self.frame, label="Developer Debug Info", pos=wx.Point(10, 10)) self.additional_info_header.SetFont(wx.Font(16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) From e962f2bb8f88898e5f0cd42df96ddb6a2208e902 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Tue, 4 Jan 2022 17:51:18 -0700 Subject: [PATCH 25/38] gui.py: Add SIP configuration --- data/sip_data.py | 96 +++++++++++++++++++++++++++++ gui/gui_main.py | 155 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 237 insertions(+), 14 deletions(-) diff --git a/data/sip_data.py b/data/sip_data.py index c79ba3637..814bf83a7 100644 --- a/data/sip_data.py +++ b/data/sip_data.py @@ -1,3 +1,4 @@ +from data import os_data class system_integrity_protection: csr_values = { # Source: macOS 11.4 (XNU's csr.h) @@ -17,6 +18,101 @@ class system_integrity_protection: "CSR_ALLOW_UNAUTHENTICATED_ROOT": False, # 0x800 - Allow Root Volume Mounting - Introduced in Big Sur # noqa: E241 } + csr_values_extended = { + "CSR_ALLOW_UNTRUSTED_KEXTS": { + "name": "CSR_ALLOW_UNTRUSTED_KEXTS", + "description": "Allows Unsigned Kexts", + "introduced": os_data.os_data.el_capitan.value, + "introduced_friendly": "El Capitan", + "value": 0x1, + }, + "CSR_ALLOW_UNRESTRICTED_FS": { + "name": "CSR_ALLOW_UNRESTRICTED_FS", + "description": "File System Access", + "introduced": os_data.os_data.el_capitan.value, + "introduced_friendly": "El Capitan", + "value": 0x2, + }, + "CSR_ALLOW_TASK_FOR_PID": { + "name": "CSR_ALLOW_TASK_FOR_PID", + "description": "Unrestricted task_for_pid()", + "introduced": os_data.os_data.el_capitan.value, + "introduced_friendly": "El Capitan", + "value": 0x4, + }, + "CSR_ALLOW_KERNEL_DEBUGGER": { + "name": "CSR_ALLOW_KERNEL_DEBUGGER", + "description": "Allow Kernel Debugger", + "introduced": os_data.os_data.el_capitan.value, + "introduced_friendly": "El Capitan", + "value": 0x8, + }, + "CSR_ALLOW_APPLE_INTERNAL": { + "name": "CSR_ALLOW_APPLE_INTERNAL", + "description": "Set AppleInternal Features", + "introduced": os_data.os_data.el_capitan.value, + "introduced_friendly": "El Capitan", + "value": 0x10, + }, + # "CSR_ALLOW_DESTRUCTIVE_DTRACE": { + # "name": "CSR_ALLOW_DESTRUCTIVE_DTRACE", + # "description": "Allow destructive DTrace", + # "deprecated": True, + # "introduced": os_data.os_data.el_capitan.value, + # "introduced_friendly": "El Capitan", + # "value": 0x20, + # }, + "CSR_ALLOW_UNRESTRICTED_DTRACE": { + "name": "CSR_ALLOW_UNRESTRICTED_DTRACE", + "description": "Unrestricted DTrace usage", + "introduced": os_data.os_data.el_capitan.value, + "introduced_friendly": "El Capitan", + "value": 0x20, + }, + "CSR_ALLOW_UNRESTRICTED_NVRAM": { + "name": "CSR_ALLOW_UNRESTRICTED_NVRAM", + "description": "Unrestricted NVRAM write", + "introduced": os_data.os_data.el_capitan.value, + "introduced_friendly": "El Capitan", + "value": 0x40, + }, + "CSR_ALLOW_DEVICE_CONFIGURATION": { + "name": "CSR_ALLOW_DEVICE_CONFIGURATION", + "description": "Allow custom DeviceTree (iOS)", + "introduced": os_data.os_data.el_capitan.value, + "introduced_friendly": "El Capitan", + "value": 0x80, + }, + "CSR_ALLOW_ANY_RECOVERY_OS": { + "name": "CSR_ALLOW_ANY_RECOVERY_OS", + "description": "Skip BaseSystem Verification", + "introduced": os_data.os_data.sierra.value, + "introduced_friendly": "Sierra", + "value": 0x100, + }, + "CSR_ALLOW_UNAPPROVED_KEXTS": { + "name": "CSR_ALLOW_UNAPPROVED_KEXTS", + "description": "Allow Unnotarized Kexts", + "introduced": os_data.os_data.high_sierra.value, + "introduced_friendly": "High Sierra", + "value": 0x200, + }, + "CSR_ALLOW_EXECUTABLE_POLICY_OVERRIDE": { + "name": "CSR_ALLOW_EXECUTABLE_POLICY_OVERRIDE", + "description": "Override Executable Policy", + "introduced": os_data.os_data.mojave.value, + "introduced_friendly": "Mojave", + "value": 0x400, + }, + "CSR_ALLOW_UNAUTHENTICATED_ROOT": { + "name": "CSR_ALLOW_UNAUTHENTICATED_ROOT", + "description": "Allow Root Volume Mounting", + "introduced": os_data.os_data.big_sur.value, + "introduced_friendly": "Big Sur", + "value": 0x800, + }, + } + root_patch_sip_mojave = [ # Variables required to root patch in Mojave and Catalina "CSR_ALLOW_UNTRUSTED_KEXTS", # 0x1 diff --git a/gui/gui_main.py b/gui/gui_main.py index d939acf86..b13c556f1 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -11,7 +11,7 @@ import os import wx.adv from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect, sys_patch, run -from data import model_array, os_data, smbios_data +from data import model_array, os_data, smbios_data, sip_data from gui import menu_redirect class wx_python_gui: @@ -1547,17 +1547,17 @@ class wx_python_gui: self.opencore_checkbox.Bind(wx.EVT_CHECKBOX, self.oc_checkbox_click) self.opencore_checkbox.ToolTip = wx.ToolTip("""Enables OpenCore logging, can heavily impact boot times""") - # Checkbox: SIP - self.sip_checkbox = wx.CheckBox(self.frame, label="SIP") - self.sip_checkbox.SetValue(self.constants.sip_status) - self.sip_checkbox.SetPosition(wx.Point(self.opencore_checkbox.GetPosition().x , self.opencore_checkbox.GetPosition().y + self.opencore_checkbox.GetSize().height)) - self.sip_checkbox.Bind(wx.EVT_CHECKBOX, self.sip_checkbox_click) - self.sip_checkbox.ToolTip = wx.ToolTip("""Sets SIP, disable to allow root patching""") + # # Checkbox: SIP + # self.sip_checkbox = wx.CheckBox(self.frame, label="SIP") + # self.sip_checkbox.SetValue(self.constants.sip_status) + # self.sip_checkbox.SetPosition(wx.Point(self.opencore_checkbox.GetPosition().x , self.opencore_checkbox.GetPosition().y + self.opencore_checkbox.GetSize().height)) + # self.sip_checkbox.Bind(wx.EVT_CHECKBOX, self.sip_checkbox_click) + # self.sip_checkbox.ToolTip = wx.ToolTip("""Sets SIP, disable to allow root patching""") # Checkbox: SecureBootModel self.secureboot_checkbox = wx.CheckBox(self.frame, label="SecureBootModel") self.secureboot_checkbox.SetValue(self.constants.secure_status) - self.secureboot_checkbox.SetPosition(wx.Point(self.sip_checkbox.GetPosition().x , self.sip_checkbox.GetPosition().y + self.sip_checkbox.GetSize().height)) + self.secureboot_checkbox.SetPosition(wx.Point(self.opencore_checkbox.GetPosition().x , self.opencore_checkbox.GetPosition().y + self.opencore_checkbox.GetSize().height)) self.secureboot_checkbox.Bind(wx.EVT_CHECKBOX, self.secureboot_checkbox_click) self.secureboot_checkbox.ToolTip = wx.ToolTip("""Sets SecureBootModel, useful for models spoofing T2 Macs to get OTA updates""") @@ -1577,20 +1577,33 @@ class wx_python_gui: # Buttons + + # Button: SIP Settings + if self.constants.custom_sip_value: + sip_string = "Custom" + elif self.constants.sip_status: + sip_string = "Enabled" + else: + sip_string = "Disabled" + self.sip_button = wx.Button(self.frame, label=f"SIP Settings ({sip_string})", size=(155,30)) + self.sip_button.SetPosition(wx.Point(self.accel_checkbox.GetPosition().x , self.accel_checkbox.GetPosition().y + self.accel_checkbox.GetSize().height + 10)) + self.sip_button.Bind(wx.EVT_BUTTON, self.sip_config_menu) + self.sip_button.Center(wx.HORIZONTAL) + # Button: SMBIOS Settings - self.smbios_button = wx.Button(self.frame, label="SMBIOS Settings", size=(150,30)) - self.smbios_button.SetPosition(wx.Point(self.accel_checkbox.GetPosition().x , self.accel_checkbox.GetPosition().y + self.accel_checkbox.GetSize().height + 10)) + self.smbios_button = wx.Button(self.frame, label="SMBIOS Settings", size=(155,30)) + self.smbios_button.SetPosition(wx.Point(self.sip_button.GetPosition().x , self.sip_button.GetPosition().y + self.sip_button.GetSize().height)) self.smbios_button.Bind(wx.EVT_BUTTON, self.smbios_settings_menu) self.smbios_button.Center(wx.HORIZONTAL) # Button: Developer Settings - self.miscellaneous_button = wx.Button(self.frame, label="Developer Settings", size=(150,30)) + self.miscellaneous_button = wx.Button(self.frame, label="Developer Settings", size=(155,30)) self.miscellaneous_button.SetPosition(wx.Point(self.smbios_button.GetPosition().x , self.smbios_button.GetPosition().y + self.smbios_button.GetSize().height)) self.miscellaneous_button.Bind(wx.EVT_BUTTON, self.misc_settings_menu) self.miscellaneous_button.Centre(wx.HORIZONTAL) # Return to Main Menu - self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu", size=(150,30)) + self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu", size=(155,30)) self.return_to_main_menu.SetPosition( wx.Point( self.miscellaneous_button.GetPosition().x, @@ -1829,7 +1842,7 @@ class wx_python_gui: self.debug_button.Bind(wx.EVT_BUTTON, self.additional_info_menu) self.debug_button.SetPosition(wx.Point( self.set_writeflash_checkbox.GetPosition().x, - self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height + 3)) + self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height + 5)) self.debug_button.Center(wx.HORIZONTAL) # Button: return to main menu @@ -2137,4 +2150,118 @@ class wx_python_gui: self.return_to_main_menu_button.Center(wx.HORIZONTAL) # Set frame below return to main menu button - self.frame.SetSize(wx.Size(-1, self.return_to_main_menu_button.GetPosition().y + self.return_to_main_menu_button.GetSize().height + 40)) \ No newline at end of file + self.frame.SetSize(wx.Size(-1, self.return_to_main_menu_button.GetPosition().y + self.return_to_main_menu_button.GetSize().height + 40)) + + + def sip_config_menu(self, event=None): + # Implement individual checkbox for each bit in SIP + # Add label showing 'self.constants.custom_sip_value' + # custom_sip_value is equivlant to all enabled checkboxes + # Refresh label whenever checkbox is changed + + self.frame.DestroyChildren() + self.frame.SetSize(wx.Size(400, 600)) + + # Title: Configure SIP + self.configure_sip_title = wx.StaticText(self.frame, label="Configure SIP") + self.configure_sip_title.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.configure_sip_title.Center(wx.HORIZONTAL) + + # Label: Flip indivdual bits corresponding to XNU's csr.h + # If you're unfamiliar with how SIP works, do not touch this menu + self.sip_label = wx.StaticText(self.frame, label="Flip indivdual bits corresponding to") + self.sip_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.sip_label.SetPosition( + wx.Point(-1, self.configure_sip_title.GetPosition().y + self.configure_sip_title.GetSize().height + 10) + ) + self.sip_label.Center(wx.HORIZONTAL) + self.sip_label.SetPosition( + wx.Point(self.sip_label.GetPosition().x - 25, -1) + ) + + # Hyperlink to the right of sip_label + import wx.lib.agw.hyperlink as hl + hl.HyperLinkCtrl( + self.frame, + -1, + "XNU's csr.h", + pos=(self.sip_label.GetPosition().x + self.sip_label.GetSize().width, self.sip_label.GetPosition().y), + URL="https://github.com/apple/darwin-xnu/blob/main/bsd/sys/csr.h" + ) + + # Label: By default, SIP is set to 0x00 (enabled) on newer Macs. + # For older Macs requiring root patching, we set SIP to (0xA03) + # This corresponds to the following bits: + # - 0x1 - CSR_ALLOW_UNTRUSTED_KEXTS + # - 0x2 - CSR_ALLOW_UNRESTRICTED_FS + # - 0x200 - CSR_ALLOW_UNAPPROVED_KEXTS + # - 0x800 - CSR_ALLOW_UNAUTHENTICATED_ROOT + + if self.constants.custom_sip_value is not None: + self.sip_value = int(self.constants.custom_sip_value, 16) + elif self.constants.sip_status is True: + self.sip_value = 0x00 + else: + self.sip_value = 0xa03 + + self.sip_label_2 = wx.StaticText(self.frame, label=f"Currently configured SIP: {hex(self.sip_value)}") + self.sip_label_2.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) + self.sip_label_2.SetPosition( + wx.Point(self.sip_label.GetPosition().x, self.sip_label.GetPosition().y + self.sip_label.GetSize().height + 10) + ) + self.sip_label_2.Center(wx.HORIZONTAL) + + self.sip_label_3 = wx.StaticText(self.frame, label="For older Macs requiring root patching, we set SIP to\n be partially disabled (0xa03) to allow root patching.") + self.sip_label_3.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.sip_label_3.SetPosition( + wx.Point(self.sip_label_2.GetPosition().x, self.sip_label_2.GetPosition().y + self.sip_label_2.GetSize().height + 10) + ) + self.sip_label_3.Center(wx.HORIZONTAL) + + self.sip_label_4 = wx.StaticText(self.frame, label="This value (0xa03) corresponds to the following bits in csr.h:") + self.sip_label_4.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.sip_label_4.SetPosition( + wx.Point(self.sip_label_3.GetPosition().x, self.sip_label_3.GetPosition().y + self.sip_label_3.GetSize().height + 5) + ) + self.sip_label_4.Center(wx.HORIZONTAL) + + self.sip_label_5 = wx.StaticText(self.frame, label=" 0x1 - CSR_ALLOW_UNTRUSTED_KEXTS\n 0x2 - CSR_ALLOW_UNRESTRICTED_FS\n 0x200 - CSR_ALLOW_UNAPPROVED_KEXTS\n 0x800 - CSR_ALLOW_UNAUTHENTICATED_ROOT") + self.sip_label_5.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.sip_label_5.SetPosition( + wx.Point(self.sip_label_4.GetPosition().x, self.sip_label_4.GetPosition().y + self.sip_label_4.GetSize().height + 7) + ) + self.sip_label_5.Center(wx.HORIZONTAL) + + i = 0 + for sip_bit in sip_data.system_integrity_protection.csr_values_extended: + self.sip_checkbox = wx.CheckBox(self.frame, label=sip_data.system_integrity_protection.csr_values_extended[sip_bit]["name"]) + self.sip_checkbox.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.sip_checkbox.SetToolTip(f'Description: {sip_data.system_integrity_protection.csr_values_extended[sip_bit]["description"]}\nValue: {hex(sip_data.system_integrity_protection.csr_values_extended[sip_bit]["value"])}\nIntroduced in: macOS {sip_data.system_integrity_protection.csr_values_extended[sip_bit]["introduced_friendly"]}') + self.sip_checkbox.SetPosition( + wx.Point(self.sip_label_5.GetPosition().x + 10, self.sip_label_5.GetPosition().y + self.sip_label_5.GetSize().height + 10 + i) + ) + i = i + 20 + self.sip_checkbox.Bind(wx.EVT_CHECKBOX, self.update_sip_value) + if self.sip_value & sip_data.system_integrity_protection.csr_values_extended[sip_bit]["value"] == sip_data.system_integrity_protection.csr_values_extended[sip_bit]["value"]: + self.sip_checkbox.SetValue(True) + + # Button: returns to the main menu + self.return_to_main_menu_button = wx.Button(self.frame, label="Return to Main Menu") + self.return_to_main_menu_button.SetPosition( + wx.Point(self.sip_checkbox.GetPosition().x, self.sip_checkbox.GetPosition().y + self.sip_checkbox.GetSize().height + 15) + ) + self.return_to_main_menu_button.Bind(wx.EVT_BUTTON, self.main_menu) + self.return_to_main_menu_button.Center(wx.HORIZONTAL) + + # Set the frame size + self.frame.SetSize(wx.Size(-1, self.return_to_main_menu_button.GetPosition().y + self.return_to_main_menu_button.GetSize().height + 40)) + + def update_sip_value(self, event): + dict = sip_data.system_integrity_protection.csr_values_extended[event.GetEventObject().GetLabel()] + if event.GetEventObject().GetValue() is True: + self.sip_value = self.sip_value + dict["value"] + else: + self.sip_value = self.sip_value - dict["value"] + self.constants.custom_sip_value = hex(self.sip_value) + self.sip_label_2.SetLabel(f"Currently configured SIP: {hex(self.sip_value)}") + self.sip_label_2.Center(wx.HORIZONTAL) \ No newline at end of file From bf7b63c1be45f0c06a356f62c5714b341cb3d749 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Tue, 4 Jan 2022 19:43:37 -0700 Subject: [PATCH 26/38] menu_redirect.py: Add configurable delay --- gui/gui_main.py | 58 ++++++++++++++++++++++++++++++++------------ gui/menu_redirect.py | 6 +++-- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index b13c556f1..6f3131f91 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -9,6 +9,7 @@ import subprocess import time import os import wx.adv +from wx.lib.agw import hyperlink from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect, sys_patch, run from data import model_array, os_data, smbios_data, sip_data @@ -588,8 +589,8 @@ class wx_python_gui: # Centre the text box to top of window self.stdout_text.Centre(wx.HORIZONTAL) self.stdout_text.SetValue("") - sys.stdout=menu_redirect.RedirectText(self.stdout_text) - sys.stderr=menu_redirect.RedirectText(self.stdout_text) + sys.stdout=menu_redirect.RedirectText(self.stdout_text, False) + sys.stderr=menu_redirect.RedirectText(self.stdout_text, False) # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") @@ -757,8 +758,8 @@ class wx_python_gui: # Centre the text box to top of window self.stdout_text.Centre(wx.HORIZONTAL) self.stdout_text.SetValue("") - sys.stdout=menu_redirect.RedirectText(self.stdout_text) - sys.stderr=menu_redirect.RedirectText(self.stdout_text) + sys.stdout=menu_redirect.RedirectText(self.stdout_text, False) + sys.stderr=menu_redirect.RedirectText(self.stdout_text, False) # Update frame height to right below self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.stdout_text.GetPosition().y + self.stdout_text.GetSize().height + 40) @@ -952,8 +953,8 @@ class wx_python_gui: wx.GetApp().Yield() - sys.stdout = menu_redirect.RedirectText(self.text_box) - sys.stderr = menu_redirect.RedirectText(self.text_box) + sys.stdout = menu_redirect.RedirectText(self.text_box, True) + sys.stderr = menu_redirect.RedirectText(self.text_box, True) wx.GetApp().Yield() self.frame.Show() sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants).start_patch() @@ -1028,8 +1029,8 @@ class wx_python_gui: self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) # Start reverting root patches - sys.stdout = menu_redirect.RedirectText(self.text_box) - sys.stderr = menu_redirect.RedirectText(self.text_box) + sys.stdout = menu_redirect.RedirectText(self.text_box, True) + sys.stderr = menu_redirect.RedirectText(self.text_box, True) wx.GetApp().Yield() sys_patch.PatchSysVolume(self.constants.custom_model or self.constants.computer.real_model, self.constants).start_unpatch() sys.stdout = self.stock_stdout @@ -1431,7 +1432,6 @@ class wx_python_gui: # Centre the text box to top of window self.stdout_text.Centre(wx.HORIZONTAL) self.stdout_text.SetValue("") - # sys.stdout=menu_redirect.RedirectText(self.stdout_text) # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") @@ -1459,8 +1459,8 @@ class wx_python_gui: wx.GetApp().Yield() time.sleep(1) args = [self.constants.oclp_helper_path, "/bin/sh", self.constants.installer_sh_path] - sys.stdout = menu_redirect.RedirectText(self.stdout_text) - sys.stderr = menu_redirect.RedirectText(self.stdout_text) + sys.stdout = menu_redirect.RedirectText(self.stdout_text, True) + sys.stderr = menu_redirect.RedirectText(self.stdout_text, True) run.Run()._stream_output(comm=args) else: print("- Failed to create installer script") @@ -2180,14 +2180,15 @@ class wx_python_gui: ) # Hyperlink to the right of sip_label - import wx.lib.agw.hyperlink as hl - hl.HyperLinkCtrl( + + hyperlink_label = hyperlink.HyperLinkCtrl( self.frame, -1, "XNU's csr.h", pos=(self.sip_label.GetPosition().x + self.sip_label.GetSize().width, self.sip_label.GetPosition().y), - URL="https://github.com/apple/darwin-xnu/blob/main/bsd/sys/csr.h" + URL="https://github.com/apple/darwin-xnu/blob/main/bsd/sys/csr.h", ) + hyperlink_label.SetForegroundColour((25, 179, 231)) # Label: By default, SIP is set to 0x00 (enabled) on newer Macs. # For older Macs requiring root patching, we set SIP to (0xA03) @@ -2232,13 +2233,31 @@ class wx_python_gui: ) self.sip_label_5.Center(wx.HORIZONTAL) + # Label: If you system requires SIP to be lowered, do not try to re-enable it. + # You may accidentally break your system. OpenCore Legacy Patcher by default + # knows the most ideal SIP value for your system. Override this value if you + # understand the consequences or are absolutely certain your configuration supports SIP + # in the OSes you wish to run OpenCore Legacy Patcher on. + warning_string = """ +OpenCore Legacy Patcher by default knows the most ideal + SIP value for your system. Override this value only if you + understand the consequences. Reckless usage of this + menu can break your installation. +""" + self.sip_label_6 = wx.StaticText(self.frame, label=warning_string) + self.sip_label_6.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.sip_label_6.SetPosition( + wx.Point(self.sip_label_5.GetPosition().x, self.sip_label_5.GetPosition().y + self.sip_label_5.GetSize().height) + ) + self.sip_label_6.Center(wx.HORIZONTAL) + i = 0 for sip_bit in sip_data.system_integrity_protection.csr_values_extended: self.sip_checkbox = wx.CheckBox(self.frame, label=sip_data.system_integrity_protection.csr_values_extended[sip_bit]["name"]) self.sip_checkbox.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.sip_checkbox.SetToolTip(f'Description: {sip_data.system_integrity_protection.csr_values_extended[sip_bit]["description"]}\nValue: {hex(sip_data.system_integrity_protection.csr_values_extended[sip_bit]["value"])}\nIntroduced in: macOS {sip_data.system_integrity_protection.csr_values_extended[sip_bit]["introduced_friendly"]}') self.sip_checkbox.SetPosition( - wx.Point(self.sip_label_5.GetPosition().x + 10, self.sip_label_5.GetPosition().y + self.sip_label_5.GetSize().height + 10 + i) + wx.Point(70, self.sip_label_6.GetPosition().y + self.sip_label_6.GetSize().height + i) ) i = i + 20 self.sip_checkbox.Bind(wx.EVT_CHECKBOX, self.update_sip_value) @@ -2262,6 +2281,13 @@ class wx_python_gui: self.sip_value = self.sip_value + dict["value"] else: self.sip_value = self.sip_value - dict["value"] - self.constants.custom_sip_value = hex(self.sip_value) + if hex(self.sip_value) == "0x0": + self.constants.custom_sip_value = None + self.constants.sip_status = True + elif hex(self.sip_value) == "0xa03": + self.constants.custom_sip_value = None + self.constants.sip_status = False + else: + self.constants.custom_sip_value = hex(self.sip_value) self.sip_label_2.SetLabel(f"Currently configured SIP: {hex(self.sip_value)}") self.sip_label_2.Center(wx.HORIZONTAL) \ No newline at end of file diff --git a/gui/menu_redirect.py b/gui/menu_redirect.py index 4fe58f779..f96dd0901 100644 --- a/gui/menu_redirect.py +++ b/gui/menu_redirect.py @@ -2,13 +2,15 @@ import wx import time class RedirectText(object): - def __init__(self,aWxTextCtrl): + def __init__(self,aWxTextCtrl, sleep): self.out=aWxTextCtrl + self.sleep = sleep def write(self,string): self.out.WriteText(string) wx.GetApp().Yield() - time.sleep(0.01) + if self.sleep: + time.sleep(0.01) def fileno(self): return 1 From 0956ad0d3de2a3085671cb1d2176566d065c38f5 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Wed, 5 Jan 2022 10:14:34 -0700 Subject: [PATCH 27/38] gui.py: Adjust SIP menu sizing --- gui/gui_main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index 6f3131f91..9a389cb50 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -2247,11 +2247,11 @@ OpenCore Legacy Patcher by default knows the most ideal self.sip_label_6 = wx.StaticText(self.frame, label=warning_string) self.sip_label_6.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.sip_label_6.SetPosition( - wx.Point(self.sip_label_5.GetPosition().x, self.sip_label_5.GetPosition().y + self.sip_label_5.GetSize().height) + wx.Point(self.sip_label_5.GetPosition().x, self.sip_label_5.GetPosition().y + self.sip_label_5.GetSize().height - 10) ) self.sip_label_6.Center(wx.HORIZONTAL) - i = 0 + i = -10 for sip_bit in sip_data.system_integrity_protection.csr_values_extended: self.sip_checkbox = wx.CheckBox(self.frame, label=sip_data.system_integrity_protection.csr_values_extended[sip_bit]["name"]) self.sip_checkbox.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) From a0978dfd20b2d5f2de0aa5106310d3b2ad23c25d Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Wed, 5 Jan 2022 13:37:10 -0700 Subject: [PATCH 28/38] gui.py: Resolve admin relaunch with space in path --- gui/gui_main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index 9a389cb50..d6a41dc41 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -87,7 +87,7 @@ class wx_python_gui: args = [ "osascript", "-e", - f'''do shell script "{args_string}"''' + f'''do shell script "'{args_string}'"''' ' with prompt "OpenCore Legacy Patcher needs administrator privileges to mount your EFI."' " with administrator privileges" " without altering line endings", @@ -2240,7 +2240,7 @@ class wx_python_gui: # in the OSes you wish to run OpenCore Legacy Patcher on. warning_string = """ OpenCore Legacy Patcher by default knows the most ideal - SIP value for your system. Override this value only if you + SIP value for your system. Override this value only if you understand the consequences. Reckless usage of this menu can break your installation. """ From 3a65f005fe4667a3836d75db9c14245ce772adcf Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Wed, 5 Jan 2022 15:02:59 -0700 Subject: [PATCH 29/38] gui.py: Update cim text --- gui/gui_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index d6a41dc41..6dcded1bb 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -1403,7 +1403,7 @@ class wx_python_gui: self.creating_macos_installer_label.Centre(wx.HORIZONTAL) # Label: Developer Note: createinstallmedia output currently not implemented - self.developer_note_label = wx.StaticText(self.frame, label="Developer Note: createinstallmedia output will print after finishing") + self.developer_note_label = wx.StaticText(self.frame, label="\tDeveloper Note: createinstallmedia output will print after finishing\nIf Application becomes unresponsive, this is due to slow USB flash drives.\n\tPlease do not close this window until the process is complete.") self.developer_note_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) self.developer_note_label.SetPosition( # Set Position below header From cb808dc7ca30707d82cc736c30109328f15a6944 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Wed, 5 Jan 2022 19:45:41 -0700 Subject: [PATCH 30/38] gui.py: clear unused menus --- gui/gui_main.py | 170 ------------------------------------------------ 1 file changed, 170 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index 6dcded1bb..161451b23 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -168,176 +168,6 @@ class wx_python_gui: ) ) self.return_button.Centre(wx.HORIZONTAL) - - def walkthrough_main_menu(self, event=None): - # Define Menu - # - Header: OpenCore Legacy Patcher v{self.constants.patcher_version} - # - Subheader: Model: {self.constants.custom_model or self.computer.real_model} - # - Options: - # - First Time Setup - # - Post-Install Setup - # - Advanced Menu - - self.frame.DestroyChildren() - self.walkthrough_mode = False - - # Header - self.header = wx.StaticText(self.frame, label=f"OpenCore Legacy Patcher v{self.constants.patcher_version}") - self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) - self.header.Centre(wx.HORIZONTAL) - - # Subheader - self.subheader = wx.StaticText(self.frame, label=f"Model: {self.constants.custom_model or self.computer.real_model}") - self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) - self.subheader.SetPosition( - wx.Point( - self.header.GetPosition().x, - self.header.GetPosition().y + self.header.GetSize().height + 5 - ) - ) - self.subheader.Centre(wx.HORIZONTAL) - - # Button: First Time Setup - self.first_time_setup = wx.Button(self.frame, label="First Time Setup", size=(200,30)) - self.first_time_setup.Bind(wx.EVT_BUTTON, self.first_time_setup_menu) - self.first_time_setup.SetPosition( - wx.Point( - self.header.GetPosition().x, - self.subheader.GetPosition().y + self.subheader.GetSize().height + 5 - ) - ) - self.first_time_setup.Centre(wx.HORIZONTAL) - - # Button: Post-Install Setup - self.post_install_setup = wx.Button(self.frame, label="Post-Install Setup", size=(200,30)) - self.post_install_setup.Bind(wx.EVT_BUTTON, self.not_yet_implemented_menu) - self.post_install_setup.SetPosition( - wx.Point( - -1, - self.first_time_setup.GetPosition().y + self.first_time_setup.GetSize().height - ) - ) - self.post_install_setup.Centre(wx.HORIZONTAL) - - # Button: Advanced Menu - self.advanced_menu = wx.Button(self.frame, label="Advanced Menu", size=(200,30)) - self.advanced_menu.Bind(wx.EVT_BUTTON, self.advanced_main_menu) - self.advanced_menu.SetPosition( - wx.Point( - self.header.GetPosition().x, - self.post_install_setup.GetPosition().y + self.post_install_setup.GetSize().height - ) - ) - self.advanced_menu.Centre(wx.HORIZONTAL) - - # Help Button - self.help_button = wx.Button(self.frame, label="Help", size=(200,30)) - self.help_button.SetPosition( - wx.Point( - self.advanced_menu.GetPosition().x, - self.advanced_menu.GetPosition().y + self.advanced_menu.GetSize().height - ) - ) - self.help_button.Bind(wx.EVT_BUTTON, self.help_menu) - self.help_button.Centre(wx.HORIZONTAL) - - # Set the window size below help button - self.frame.SetSize( - self.WINDOW_WIDTH_MAIN, - self.help_button.GetPosition().y + self.help_button.GetSize().height + 40 - ) - - self.app.MainLoop() - - def first_time_setup_menu(self, event=None): - # Define Menu - # - Header: First Time Setup - # - Subheader: Model: {self.constants.custom_model or self.computer.real_model} - # - Label: Here we'll be downloading and create a macOS installer - # - Label: Then, install OpenCore onto the installer's drive (or any other bootable drive) - # - Button: Create macOS Installer - # - Button: Return to Main Menu - - self.frame.DestroyChildren() - self.walkthrough_mode = True - - # Header - self.header = wx.StaticText(self.frame, label="First Time Setup") - self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) - self.header.Centre(wx.HORIZONTAL) - - # Subheader - self.subheader = wx.StaticText(self.frame, label=f"Model: {self.constants.custom_model or self.computer.real_model}") - self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) - self.subheader.SetPosition( - wx.Point( - self.header.GetPosition().x, - self.header.GetPosition().y + self.header.GetSize().height + 5 - ) - ) - self.subheader.Centre(wx.HORIZONTAL) - - # Label: Here we'll be downloading and create a macOS installer - self.label_1 = wx.StaticText(self.frame, label="Here we'll download and create a macOS installer") - self.label_1.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) - self.label_1.SetPosition( - wx.Point( - self.header.GetPosition().x, - self.subheader.GetPosition().y + self.subheader.GetSize().height + 5 - ) - ) - self.label_1.Centre(wx.HORIZONTAL) - - # Label: Then, install OpenCore onto the installer's drive (or any other bootable drive) - self.label_2 = wx.StaticText(self.frame, label="Then, install OpenCore onto the installer's drive") - self.label_2.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) - self.label_2.SetPosition( - wx.Point( - self.header.GetPosition().x, - self.label_1.GetPosition().y + self.label_1.GetSize().height + 5 - ) - ) - self.label_2.Centre(wx.HORIZONTAL) - - # Label: Once finished, we can reboot and install macOS! - self.label_3 = wx.StaticText(self.frame, label="Once finished, we can reboot and install macOS!") - self.label_3.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) - self.label_3.SetPosition( - wx.Point( - self.header.GetPosition().x, - self.label_2.GetPosition().y + self.label_2.GetSize().height + 5 - ) - ) - self.label_3.Centre(wx.HORIZONTAL) - - # Button: Create macOS Installer - self.create_macos_installer = wx.Button(self.frame, label="Create macOS Installer", size=(200,30)) - self.create_macos_installer.Bind(wx.EVT_BUTTON, self.not_yet_implemented_menu) - self.create_macos_installer.SetPosition( - wx.Point( - self.header.GetPosition().x, - self.label_3.GetPosition().y + self.label_3.GetSize().height + 5 - ) - ) - self.create_macos_installer.Centre(wx.HORIZONTAL) - - # Button: Return to Main Menu - self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu", size=(200,30)) - self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) - self.return_to_main_menu.SetPosition( - - wx.Point( - self.create_macos_installer.GetPosition().x, - self.create_macos_installer.GetPosition().y + self.create_macos_installer.GetSize().height - ) - ) - self.return_to_main_menu.Centre(wx.HORIZONTAL) - - # Set the window size below return to main menu button - self.frame.SetSize( - -1, - self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40 - ) def main_menu(self, event=None): # Define Menu From fd67032afeea8ea4a762cd5fafb39cc094c9a2d2 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 7 Jan 2022 17:12:31 -0700 Subject: [PATCH 31/38] gui.py: Add FeatureUnlock configurability --- gui/gui_main.py | 157 ++++++++++++++++------------------- resources/build.py | 14 +--- resources/cli_menu.py | 3 +- resources/constants.py | 4 +- resources/generate_smbios.py | 15 +++- 5 files changed, 92 insertions(+), 101 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index 161451b23..63bea29a2 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -11,7 +11,7 @@ import os import wx.adv from wx.lib.agw import hyperlink -from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect, sys_patch, run +from resources import constants, defaults, build, install, installer, utilities, sys_patch_detect, sys_patch, run, generate_smbios from data import model_array, os_data, smbios_data, sip_data from gui import menu_redirect @@ -352,7 +352,6 @@ class wx_python_gui: self.overclock.Centre(wx.HORIZONTAL) - # Return to Main Menu self.return_to_main = wx.Button(self.frame, label="Return to Main Menu", size=(150,30)) self.return_to_main.SetPosition( wx.Point( @@ -422,7 +421,6 @@ class wx_python_gui: sys.stdout=menu_redirect.RedirectText(self.stdout_text, False) sys.stderr=menu_redirect.RedirectText(self.stdout_text, False) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -505,7 +503,6 @@ class wx_python_gui: - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -516,7 +513,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) def install_oc_disk_select(self, disk, disk_data): @@ -554,7 +550,6 @@ class wx_python_gui: self.install_button.Centre(wx.HORIZONTAL) i += self.install_button.GetSize().height + 3 - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -565,7 +560,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) def install_oc_process(self, partition): @@ -598,7 +592,6 @@ class wx_python_gui: install.tui_disk_installation(self.constants).install_opencore(partition) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -610,7 +603,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(self.WINDOW_WIDTH_BUILD, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) def root_patch_menu(self, event=None): @@ -705,7 +697,6 @@ class wx_python_gui: if self.constants.detected_os < os_data.os_data.big_sur: self.revert_root_patches.Disable() - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -716,7 +707,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) def root_patch_start(self, event=None): @@ -767,7 +757,6 @@ class wx_python_gui: ) self.text_box.Centre(wx.HORIZONTAL) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -778,7 +767,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) wx.GetApp().Yield() @@ -844,7 +832,6 @@ class wx_python_gui: ) self.text_box.Centre(wx.HORIZONTAL) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -855,7 +842,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) # Start reverting root patches @@ -905,7 +891,6 @@ class wx_python_gui: self.use_existing_macos_installer.Bind(wx.EVT_BUTTON, self.flash_installer_menu) self.use_existing_macos_installer.Centre(wx.HORIZONTAL) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -916,7 +901,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) def grab_installer_data(self, event=None): @@ -931,7 +915,6 @@ class wx_python_gui: self.download_label = wx.StaticText(self.frame, label="Downloading installer catalog...") self.download_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) self.download_label.SetPosition( - # Set Position below header wx.Point( self.header.GetPosition().x, self.header.GetPosition().y + self.header.GetSize().height + 10 @@ -941,7 +924,6 @@ class wx_python_gui: # Redirect stdout to label sys.stdout=menu_redirect.RedirectLabel(self.download_label) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -969,7 +951,6 @@ class wx_python_gui: self.subheader = wx.StaticText(self.frame, label="Installers currently available from Apple:") self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.subheader.SetPosition( - # Set Position below header wx.Point( self.header.GetPosition().x, self.header.GetPosition().y + self.header.GetSize().height + 10 @@ -1008,7 +989,6 @@ class wx_python_gui: self.install_selection.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.install_selection.Centre(wx.HORIZONTAL) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -1019,7 +999,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) def download_macos_click(self, installer_name, installer_link): @@ -1035,7 +1014,6 @@ class wx_python_gui: self.download_label = wx.StaticText(self.frame, label="Downloading...") self.download_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) self.download_label.SetPosition( - # Set Position below header wx.Point( self.header.GetPosition().x, self.header.GetPosition().y + self.header.GetSize().height + 10 @@ -1045,7 +1023,6 @@ class wx_python_gui: # Redirect stdout to label sys.stdout=menu_redirect.RedirectLabel(self.download_label) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -1090,8 +1067,18 @@ class wx_python_gui: self.header = wx.StaticText(self.frame, label="Select macOS Installer") self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.header.Centre(wx.HORIZONTAL) + # Subheader: Installers found in /Applications + self.subheader = wx.StaticText(self.frame, label="Installers found in Applications folder") + self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.subheader.SetPosition( + wx.Point( + self.header.GetPosition().x, + self.header.GetPosition().y + self.header.GetSize().height + ) + ) + self.subheader.Centre(wx.HORIZONTAL) - i = -10 + i = -7 avalible_installers = installer.list_local_macOS_installers() if avalible_installers: print("Installer found") @@ -1121,7 +1108,6 @@ class wx_python_gui: ) self.install_selection.Centre(wx.HORIZONTAL) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -1132,7 +1118,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) def format_usb_menu(self, installer_path): @@ -1148,7 +1133,6 @@ class wx_python_gui: self.subheader = wx.StaticText(self.frame, label="Selected USB will be erased, please backup your data") self.subheader.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD)) self.subheader.SetPosition( - # Set Position below header wx.Point( self.header.GetPosition().x, self.header.GetPosition().y + self.header.GetSize().height + 10 @@ -1160,7 +1144,6 @@ class wx_python_gui: self.usb_selection_label = wx.StaticText(self.frame, label="Missing drives? Ensure they're 14GB+ and removable") self.usb_selection_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) self.usb_selection_label.SetPosition( - # Set Position below header wx.Point( self.subheader.GetPosition().x, self.subheader.GetPosition().y + self.subheader.GetSize().height + 10 @@ -1198,7 +1181,6 @@ class wx_python_gui: ) self.usb_selection.Centre(wx.HORIZONTAL) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -1209,7 +1191,6 @@ class wx_python_gui: self.return_to_main_menu.Bind(wx.EVT_BUTTON, self.main_menu) self.return_to_main_menu.Centre(wx.HORIZONTAL) - # Update frame height to right below return_to_main_menu self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) def format_usb_progress(self, disk, installer_path): @@ -1224,7 +1205,6 @@ class wx_python_gui: self.creating_macos_installer_label = wx.StaticText(self.frame, label="Formatting and flashing installer to drive") self.creating_macos_installer_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) self.creating_macos_installer_label.SetPosition( - # Set Position below header wx.Point( self.header.GetPosition().x, self.header.GetPosition().y + self.header.GetSize().height + 10 @@ -1236,7 +1216,6 @@ class wx_python_gui: self.developer_note_label = wx.StaticText(self.frame, label="\tDeveloper Note: createinstallmedia output will print after finishing\nIf Application becomes unresponsive, this is due to slow USB flash drives.\n\tPlease do not close this window until the process is complete.") self.developer_note_label.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) self.developer_note_label.SetPosition( - # Set Position below header wx.Point( self.creating_macos_installer_label.GetPosition().x, self.creating_macos_installer_label.GetPosition().y + self.creating_macos_installer_label.GetSize().height + 10 @@ -1248,7 +1227,6 @@ class wx_python_gui: # Redirect stdout to a text box self.stdout_text = wx.TextCtrl(self.frame, style=wx.TE_MULTILINE | wx.TE_READONLY) self.stdout_text.SetPosition( - # Set Position below header wx.Point( self.developer_note_label.GetPosition().x, self.developer_note_label.GetPosition().y + self.developer_note_label.GetSize().height + 10 @@ -1263,7 +1241,6 @@ class wx_python_gui: self.stdout_text.Centre(wx.HORIZONTAL) self.stdout_text.SetValue("") - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu.SetPosition( wx.Point( @@ -1276,7 +1253,6 @@ class wx_python_gui: self.frame.Show() - # Update frame height to right below return_to_main_menu self.frame.SetSize(-1, self.return_to_main_menu.GetPosition().y + self.return_to_main_menu.GetSize().height + 40) wx.GetApp().Yield() # Create installer.sh script @@ -1377,13 +1353,6 @@ class wx_python_gui: self.opencore_checkbox.Bind(wx.EVT_CHECKBOX, self.oc_checkbox_click) self.opencore_checkbox.ToolTip = wx.ToolTip("""Enables OpenCore logging, can heavily impact boot times""") - # # Checkbox: SIP - # self.sip_checkbox = wx.CheckBox(self.frame, label="SIP") - # self.sip_checkbox.SetValue(self.constants.sip_status) - # self.sip_checkbox.SetPosition(wx.Point(self.opencore_checkbox.GetPosition().x , self.opencore_checkbox.GetPosition().y + self.opencore_checkbox.GetSize().height)) - # self.sip_checkbox.Bind(wx.EVT_CHECKBOX, self.sip_checkbox_click) - # self.sip_checkbox.ToolTip = wx.ToolTip("""Sets SIP, disable to allow root patching""") - # Checkbox: SecureBootModel self.secureboot_checkbox = wx.CheckBox(self.frame, label="SecureBootModel") self.secureboot_checkbox.SetValue(self.constants.secure_status) @@ -1405,7 +1374,6 @@ class wx_python_gui: self.accel_checkbox.Bind(wx.EVT_CHECKBOX, self.accel_checkbox_click) self.accel_checkbox.ToolTip = wx.ToolTip("""Allows Root Patching on Mojave/Catalina\nUseful for enabling TeraScale 2 Acceleration when not provided by dosdude1's patcher""") - # Buttons # Button: SIP Settings @@ -1414,7 +1382,7 @@ class wx_python_gui: elif self.constants.sip_status: sip_string = "Enabled" else: - sip_string = "Disabled" + sip_string = "Lowered" self.sip_button = wx.Button(self.frame, label=f"SIP Settings ({sip_string})", size=(155,30)) self.sip_button.SetPosition(wx.Point(self.accel_checkbox.GetPosition().x , self.accel_checkbox.GetPosition().y + self.accel_checkbox.GetSize().height + 10)) self.sip_button.Bind(wx.EVT_BUTTON, self.sip_config_menu) @@ -1432,7 +1400,6 @@ class wx_python_gui: self.miscellaneous_button.Bind(wx.EVT_BUTTON, self.misc_settings_menu) self.miscellaneous_button.Centre(wx.HORIZONTAL) - # Return to Main Menu self.return_to_main_menu = wx.Button(self.frame, label="Return to Main Menu", size=(155,30)) self.return_to_main_menu.SetPosition( wx.Point( @@ -1540,17 +1507,39 @@ class wx_python_gui: # Subheader: If unfamiliar with the following settings, please do not change them. self.subheader = wx.StaticText(self.frame, label="Do not change if unfamiliar", style=wx.ALIGN_CENTRE) self.subheader.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) - self.subheader.SetPosition(wx.Point(0, self.header.GetPosition().y + self.header.GetSize().height + 10)) + self.subheader.SetPosition(wx.Point(0, self.header.GetPosition().y + self.header.GetSize().height)) self.subheader.SetSize(wx.Size(self.frame.GetSize().width, 30)) self.subheader.Centre(wx.HORIZONTAL) + # Label: Set FeatreUnlock status + self.feature_unlock_label = wx.StaticText(self.frame, label="Feature Unlock Status:", style=wx.ALIGN_CENTRE) + self.feature_unlock_label.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + self.feature_unlock_label.SetPosition(wx.Point(0, self.subheader.GetPosition().y + self.subheader.GetSize().height -5)) + self.feature_unlock_label.Centre(wx.HORIZONTAL) + + # Dropdown: Set Feature Unlock status + self.feature_unlock_dropdown = wx.Choice(self.frame) + for entry in ["Enabled", "Paritally enabled (No AirPlay/SideCar)", "Disabled"]: + self.feature_unlock_dropdown.Append(entry) + self.feature_unlock_dropdown.SetPosition(wx.Point(0, self.feature_unlock_label.GetPosition().y + self.feature_unlock_label.GetSize().height + 5)) + if self.constants.fu_status is True: + if self.constants.fu_arguments is None: + selection = 0 + else: + selection = 1 + else: + selection = 2 + self.feature_unlock_dropdown.SetSelection(selection) + self.feature_unlock_dropdown.Bind(wx.EVT_CHOICE, self.fu_selection_click) + self.feature_unlock_dropdown.Centre(wx.HORIZONTAL) # Label: Set GPU Model for MXM iMacs self.label_model = wx.StaticText(self.frame, label="Set GPU Model for MXM iMacs:", style=wx.ALIGN_CENTRE) self.label_model.SetFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) - self.label_model.SetPosition(wx.Point(0, self.subheader.GetPosition().y + self.subheader.GetSize().height)) + self.label_model.SetPosition(wx.Point(0, self.feature_unlock_dropdown.GetPosition().y + self.feature_unlock_dropdown.GetSize().height + 2)) self.label_model.SetSize(wx.Size(self.frame.GetSize().width, 30)) self.label_model.Centre(wx.HORIZONTAL) + self.label_model.SetToolTip(wx.ToolTip("Configures MXM GPU Vendor logic on pre-built models\nIf you are not using MXM iMacs, please leave this setting as is.")) # Dropdown: GPU Model self.gpu_dropdown = wx.Choice(self.frame) @@ -1562,6 +1551,8 @@ class wx_python_gui: self.label_model.GetPosition().y + self.label_model.GetSize().height / 1.5)) self.gpu_dropdown.Bind(wx.EVT_CHOICE, self.gpu_selection_click) self.gpu_dropdown.Centre(wx.HORIZONTAL) + if self.computer.real_model not in ["iMac10,1", "iMac11,1", "iMac11,2", "iMac11,3", "iMac12,1", "iMac12,2"]: + self.gpu_dropdown.Disable() # Checkbox List: # FireWire Boot @@ -1579,13 +1570,16 @@ class wx_python_gui: self.firewire_boot_checkbox.SetValue(self.constants.firewire_boot) self.firewire_boot_checkbox.Bind(wx.EVT_CHECKBOX, self.firewire_click) self.firewire_boot_checkbox.SetPosition(wx.Point(30, self.gpu_dropdown.GetPosition().y + self.gpu_dropdown.GetSize().height + 5)) + self.firewire_boot_checkbox.SetToolTip(wx.ToolTip("Enable FireWire Boot support in macOS 10.15 and newer.\nMainly applicable for Macs with FireWire or Thunderbolt to FireWire adapters")) + if generate_smbios.check_firewire(self.computer.real_model) is False and not self.constants.custom_model: + self.firewire_boot_checkbox.Disable() # NVMe Boot self.nvme_boot_checkbox = wx.CheckBox(self.frame, label="NVMe Boot") self.nvme_boot_checkbox.SetValue(self.constants.nvme_boot) self.nvme_boot_checkbox.Bind(wx.EVT_CHECKBOX, self.nvme_click) self.nvme_boot_checkbox.SetPosition(wx.Point(self.firewire_boot_checkbox.GetPosition().x, self.firewire_boot_checkbox.GetPosition().y + self.firewire_boot_checkbox.GetSize().height)) - + self.nvme_boot_checkbox.SetToolTip(wx.ToolTip("Enables NVMe support in UEFI for non-native systems (ie. MacPro3,1)\nRequires OpenCore to be stored on a natively bootable volume however")) # Wake on WLAN self.wake_on_wlan_checkbox = wx.CheckBox(self.frame, label="Wake on WLAN") @@ -1594,6 +1588,7 @@ class wx_python_gui: self.wake_on_wlan_checkbox.SetPosition(wx.Point( self.nvme_boot_checkbox.GetPosition().x, self.nvme_boot_checkbox.GetPosition().y + self.nvme_boot_checkbox.GetSize().height)) + self.wake_on_wlan_checkbox.SetToolTip(wx.ToolTip("Enables Wake on WLAN for Broadcom Wifi.\nBy default, Wake on WLAN is disabled to work around Apple's wake from sleep bug causing heavily degraded networking performance.")) # Disable Thunderbolt self.disable_thunderbolt_checkbox = wx.CheckBox(self.frame, label="Disable Thunderbolt") @@ -1602,7 +1597,9 @@ class wx_python_gui: self.disable_thunderbolt_checkbox.SetPosition(wx.Point( self.wake_on_wlan_checkbox.GetPosition().x, self.wake_on_wlan_checkbox.GetPosition().y + self.wake_on_wlan_checkbox.GetSize().height)) - + self.disable_thunderbolt_checkbox.SetToolTip(wx.ToolTip("Disables Thunderbolt support on MacBookPro11,x\nMainly applicable for systems that cannot boot with Thunderbolt enabled")) + if not self.constants.custom_model and not self.computer.real_model.startswith("MacBookPro11"): + self.disable_thunderbolt_checkbox.Disable() # Set TeraScale 2 Accel self.set_terascale_accel_checkbox = wx.CheckBox(self.frame, label="Set TeraScale 2 Accel") self.set_terascale_accel_checkbox.SetValue(self.constants.allow_ts2_accel) @@ -1610,6 +1607,9 @@ class wx_python_gui: self.set_terascale_accel_checkbox.SetPosition(wx.Point( self.disable_thunderbolt_checkbox.GetPosition().x, self.disable_thunderbolt_checkbox.GetPosition().y + self.disable_thunderbolt_checkbox.GetSize().height)) + self.set_terascale_accel_checkbox.SetToolTip(wx.ToolTip("This option will determine whether TeraScale 2 acceleration is avalible during Root Volume patching.\nOnly applicable if your system has a AMD TeraScale 2 GPU (ie. MacBookPro8,2/3)")) + if self.computer.real_model not in ["MacBookPro8,2", "MacBookPro8,3"]: + self.set_terascale_accel_checkbox.Disable() # Windows GMUX self.windows_gmux_checkbox = wx.CheckBox(self.frame, label="Windows GMUX") @@ -1618,6 +1618,7 @@ class wx_python_gui: self.windows_gmux_checkbox.SetPosition(wx.Point( self.set_terascale_accel_checkbox.GetPosition().x, self.set_terascale_accel_checkbox.GetPosition().y + self.set_terascale_accel_checkbox.GetSize().height)) + self.windows_gmux_checkbox.SetToolTip(wx.ToolTip("Enable this option to allow usage of the hardware GMUX to switch between Intel and Nvidia/AMD GPUs in Windows.")) # Hibernation Workaround self.hibernation_checkbox = wx.CheckBox(self.frame, label="Hibernation Workaround") @@ -1626,6 +1627,7 @@ class wx_python_gui: self.hibernation_checkbox.SetPosition(wx.Point( self.windows_gmux_checkbox.GetPosition().x, self.windows_gmux_checkbox.GetPosition().y + self.windows_gmux_checkbox.GetSize().height)) + self.hibernation_checkbox.SetToolTip(wx.ToolTip("This will disable the ConnectDrivers in OpenCore\nRecommended to toggle if your machine is having issues with hibernation.\nMainly applicable for MacBookPro9,1 and MacBookPro10,1")) # Disable Battery Throttling self.disable_battery_throttling_checkbox = wx.CheckBox(self.frame, label="Disable Battery Throttling") @@ -1634,6 +1636,7 @@ class wx_python_gui: self.disable_battery_throttling_checkbox.SetPosition(wx.Point( self.hibernation_checkbox.GetPosition().x, self.hibernation_checkbox.GetPosition().y + self.hibernation_checkbox.GetSize().height)) + self.disable_battery_throttling_checkbox.SetToolTip(wx.ToolTip("This will forcefully disable MSR Power Control on Arrendale and newer Laptops\nMainly applicable for systems with severe battery throttling")) # Software Demux self.software_demux_checkbox = wx.CheckBox(self.frame, label="Software Demux") @@ -1642,6 +1645,9 @@ class wx_python_gui: self.software_demux_checkbox.SetPosition(wx.Point( self.disable_battery_throttling_checkbox.GetPosition().x, self.disable_battery_throttling_checkbox.GetPosition().y + self.disable_battery_throttling_checkbox.GetSize().height)) + self.software_demux_checkbox.SetToolTip(wx.ToolTip("This will force a software based demux on MacBookPro8,2/3 aiding for better battery life\nThis will require the dGPU to be disabled via NVRAM")) + if not self.constants.custom_model and self.computer.real_model not in ["MacBookPro8,2", "MacBookPro8,3"]: + self.software_demux_checkbox.Disable() # Disable CPUFriend self.disable_cpu_friend_checkbox = wx.CheckBox(self.frame, label="Disable CPUFriend") @@ -1650,6 +1656,9 @@ class wx_python_gui: self.disable_cpu_friend_checkbox.SetPosition(wx.Point( self.software_demux_checkbox.GetPosition().x, self.software_demux_checkbox.GetPosition().y + self.software_demux_checkbox.GetSize().height)) + self.disable_cpu_friend_checkbox.SetToolTip(wx.ToolTip("This will disable CPUFriend on your system when using Minimal or higher SMBIOS spoofing.\nMainly applicable for older iMacs (2007-9) that wish to disable CPU throttling")) + if self.constants.serial_settings == "None": + self.disable_cpu_friend_checkbox.Disable() # AppleALC Usage self.apple_alc_checkbox = wx.CheckBox(self.frame, label="AppleALC Usage") @@ -1658,6 +1667,7 @@ class wx_python_gui: self.apple_alc_checkbox.SetPosition(wx.Point( self.disable_cpu_friend_checkbox.GetPosition().x, self.disable_cpu_friend_checkbox.GetPosition().y + self.disable_cpu_friend_checkbox.GetSize().height)) + self.apple_alc_checkbox.SetToolTip(wx.ToolTip("This will set whether AppleALC is allowed to be used during config building.\nMainly applicable for MacPro3,1s that do not have boot screen support, thus preventing AppleALC from working.")) # Set WriteFlash self.set_writeflash_checkbox = wx.CheckBox(self.frame, label="Set NVRAM WriteFlash") @@ -1666,6 +1676,7 @@ class wx_python_gui: self.set_writeflash_checkbox.SetPosition(wx.Point( self.apple_alc_checkbox.GetPosition().x, self.apple_alc_checkbox.GetPosition().y + self.apple_alc_checkbox.GetSize().height)) + self.set_writeflash_checkbox.SetToolTip(wx.ToolTip("This will set whether OpenCore is allowed to write to hardware NVRAM.\nDisable this option if your system has degraded or fragile NVRAM.")) # Button: Developer Debug Info self.debug_button = wx.Button(self.frame, label="Developer Debug Info") @@ -1802,6 +1813,18 @@ class wx_python_gui: print(f"GPU Vendor: {self.constants.imac_vendor}") print(f"GPU Model: {self.constants.imac_model}") + def fu_selection_click(self, event=None): + fu_choice = self.feature_unlock_dropdown.GetStringSelection() + if fu_choice == "Enabled": + self.constants.fu_status = True + self.constants.fu_arguments = None + elif fu_choice == "Paritally enabled (No AirPlay/SideCar)": + self.constants.fu_status = True + self.constants.fu_arguments = " -disable_sidecar_mac" + else: + self.constants.fu_status = False + self.constants.fu_arguments = None + def set_writeflash_click(self, event=None): if self.set_writeflash_checkbox.GetValue(): print("Write Flash Enabled") @@ -1881,20 +1904,7 @@ class wx_python_gui: self.constants.override_smbios = selection def additional_info_menu(self, event=None): - # Define Menu: - - # Header: Additional Info - # Label: Model Dump - # Textbox: Model Dump - # Label: Real User ID - # Label: Effective User ID - # Label: Launcher Binary - # Textbox: Launcher Binary - # Label: Launcher Script - # Textbox: Launcher Script - self.frame.DestroyChildren() - self.frame.SetSize(wx.Size(500, -1)) # Header: Additional Info @@ -1971,7 +1981,6 @@ class wx_python_gui: self.launcher_script_textbox.Center(wx.HORIZONTAL) self.launcher_script_textbox.SetEditable(False) - # Return to Main Menu Button self.return_to_main_menu_button = wx.Button(self.frame, label="Return to Main Menu") self.return_to_main_menu_button.SetPosition( wx.Point(self.launcher_script_textbox.GetPosition().x, self.launcher_script_textbox.GetPosition().y + self.launcher_script_textbox.GetSize().height + 10) @@ -1984,11 +1993,6 @@ class wx_python_gui: def sip_config_menu(self, event=None): - # Implement individual checkbox for each bit in SIP - # Add label showing 'self.constants.custom_sip_value' - # custom_sip_value is equivlant to all enabled checkboxes - # Refresh label whenever checkbox is changed - self.frame.DestroyChildren() self.frame.SetSize(wx.Size(400, 600)) @@ -2008,8 +2012,6 @@ class wx_python_gui: self.sip_label.SetPosition( wx.Point(self.sip_label.GetPosition().x - 25, -1) ) - - # Hyperlink to the right of sip_label hyperlink_label = hyperlink.HyperLinkCtrl( self.frame, @@ -2020,14 +2022,6 @@ class wx_python_gui: ) hyperlink_label.SetForegroundColour((25, 179, 231)) - # Label: By default, SIP is set to 0x00 (enabled) on newer Macs. - # For older Macs requiring root patching, we set SIP to (0xA03) - # This corresponds to the following bits: - # - 0x1 - CSR_ALLOW_UNTRUSTED_KEXTS - # - 0x2 - CSR_ALLOW_UNRESTRICTED_FS - # - 0x200 - CSR_ALLOW_UNAPPROVED_KEXTS - # - 0x800 - CSR_ALLOW_UNAUTHENTICATED_ROOT - if self.constants.custom_sip_value is not None: self.sip_value = int(self.constants.custom_sip_value, 16) elif self.constants.sip_status is True: @@ -2063,11 +2057,6 @@ class wx_python_gui: ) self.sip_label_5.Center(wx.HORIZONTAL) - # Label: If you system requires SIP to be lowered, do not try to re-enable it. - # You may accidentally break your system. OpenCore Legacy Patcher by default - # knows the most ideal SIP value for your system. Override this value if you - # understand the consequences or are absolutely certain your configuration supports SIP - # in the OSes you wish to run OpenCore Legacy Patcher on. warning_string = """ OpenCore Legacy Patcher by default knows the most ideal SIP value for your system. Override this value only if you diff --git a/resources/build.py b/resources/build.py index 967738e6b..f361186ad 100644 --- a/resources/build.py +++ b/resources/build.py @@ -478,20 +478,8 @@ class BuildOpenCore: # Used to enable Audio support for non-standard dGPUs self.enable_kext("AppleALC.kext", self.constants.applealc_version, self.constants.applealc_path) - def check_firewire(model): - # MacBooks never supported FireWire - # Pre-Thunderbolt MacBook Airs as well - if model.startswith("MacBookPro"): - return True - elif model.startswith("MacBookAir"): - if smbios_data.smbios_dictionary[self.model]["CPU Generation"] < cpu_data.cpu_data.sandy_bridge.value: - return False - elif model.startswith("MacBook"): - return False - else: - return True - if self.constants.firewire_boot is True and check_firewire(self.model) is True: + if self.constants.firewire_boot is True and generate_smbios.check_firewire(self.model) is True: # Enable FireWire Boot Support # Applicable for both native FireWire and Thunderbolt to FireWire adapters print("- Enabling FireWire Boot Support") diff --git a/resources/cli_menu.py b/resources/cli_menu.py index fa2330767..eb128e2ec 100644 --- a/resources/cli_menu.py +++ b/resources/cli_menu.py @@ -857,12 +857,13 @@ Supported Options: change_menu = input("Set FeatreUnlock (ie. 1): ") if change_menu == "1": self.constants.fu_status = True - self.constants.fu_arguments = "" + self.constants.fu_arguments = None elif change_menu == "2": self.constants.fu_status = True self.constants.fu_arguments = " -disable_sidecar_mac" elif change_menu == "3": self.constants.fu_status = False + self.constants.fu_arguments = None else: print("Invalid input, returning to previous menu") self.set_fu_settings() diff --git a/resources/constants.py b/resources/constants.py index fd98e2b23..a08790a30 100644 --- a/resources/constants.py +++ b/resources/constants.py @@ -124,8 +124,8 @@ class Constants: self.override_smbios = "Default" # Set SMBIOS model used ## FeatureUnlock Settings - self.fu_status = True # Enable FeatureUnlock - self.fu_arguments = "" # Set FeatureUnlock arguments + self.fu_status = True # Enable FeatureUnlock + self.fu_arguments = None # Set FeatureUnlock arguments ## Latebloom Settings self.latebloom_status = False # Latebloom Enabled diff --git a/resources/generate_smbios.py b/resources/generate_smbios.py index 1dd01437b..7ffefbdb9 100644 --- a/resources/generate_smbios.py +++ b/resources/generate_smbios.py @@ -1,4 +1,4 @@ -from data import smbios_data, os_data +from data import smbios_data, os_data, cpu_data from resources import utilities @@ -98,3 +98,16 @@ def find_model_off_board(board): key = "MacPro5,1" return key return None + +def check_firewire(model): + # MacBooks never supported FireWire + # Pre-Thunderbolt MacBook Airs as well + if model.startswith("MacBookPro"): + return True + elif model.startswith("MacBookAir"): + if smbios_data.smbios_dictionary[model]["CPU Generation"] < cpu_data.cpu_data.sandy_bridge.value: + return False + elif model.startswith("MacBook"): + return False + else: + return True \ No newline at end of file From 54b4c27d4ac151a1a90f4602bc20d8e54c1d2d1b Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Sun, 9 Jan 2022 10:29:07 -0700 Subject: [PATCH 32/38] gui.py: Add ThirdPartyDrives option --- gui/gui_main.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index 63bea29a2..88068a209 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -1532,6 +1532,7 @@ class wx_python_gui: self.feature_unlock_dropdown.SetSelection(selection) self.feature_unlock_dropdown.Bind(wx.EVT_CHOICE, self.fu_selection_click) self.feature_unlock_dropdown.Centre(wx.HORIZONTAL) + self.feature_unlock_dropdown.SetToolTip(wx.ToolTip("Set whether FeatureUnlock support level\nBy default, full functionality is enabled. For systems experiencing memory instability, lowering this option to disable AirPlay/Sidecar patch sets is recommended.")) # Label: Set GPU Model for MXM iMacs self.label_model = wx.StaticText(self.frame, label="Set GPU Model for MXM iMacs:", style=wx.ALIGN_CENTRE) @@ -1539,7 +1540,6 @@ class wx_python_gui: self.label_model.SetPosition(wx.Point(0, self.feature_unlock_dropdown.GetPosition().y + self.feature_unlock_dropdown.GetSize().height + 2)) self.label_model.SetSize(wx.Size(self.frame.GetSize().width, 30)) self.label_model.Centre(wx.HORIZONTAL) - self.label_model.SetToolTip(wx.ToolTip("Configures MXM GPU Vendor logic on pre-built models\nIf you are not using MXM iMacs, please leave this setting as is.")) # Dropdown: GPU Model self.gpu_dropdown = wx.Choice(self.frame) @@ -1551,6 +1551,7 @@ class wx_python_gui: self.label_model.GetPosition().y + self.label_model.GetSize().height / 1.5)) self.gpu_dropdown.Bind(wx.EVT_CHOICE, self.gpu_selection_click) self.gpu_dropdown.Centre(wx.HORIZONTAL) + self.gpu_dropdown.SetToolTip(wx.ToolTip("Configures MXM GPU Vendor logic on pre-built models\nIf you are not using MXM iMacs, please leave this setting as is.")) if self.computer.real_model not in ["iMac10,1", "iMac11,1", "iMac11,2", "iMac11,3", "iMac12,1", "iMac12,2"]: self.gpu_dropdown.Disable() @@ -1677,13 +1678,24 @@ class wx_python_gui: self.apple_alc_checkbox.GetPosition().x, self.apple_alc_checkbox.GetPosition().y + self.apple_alc_checkbox.GetSize().height)) self.set_writeflash_checkbox.SetToolTip(wx.ToolTip("This will set whether OpenCore is allowed to write to hardware NVRAM.\nDisable this option if your system has degraded or fragile NVRAM.")) + # Set Enhanced 3rd Party SSD + self.set_enhanced_3rd_party_ssd_checkbox = wx.CheckBox(self.frame, label="Enhanced SSD Support") + self.set_enhanced_3rd_party_ssd_checkbox.SetValue(self.constants.allow_3rd_party_drives) + self.set_enhanced_3rd_party_ssd_checkbox.Bind(wx.EVT_CHECKBOX, self.set_enhanced_3rd_party_ssd_click) + self.set_enhanced_3rd_party_ssd_checkbox.SetPosition(wx.Point( + self.set_writeflash_checkbox.GetPosition().x, + self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height)) + self.set_enhanced_3rd_party_ssd_checkbox.SetToolTip(wx.ToolTip("This will set whether OpenCore is allowed to force Apple Vendor on 3rd Party SATA SSDs\nSome benefits from this patch include better SSD performance, TRIM support and hibernation support.\nDisable this option if your SSD does not support TRIM correctly")) + if self.computer.third_party_sata_ssd is False and not self.constants.custom_model: + self.set_enhanced_3rd_party_ssd_checkbox.Disable() + # Button: Developer Debug Info self.debug_button = wx.Button(self.frame, label="Developer Debug Info") self.debug_button.Bind(wx.EVT_BUTTON, self.additional_info_menu) self.debug_button.SetPosition(wx.Point( - self.set_writeflash_checkbox.GetPosition().x, - self.set_writeflash_checkbox.GetPosition().y + self.set_writeflash_checkbox.GetSize().height + 5)) + self.set_enhanced_3rd_party_ssd_checkbox.GetPosition().x, + self.set_enhanced_3rd_party_ssd_checkbox.GetPosition().y + self.set_enhanced_3rd_party_ssd_checkbox.GetSize().height + 5)) self.debug_button.Center(wx.HORIZONTAL) # Button: return to main menu @@ -1784,6 +1796,14 @@ class wx_python_gui: else: print("AppleALC Usage Disabled") self.constants.set_alc_usage = False + + def set_enhanced_3rd_party_ssd_click(self, event=None): + if self.set_enhanced_3rd_party_ssd_checkbox.GetValue(): + print("Enhanced 3rd Party SSDs Enabled") + self.constants.allow_3rd_party_drives = True + else: + print("Enhanced 3rd Party SSDs Disabled") + self.constants.allow_3rd_party_drives = False def gpu_selection_click(self, event=None): gpu_choice = self.gpu_dropdown.GetStringSelection() From 7ecf9ff151c052135810331baed306215e5edaee Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Tue, 11 Jan 2022 09:21:38 -0700 Subject: [PATCH 33/38] Update docs --- .../workflows/build-app-wxpython-offline.yml | 10 +---- README.md | 2 +- SOURCE.md | 39 +++++++------------ requirements.txt | 3 +- 4 files changed, 18 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build-app-wxpython-offline.yml b/.github/workflows/build-app-wxpython-offline.yml index 73affca15..ddad4237c 100644 --- a/.github/workflows/build-app-wxpython-offline.yml +++ b/.github/workflows/build-app-wxpython-offline.yml @@ -1,10 +1,4 @@ -on: - push: - workflow_dispatch: - release: - types: [published] - -name: CI - Build Offline wxPython +name: CI - Build wxPython Offline on: push: @@ -14,7 +8,7 @@ on: jobs: build: - name: Build Offline wxPython + name: Build wxPython Offline runs-on: x86_64_mojave steps: - uses: actions/checkout@v2 diff --git a/README.md b/README.md index 3b678eb89..b5779c8b4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

OpenCore Legacy Patcher

-A python program with an [Objective-C GUI](https://github.com/dortania/OCLP-GUI) for building and booting [OpenCore](https://github.com/acidanthera/OpenCorePkg) on both legacy and modern Macs, see our in-depth [Guide](https://dortania.github.io/OpenCore-Legacy-Patcher/) for more information. +A python program for building and booting [OpenCore](https://github.com/acidanthera/OpenCorePkg) on both legacy and modern Macs, see our in-depth [Guide](https://dortania.github.io/OpenCore-Legacy-Patcher/) for more information. Supported features: diff --git a/SOURCE.md b/SOURCE.md index d0373104f..b3e36aba7 100644 --- a/SOURCE.md +++ b/SOURCE.md @@ -4,7 +4,8 @@ OpenCore Legacy Patcher at its core is a python-based TUI/CLI based application. For developers wishing to validate mainline changes, you may use these nightly links: -* [GUI (Graphical Based App)](https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-gui/main/OpenCore-Patcher-GUI.app.zip) +* [GUI (Graphical Based App)](https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-app-wxpython/main/OpenCore-Patcher-GUI.app.zip) +* [GUI (Graphical Based App) - Offline Variant](https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-app-wxpython-offline/main/OpenCore-Patcher-GUI.app.zip) * [TUI (Text Based App)](https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-app/main/OpenCore-Patcher-TUI.app.zip) * [TUI (Text Based App) - Offline Variant](https://nightly.link/dortania/OpenCore-Legacy-Patcher/workflows/build-app/main/OpenCore-Patcher-TUI-Offline.app.zip) @@ -36,12 +37,19 @@ pip3 install -r requirements.txt To run the project from source, simply invoke via python3: ```sh +# Launch TUI python3 OpenCore-Patcher.command ``` +```sh +# Launch GUI +python3 OpenCore-Patcher-GUI.command +``` + Note that the OpenCore-Patcher.command file can be run as both a TUI and a CLI utility for other programs to call. If no core arguments are passed, the TUI is initialized. Otherwise the CLI will start: ```sh +# Launch CLI python3 OpenCore-Patcher.command --build --model iMac12,2 --verbose ``` @@ -49,7 +57,7 @@ See `-h`/`--help` for more information on supported CLI arguments. ## Generating prebuilt binaries -The main goal of generating prebuilt binaries is to strip the requirement of a local python installation for users. For developers, there's very little benefit besides for usage with the project's GUI ([Generating the GUI](#generating-the-gui)). For development, simply use the OpenCore-Patcher.command file with a python3 installation. +The main goal of generating prebuilt binaries is to strip the requirement of a local python installation for users. For developers, there's very little benefit besides enabling dark mode support in the GUI. For development, simply use the OpenCore-Patcher.command file with a python3 installation. * Note that due to PyInstaller's linking mechanism, binaries generated on Catalina and newer are not compatible with High Sierra and older * To ensure the largest compatibility, generate binaries on macOS Mojave. These binaries will be compatible with macOS 10.9 to macOS 12. @@ -60,9 +68,9 @@ The main goal of generating prebuilt binaries is to strip the requirement of a l pip3 install pyinstaller # Move into project directory cd ~/Developer/OpenCore-Legacy-Patcher/ -# Create the pyinstaller based Application +# Create the pyinstaller based Application (replace OpenCore-Patcher.spec with OpenCore-Patcher-GUI.spec for GUI binary) pyinstaller OpenCore-Patcher.spec -# Post PyInstaller clean up +# Post PyInstaller clean up (only for the TUI) ./after_pyinstaller.sh # Open build folder open ./dist/ @@ -70,25 +78,4 @@ open ./dist/ Once done, you'll find the application generated at `./dist/OpenCore-Patcher.app`: -![](./images/build-dist.png) - -## Generating the GUI - -To generate a GUI, you will have need a core `OpenCore-Patcher` binary generated during the above stage([Generating prebuilt binaries](#generating-prebuilt-binaries)). - -Once conditions are met, you'll be able to work with the GUI portion. The source of which is found at [dortania/OCLP-GUI](https://github.com/dortania/OCLP-GUI). - -```sh -# Move into a directory to store the project -cd ~/Developer -# Clone project -git clone https://github.com/dortania/OCLP-GUI -# Update the OpenCore-Patcher binary from the core project -cp ./OpenCore-Legacy-Patcher/dist/OpenCore-Patcher ./OCLP-GUI/OpenCore\ Patcher/OpenCore\ Patcher/ -# Rename binary to OCLP-CLI -mv ./OCLP-GUI/OpenCore\ Patcher/OpenCore\ Patcher/OCLP-GUI/OpenCore-Patcher ./OCLP-GUI/OpenCore\ Patcher/OpenCore\ Patcher/OCLP-GUI/OCLP-CLI -# Build project -cd ./OCLP-GUI/OpenCore\ Patcher; xcodebuild; cd ../../ -# Open build folder -open ./OCLP-GUI/OpenCore\ Patcher/build/Release/ -``` \ No newline at end of file +![](./images/build-dist.png) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 9e7648675..48afcd905 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ requests -pyobjc \ No newline at end of file +pyobjc +wxpython \ No newline at end of file From 31812f0485302be119de78448d90630df6e176ed Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Tue, 11 Jan 2022 10:35:57 -0700 Subject: [PATCH 34/38] Resolve validation run --- .github/workflows/build-app-wxpython-offline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-app-wxpython-offline.yml b/.github/workflows/build-app-wxpython-offline.yml index ddad4237c..2ed83d367 100644 --- a/.github/workflows/build-app-wxpython-offline.yml +++ b/.github/workflows/build-app-wxpython-offline.yml @@ -32,4 +32,4 @@ jobs: file_glob: true asset_name: OpenCore-Patcher.app (GUI Offline, macOS 10.13 and newer) - name: Validate OpenCore - run: ./OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher --validate \ No newline at end of file + run: ./dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher --validate \ No newline at end of file From 7e236f06e5e43b5b7ec9cca9f64d1b05bcbfadbc Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Thu, 13 Jan 2022 12:21:16 -0700 Subject: [PATCH 35/38] gui.py: Add Cmd+Q support --- gui/gui_main.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/gui/gui_main.py b/gui/gui_main.py index 88068a209..9e5fe0f91 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -26,6 +26,8 @@ class wx_python_gui: self.stock_stdout = sys.stdout self.stock_stderr = sys.stderr + current_uid = os.getuid() + # Define Window Size self.WINDOW_WIDTH_MAIN = 350 self.WINDOW_HEIGHT_MAIN = 220 @@ -45,12 +47,24 @@ class wx_python_gui: self.frame.Show() self.frame.Bind(wx.EVT_CLOSE, self.OnCloseFrame) + # Create Menubar (allows Cmd+Q usage) + self.menubar = wx.MenuBar() + self.file_menu = wx.Menu() + self.file_menu.Append(wx.ID_EXIT, "Quit", "Quit Application" ) + self.file_menu.Append(wx.ID_REDO, f"Relaunch as Root (UID: {int(current_uid)})", "Relaunch OpenCore Legacy Patcher as Root") + self.menubar.Append(self.file_menu, "File") + self.frame.Bind(wx.EVT_MENU, self.OnCloseFrame, id=wx.ID_EXIT) + self.frame.Bind(wx.EVT_MENU, self.relaunch_as_root, id=wx.ID_REDO) + self.frame.SetMenuBar(self.menubar) + + if current_uid == 0: + self.file_menu.Enable(wx.ID_REDO, False) + self.main_menu(None) wx.CallAfter(self.frame.Close) def OnCloseFrame(self, event): - print("Cleaning up on close") self.frame.DestroyChildren() self.frame.Destroy() self.app.ExitMainLoop() @@ -80,15 +94,15 @@ class wx_python_gui: if self.dialog.ShowModal() == wx.ID_YES: print("Relaunching as root") if self.constants.launcher_script is None: - args_string = f"{self.constants.launcher_binary}""" + args_string = f"'{self.constants.launcher_binary}'" else: args_string = f"{self.constants.launcher_binary} {self.constants.launcher_script}" args = [ "osascript", "-e", - f'''do shell script "'{args_string}'"''' - ' with prompt "OpenCore Legacy Patcher needs administrator privileges to mount your EFI."' + f'''do shell script "{args_string}"''' + ' with prompt "OpenCore Legacy Patcher needs administrator privileges to relaunch as admin."' " with administrator privileges" " without altering line endings", ] @@ -183,7 +197,7 @@ class wx_python_gui: self.reset_window() # Set header text - self.frame.SetTitle(f"OpenCore Legacy Patcher v{self.constants.patcher_version}") + self.frame.SetTitle(f"OpenCore Legacy Patcher") # Header self.header = wx.StaticText(self.frame, label=f"OpenCore Legacy Patcher v{self.constants.patcher_version}") self.header.SetFont(wx.Font(18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) From 43a708d3aea06df782fad110b1a7c1e8bb611be8 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 14 Jan 2022 11:28:26 -0700 Subject: [PATCH 36/38] sys_patch.py: Strip User ID printing --- resources/sys_patch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/sys_patch.py b/resources/sys_patch.py index bbf65488c..9c22d96aa 100644 --- a/resources/sys_patch.py +++ b/resources/sys_patch.py @@ -83,7 +83,6 @@ class PatchSysVolume: self.unpatch_root_vol() return True else: - print(f"User ID: {os.getuid()} - {os.geteuid()}") if self.constants.detected_os > os_data.os_data.catalina: print("- Mounting APFS Snapshot as writable") result = utilities.elevated(["mount", "-o", "nobrowse", "-t", "apfs", f"/dev/{self.root_mount_path}", self.mount_location], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) From 5ea1b5075b8fe050f2b66033015ca266961ac320 Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 14 Jan 2022 15:38:12 -0700 Subject: [PATCH 37/38] Implement single binary for 10.10-12.0 --- .../workflows/build-app-wxpython-offline.yml | 4 +-- .github/workflows/build-app-wxpython.yml | 26 +++---------------- merge_gui.py | 10 ------- merge_gui_legacy.py | 10 ------- payloads/binary.py | 10 +++++++ 5 files changed, 15 insertions(+), 45 deletions(-) delete mode 100644 merge_gui.py delete mode 100644 merge_gui_legacy.py create mode 100644 payloads/binary.py diff --git a/.github/workflows/build-app-wxpython-offline.yml b/.github/workflows/build-app-wxpython-offline.yml index 2ed83d367..29adef56a 100644 --- a/.github/workflows/build-app-wxpython-offline.yml +++ b/.github/workflows/build-app-wxpython-offline.yml @@ -20,7 +20,7 @@ jobs: - name: Upload App to Artifacts uses: actions/upload-artifact@v2 with: - name: OpenCore-Patcher.app (GUI Offline, macOS 10.13 and newer) + name: OpenCore-Patcher.app (GUI Offline) path: OpenCore-Patcher-wxPython.app.zip - name: Upload to Release if: github.event_name == 'release' @@ -30,6 +30,6 @@ jobs: file: OpenCore-Patcher-wxPython.app.zip tag: ${{ github.ref }} file_glob: true - asset_name: OpenCore-Patcher.app (GUI Offline, macOS 10.13 and newer) + asset_name: OpenCore-Patcher.app (GUI Offline) - name: Validate OpenCore run: ./dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher --validate \ No newline at end of file diff --git a/.github/workflows/build-app-wxpython.yml b/.github/workflows/build-app-wxpython.yml index 6f1275580..289bcdf2d 100644 --- a/.github/workflows/build-app-wxpython.yml +++ b/.github/workflows/build-app-wxpython.yml @@ -13,25 +13,15 @@ jobs: steps: - uses: actions/checkout@v2 - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher-GUI.spec - - run: cp -r dist/OpenCore-Patcher.app dist/OpenCore-Patcher-Legacy.app - - run: cp payloads/launcher.sh dist/OpenCore-Patcher-Legacy.app/Contents/MacOS/Launcher - - run: python3 merge_gui_legacy.py + - run: python3 ./payloads/binary.py - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' - - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher-Legacy.app"' - run: cd dist; zip -r ../OpenCore-Patcher-wxPython.app.zip OpenCore-Patcher.app - - run: cd dist; zip -r ../OpenCore-Patcher-wxPython-Legacy.app.zip OpenCore-Patcher-Legacy.app - run: ./../sign-wxpython.sh - name: Upload App to Artifacts uses: actions/upload-artifact@v2 with: - name: OpenCore-Patcher.app (GUI, macOS 10.13 and newer) + name: OpenCore-Patcher.app (GUI) path: OpenCore-Patcher-wxPython.app.zip - - name: Upload Legacy App to Artifacts - uses: actions/upload-artifact@v2 - with: - name: OpenCore-Patcher.app (GUI, macOS 10.12 and older) - path: OpenCore-Patcher-wxPython-Legacy.app.zip - - name: Upload to Release if: github.event_name == 'release' uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d @@ -40,14 +30,4 @@ jobs: file: OpenCore-Patcher-wxPython.app.zip tag: ${{ github.ref }} file_glob: true - asset_name: OpenCore-Patcher.app (GUI, macOS 10.13 and newer) - - - name: Upload Legacy to Release - if: github.event_name == 'release' - uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: OpenCore-Patcher-wxPython-Legacy.app.zip - tag: ${{ github.ref }} - file_glob: true - asset_name: OpenCore-Patcher.app (GUI, macOS 10.12 and older) + asset_name: OpenCore-Patcher.app (GUI) \ No newline at end of file diff --git a/merge_gui.py b/merge_gui.py deleted file mode 100644 index b8f8d8995..000000000 --- a/merge_gui.py +++ /dev/null @@ -1,10 +0,0 @@ -# Updates build version in OCLP-GUI during CI builds -# Copyright (C) 2021-2022 Mykola Grymalyuk -import plistlib -from pathlib import Path -from resources import constants - -app_path = Path.cwd() / Path ("OpenCore Patcher.app/Contents/Info.plist") -info = plistlib.load(Path(app_path).open("rb")) -info["CFBundleShortVersionString"] = constants.Constants().patcher_version -plistlib.dump(info, Path(app_path).open("wb"), sort_keys=True) \ No newline at end of file diff --git a/merge_gui_legacy.py b/merge_gui_legacy.py deleted file mode 100644 index 156e5f765..000000000 --- a/merge_gui_legacy.py +++ /dev/null @@ -1,10 +0,0 @@ -# Updates build version in OCLP-GUI during CI builds -# Copyright (C) 2021 Mykola Grymalyuk -import plistlib -from pathlib import Path -from resources import constants - -app_path = Path.cwd() / Path ("dist/OpenCore-Patcher-Legacy.app/Contents/Info.plist") -info = plistlib.load(Path(app_path).open("rb")) -info["CFBundleExecutable"] = "Launcher" -plistlib.dump(info, Path(app_path).open("wb"), sort_keys=True) \ No newline at end of file diff --git a/payloads/binary.py b/payloads/binary.py new file mode 100644 index 000000000..7e6f5fa62 --- /dev/null +++ b/payloads/binary.py @@ -0,0 +1,10 @@ + +path = './dist/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher' +find = b'\x00\x0D\x0A\x00' +replace = b'\x00\x0A\x0A\x00' +# Open file in binary mode +with open(path, 'rb') as f: + data = f.read() + data = data.replace(find, replace) + with open(path, 'wb') as f: + f.write(data) \ No newline at end of file From cc914aadc15a99d3d8e0e5a1c4111326055f748c Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Fri, 14 Jan 2022 15:53:17 -0700 Subject: [PATCH 38/38] Add signing to offline TUI --- .github/workflows/build-app-offline.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-app-offline.yml b/.github/workflows/build-app-offline.yml index 976994fc3..29679387c 100644 --- a/.github/workflows/build-app-offline.yml +++ b/.github/workflows/build-app-offline.yml @@ -16,18 +16,20 @@ jobs: - run: /Library/Frameworks/Python.framework/Versions/3.9/bin/pyinstaller OpenCore-Patcher.spec - run: ./after_pyinstaller.sh - run: 'codesign -s "Developer ID Application: Mykola Grymalyuk (S74BDJXQMD)" -v --force --deep --timestamp --entitlements ./payloads/entitlements.plist -o runtime "dist/OpenCore-Patcher.app"' - - run: cd dist; zip -r ../OpenCore-Patcher-TUI-Offline.app.zip OpenCore-Patcher.app + - run: cd dist; zip -r ../OpenCore-Patcher-TUI.app.zip OpenCore-Patcher.app + - run: ./../sign-tui.sh - name: Upload App to Artifacts uses: actions/upload-artifact@v2 with: - name: OpenCore-Patcher-TUI-Offline.app - path: OpenCore-Patcher-TUI-Offline.app.zip + name: OpenCore-Patcher-TUI.app (Offline) + path: OpenCore-Patcher-TUI.app.zip - name: Upload to Release if: github.event_name == 'release' uses: svenstaro/upload-release-action@e74ff71f7d8a4c4745b560a485cc5fdb9b5b999d with: repo_token: ${{ secrets.GITHUB_TOKEN }} - file: OpenCore-Patcher-TUI-Offline.app.zip + asset_name: OpenCore-Patcher-TUI.app (Offline) + file: OpenCore-Patcher-TUI.app.zip tag: ${{ github.ref }} file_glob: true