GUI: Implement Pulse() work-around for non-Metal

ASB I beg of you, please fix this. This hack is so painful…
This commit is contained in:
Mykola Grymalyuk
2023-05-12 09:44:44 -06:00
parent 3bd9d85ae2
commit 28d3e981c5
7 changed files with 153 additions and 12 deletions

View File

@@ -585,6 +585,7 @@ class LocalInstallerCatalog:
"Build": app_sdk,
"Path": application,
"Minimum Host OS": min_required,
"OS": kernel
}
})

View File

@@ -21,6 +21,8 @@ class InstallOCFrame(wx.Frame):
self.available_disks: dict = None
self.stock_output = logging.getLogger().handlers[0].stream
self.progress_bar_animation: gui_support.GaugePulseCallback = None
self.hyperlink_colour = (25, 179, 231)
self._generate_elements()
@@ -55,7 +57,11 @@ class InstallOCFrame(wx.Frame):
# Progress bar: {indeterminate}
progress_bar = wx.Gauge(self, range=100, pos=(-1, text_label.GetPosition()[1] + text_label.GetSize()[1]), size=(150, 30), style=wx.GA_HORIZONTAL | wx.GA_SMOOTH)
progress_bar.Center(wx.HORIZONTAL)
progress_bar.Pulse()
progress_bar_animation = gui_support.GaugePulseCallback(self.constants, progress_bar)
progress_bar_animation.start_pulse()
self.progress_bar_animation = progress_bar_animation
self.progress_bar = progress_bar
@@ -77,6 +83,7 @@ class InstallOCFrame(wx.Frame):
wx.Yield()
continue
self.progress_bar_animation.stop_pulse()
self.progress_bar.Hide()
# Create wxDialog for disk selection

View File

@@ -81,7 +81,8 @@ class macOSInstallerFrame(wx.Frame):
# Progress bar
progress_bar = wx.Gauge(self, range=100, pos=(-1, title_label.GetPosition()[1] + title_label.GetSize()[1] + 5), size=(250, 30))
progress_bar.Center(wx.HORIZONTAL)
progress_bar.Pulse()
progress_bar_animation = gui_support.GaugePulseCallback(self.constants, progress_bar)
progress_bar_animation.start_pulse()
# Set size of frame
self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40))
@@ -100,6 +101,7 @@ class macOSInstallerFrame(wx.Frame):
while thread.is_alive():
wx.Yield()
progress_bar_animation.stop_pulse()
progress_bar.Hide()
self._display_available_installers()
@@ -233,7 +235,8 @@ class macOSInstallerFrame(wx.Frame):
chunk_label.SetLabel("May take a few minutes...")
chunk_label.Center(wx.HORIZONTAL)
progress_bar.Pulse()
progress_bar_animation = gui_support.GaugePulseCallback(self.constants, progress_bar)
progress_bar_animation.start_pulse()
# Start thread to extract installer
self.result = False
@@ -250,6 +253,7 @@ class macOSInstallerFrame(wx.Frame):
while thread.is_alive():
wx.Yield()
progress_bar_animation.stop_pulse()
progress_bar.Hide()
chunk_label.SetLabel("Successfully extracted macOS installer" if self.result is True else "Failed to extract macOS installer")
chunk_label.Center(wx.HORIZONTAL)

View File

@@ -8,7 +8,7 @@ import tempfile
from pathlib import Path
from resources.wx_gui import gui_main_menu, gui_build
from resources.wx_gui import gui_main_menu, gui_build, gui_support
from resources import (
constants,
macos_installer_handler,
@@ -31,6 +31,8 @@ class macOSInstallerFlashFrame(wx.Frame):
self.available_disks: dict = {}
self.prepare_result: bool = False
self.progress_bar_animation: gui_support.GaugePulseCallback = None
self.frame_modal: wx.Dialog = None
self._generate_elements()
@@ -54,7 +56,10 @@ class macOSInstallerFlashFrame(wx.Frame):
# Progress bar
progress_bar = wx.Gauge(self, range=100, pos=(-1, 30), size=(200, 30))
progress_bar.Center(wx.HORIZONTAL)
progress_bar.Pulse()
progress_bar_animation = gui_support.GaugePulseCallback(self.constants, progress_bar)
progress_bar_animation.start_pulse()
self.progress_bar_animation = progress_bar_animation
# Set size of frame
self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40))
@@ -105,6 +110,8 @@ class macOSInstallerFlashFrame(wx.Frame):
# Set size of frame
frame_modal.SetSize((-1, cancel_button.GetPosition()[1] + cancel_button.GetSize()[1] + 40))
self.progress_bar_animation.stop_pulse()
frame_modal.ShowWindowModal()
self.frame_modal = frame_modal
@@ -123,7 +130,9 @@ class macOSInstallerFlashFrame(wx.Frame):
# Progress bar
progress_bar = wx.Gauge(self, range=100, pos=(-1, 30), size=(200, 30))
progress_bar.Center(wx.HORIZONTAL)
progress_bar.Pulse()
progress_bar_animation = gui_support.GaugePulseCallback(self.constants, progress_bar)
progress_bar_animation.start_pulse()
# Set size of frame
self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40))
@@ -179,6 +188,9 @@ class macOSInstallerFlashFrame(wx.Frame):
# Set size of frame
self.frame_modal.SetSize((-1, cancel_button.GetPosition()[1] + cancel_button.GetSize()[1] + 40))
progress_bar_animation.stop_pulse()
self.frame_modal.ShowWindowModal()
@@ -217,7 +229,9 @@ class macOSInstallerFlashFrame(wx.Frame):
# Progress bar
progress_bar = wx.Gauge(self, range=100, pos=(-1, bytes_written_label.GetPosition()[1] + bytes_written_label.GetSize()[1] + 5), size=(300, 30))
progress_bar.Center(wx.HORIZONTAL)
progress_bar.Pulse()
progress_bar_animation = gui_support.GaugePulseCallback(self.constants, progress_bar)
progress_bar_animation.start_pulse()
# Set size of frame
self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40))
@@ -232,10 +246,11 @@ class macOSInstallerFlashFrame(wx.Frame):
# Base Size
estimated_size = 16000
# AutoPkg (700MB~)
estimated_size += 700 if self.constants.detected_os >= os_data.os_data.big_sur else 0
estimated_size += 700 if installer['OS'] >= os_data.os_data.big_sur else 0
# KDK (700MB~, and overhead for copying to installer)
estimated_size += 700 * 2 if self.constants.detected_os >= os_data.os_data.ventura else 0
estimated_size += 700 * 2 if installer['OS'] >= os_data.os_data.ventura else 0
progress_bar_animation.stop_pulse()
progress_bar.SetRange(estimated_size)
root_disk = disk['identifier'][5:]
@@ -259,10 +274,14 @@ class macOSInstallerFlashFrame(wx.Frame):
return
# Next verify the installer
progress_bar.Pulse()
progress_bar_animation = gui_support.GaugePulseCallback(self.constants, progress_bar)
progress_bar_animation.start_pulse()
bytes_written_label.SetLabel("Validating Installer Integrity...")
error_message = self._validate_installer_pkg(disk['identifier'])
progress_bar_animation.stop_pulse()
if error_message != "":
progress_bar.SetValue(0)
wx.MessageBox(f"Failed to validate installer, cannot continue.\n This can generally happen due to a faulty USB drive, as flashing is an intensive process that can trigger hardware faults not normally seen. \n\n{error_message}", "Corrupted Installer!", wx.OK | wx.ICON_ERROR)

View File

@@ -8,6 +8,7 @@ from resources.wx_gui import (
gui_settings,
)
from resources import constants
from data import model_array, os_data
class MainMenu(wx.Frame):
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None):
@@ -16,6 +17,9 @@ class MainMenu(wx.Frame):
self.constants: constants.Constants = global_constants
self.title: str = title
self.model_label: wx.StaticText = None
self.build_button: wx.Button = None
self._generate_elements()
self.SetPosition(screen_location) if screen_location else self.Centre()
@@ -64,6 +68,14 @@ class MainMenu(wx.Frame):
button.Center(wx.HORIZONTAL)
button_y += 30
if button_name == "Build and Install OpenCore":
self.build_button = button
if gui_support.CheckProperties(self.constants).host_can_build() is False:
button.Disable()
elif button_name == "Post-Install Root Patch":
if self.constants.detected_os < os_data.os_data.big_sur:
button.Disable()
# Text: Copyright
copy_label = wx.StaticText(self, label=self.constants.copyright_date, pos=(-1, button_y + 10))
copy_label.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))

View File

@@ -4,10 +4,12 @@ import sys
import time
import logging
import subprocess
import threading
from pathlib import Path
from resources import constants
from data import model_array, os_data
class GenerateMenubar:
@@ -21,6 +23,95 @@ class GenerateMenubar:
return self.menubar
class GaugePulseCallback:
"""
Uses an alternative Pulse() method for wx.Gauge() on macOS Monterey+
Dirty hack, however better to display some form of animation than none at all
"""
def __init__(self, global_constants: constants.Constants, gauge: wx.Gauge) -> None:
self.gauge: wx.Gauge = gauge
self.pulse_thread: threading.Thread = None
self.pulse_thread_active: bool = False
self.gauge_value: int = 0
self.pulse_forward: bool = True
self.non_metal_alternative: bool = CheckProperties(global_constants).host_is_non_metal()
def start_pulse(self) -> None:
if self.non_metal_alternative is False:
self.gauge.Pulse()
return
self.pulse_thread_active = True
self.pulse_thread = threading.Thread(target=self._pulse)
self.pulse_thread.start()
def stop_pulse(self) -> None:
if self.non_metal_alternative is False:
return
self.pulse_thread_active = False
self.pulse_thread.join()
def _pulse(self) -> None:
while self.pulse_thread_active:
if self.gauge_value == 0:
self.pulse_forward = True
elif self.gauge_value == 100:
self.pulse_forward = False
if self.pulse_forward:
self.gauge_value += 1
else:
self.gauge_value -= 1
wx.CallAfter(self.gauge.SetValue, self.gauge_value)
time.sleep(0.005)
class CheckProperties:
def __init__(self, global_constants: constants.Constants) -> None:
self.constants: constants.Constants = global_constants
def host_can_build(self):
"""
Check if host supports building OpenCore configs
"""
if self.constants.host_is_hackintosh is True:
return False
if self.constants.allow_oc_everywhere is True:
return True
if self.constants.custom_model:
return True
if self.constants.computer.real_model in model_array.SupportedSMBIOS:
return True
return False
def host_is_non_metal(self):
"""
Check if host is non-metal
Primarily for wx.Gauge().Pulse() workaround (where animation doesn't work on Monterey+)
"""
if self.constants.detected_os < os_data.os_data.monterey:
return False
if not Path("/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLightOld.dylib").exists():
# SkyLight stubs are only used on non-Metal
return False
return True
class PayloadMount:
def __init__(self, global_constants: constants.Constants, frame: wx.Frame) -> None:

View File

@@ -61,7 +61,9 @@ class SysPatchMenu(wx.Frame):
progress_bar = wx.Gauge(frame, range=100, pos=(-1, subheader.GetPosition()[1] + subheader.GetSize()[1] + 5), size=(250, 20))
progress_bar.Center(wx.HORIZONTAL)
progress_bar.Pulse()
progress_bar_animation = gui_support.GaugePulseCallback(self.constants, progress_bar)
progress_bar_animation.start_pulse()
# Set size of frame
frame.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 35))
@@ -76,10 +78,10 @@ class SysPatchMenu(wx.Frame):
kdk_thread.start()
while kdk_thread.is_alive():
progress_bar.Pulse()
wx.GetApp().Yield()
if self.kdk_obj.success is False:
progress_bar_animation.stop_pulse()
progress_bar.SetValue(0)
wx.MessageBox(f"KDK download failed: {self.kdk_obj.error_msg}", "Error", wx.OK | wx.ICON_ERROR)
return False
@@ -107,13 +109,18 @@ class SysPatchMenu(wx.Frame):
subheader.Center(wx.HORIZONTAL)
wx.GetApp().Yield()
progress_bar_animation.stop_pulse()
if self.kdk_obj.validate_kdk_checksum() is False:
progress_bar.SetValue(0)
logging.error("KDK checksum validation failed")
logging.error(self.kdk_obj.error_msg)
msg = wx.MessageDialog(frame, f"KDK checksum validation failed: {self.kdk_obj.error_msg}", "Error", wx.OK | wx.ICON_ERROR)
msg.ShowModal()
return False
progress_bar.SetValue(100)
logging.info("KDK download complete")
return True