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
+1
View File
@@ -585,6 +585,7 @@ class LocalInstallerCatalog:
"Build": app_sdk, "Build": app_sdk,
"Path": application, "Path": application,
"Minimum Host OS": min_required, "Minimum Host OS": min_required,
"OS": kernel
} }
}) })
+8 -1
View File
@@ -21,6 +21,8 @@ class InstallOCFrame(wx.Frame):
self.available_disks: dict = None self.available_disks: dict = None
self.stock_output = logging.getLogger().handlers[0].stream self.stock_output = logging.getLogger().handlers[0].stream
self.progress_bar_animation: gui_support.GaugePulseCallback = None
self.hyperlink_colour = (25, 179, 231) self.hyperlink_colour = (25, 179, 231)
self._generate_elements() self._generate_elements()
@@ -55,7 +57,11 @@ class InstallOCFrame(wx.Frame):
# Progress bar: {indeterminate} # 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 = 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.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 self.progress_bar = progress_bar
@@ -77,6 +83,7 @@ class InstallOCFrame(wx.Frame):
wx.Yield() wx.Yield()
continue continue
self.progress_bar_animation.stop_pulse()
self.progress_bar.Hide() self.progress_bar.Hide()
# Create wxDialog for disk selection # Create wxDialog for disk selection
@@ -81,7 +81,8 @@ class macOSInstallerFrame(wx.Frame):
# Progress bar # 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 = 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.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 # Set size of frame
self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40)) self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40))
@@ -100,6 +101,7 @@ class macOSInstallerFrame(wx.Frame):
while thread.is_alive(): while thread.is_alive():
wx.Yield() wx.Yield()
progress_bar_animation.stop_pulse()
progress_bar.Hide() progress_bar.Hide()
self._display_available_installers() self._display_available_installers()
@@ -233,7 +235,8 @@ class macOSInstallerFrame(wx.Frame):
chunk_label.SetLabel("May take a few minutes...") chunk_label.SetLabel("May take a few minutes...")
chunk_label.Center(wx.HORIZONTAL) 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 # Start thread to extract installer
self.result = False self.result = False
@@ -250,6 +253,7 @@ class macOSInstallerFrame(wx.Frame):
while thread.is_alive(): while thread.is_alive():
wx.Yield() wx.Yield()
progress_bar_animation.stop_pulse()
progress_bar.Hide() progress_bar.Hide()
chunk_label.SetLabel("Successfully extracted macOS installer" if self.result is True else "Failed to extract macOS installer") chunk_label.SetLabel("Successfully extracted macOS installer" if self.result is True else "Failed to extract macOS installer")
chunk_label.Center(wx.HORIZONTAL) chunk_label.Center(wx.HORIZONTAL)
+26 -7
View File
@@ -8,7 +8,7 @@ import tempfile
from pathlib import Path 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 ( from resources import (
constants, constants,
macos_installer_handler, macos_installer_handler,
@@ -31,6 +31,8 @@ class macOSInstallerFlashFrame(wx.Frame):
self.available_disks: dict = {} self.available_disks: dict = {}
self.prepare_result: bool = False self.prepare_result: bool = False
self.progress_bar_animation: gui_support.GaugePulseCallback = None
self.frame_modal: wx.Dialog = None self.frame_modal: wx.Dialog = None
self._generate_elements() self._generate_elements()
@@ -54,7 +56,10 @@ class macOSInstallerFlashFrame(wx.Frame):
# Progress bar # Progress bar
progress_bar = wx.Gauge(self, range=100, pos=(-1, 30), size=(200, 30)) progress_bar = wx.Gauge(self, range=100, pos=(-1, 30), size=(200, 30))
progress_bar.Center(wx.HORIZONTAL) 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 # Set size of frame
self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40)) self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40))
@@ -105,6 +110,8 @@ class macOSInstallerFlashFrame(wx.Frame):
# Set size of frame # Set size of frame
frame_modal.SetSize((-1, cancel_button.GetPosition()[1] + cancel_button.GetSize()[1] + 40)) frame_modal.SetSize((-1, cancel_button.GetPosition()[1] + cancel_button.GetSize()[1] + 40))
self.progress_bar_animation.stop_pulse()
frame_modal.ShowWindowModal() frame_modal.ShowWindowModal()
self.frame_modal = frame_modal self.frame_modal = frame_modal
@@ -123,7 +130,9 @@ class macOSInstallerFlashFrame(wx.Frame):
# Progress bar # Progress bar
progress_bar = wx.Gauge(self, range=100, pos=(-1, 30), size=(200, 30)) progress_bar = wx.Gauge(self, range=100, pos=(-1, 30), size=(200, 30))
progress_bar.Center(wx.HORIZONTAL) 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 # Set size of frame
self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40)) self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40))
@@ -179,6 +188,9 @@ class macOSInstallerFlashFrame(wx.Frame):
# Set size of frame # Set size of frame
self.frame_modal.SetSize((-1, cancel_button.GetPosition()[1] + cancel_button.GetSize()[1] + 40)) self.frame_modal.SetSize((-1, cancel_button.GetPosition()[1] + cancel_button.GetSize()[1] + 40))
progress_bar_animation.stop_pulse()
self.frame_modal.ShowWindowModal() self.frame_modal.ShowWindowModal()
@@ -217,7 +229,9 @@ class macOSInstallerFlashFrame(wx.Frame):
# Progress bar # 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 = 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.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 # Set size of frame
self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40)) self.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 40))
@@ -232,10 +246,11 @@ class macOSInstallerFlashFrame(wx.Frame):
# Base Size # Base Size
estimated_size = 16000 estimated_size = 16000
# AutoPkg (700MB~) # 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) # 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) progress_bar.SetRange(estimated_size)
root_disk = disk['identifier'][5:] root_disk = disk['identifier'][5:]
@@ -259,10 +274,14 @@ class macOSInstallerFlashFrame(wx.Frame):
return return
# Next verify the installer # 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...") bytes_written_label.SetLabel("Validating Installer Integrity...")
error_message = self._validate_installer_pkg(disk['identifier']) error_message = self._validate_installer_pkg(disk['identifier'])
progress_bar_animation.stop_pulse()
if error_message != "": if error_message != "":
progress_bar.SetValue(0) 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) 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)
+12
View File
@@ -8,6 +8,7 @@ from resources.wx_gui import (
gui_settings, gui_settings,
) )
from resources import constants from resources import constants
from data import model_array, os_data
class MainMenu(wx.Frame): class MainMenu(wx.Frame):
def __init__(self, parent: wx.Frame, title: str, global_constants: constants.Constants, screen_location: tuple = None): 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.constants: constants.Constants = global_constants
self.title: str = title self.title: str = title
self.model_label: wx.StaticText = None
self.build_button: wx.Button = None
self._generate_elements() self._generate_elements()
self.SetPosition(screen_location) if screen_location else self.Centre() self.SetPosition(screen_location) if screen_location else self.Centre()
@@ -64,6 +68,14 @@ class MainMenu(wx.Frame):
button.Center(wx.HORIZONTAL) button.Center(wx.HORIZONTAL)
button_y += 30 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 # Text: Copyright
copy_label = wx.StaticText(self, label=self.constants.copyright_date, pos=(-1, button_y + 10)) 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")) copy_label.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, ".AppleSystemUIFont"))
+91
View File
@@ -4,10 +4,12 @@ import sys
import time import time
import logging import logging
import subprocess import subprocess
import threading
from pathlib import Path from pathlib import Path
from resources import constants from resources import constants
from data import model_array, os_data
class GenerateMenubar: class GenerateMenubar:
@@ -21,6 +23,95 @@ class GenerateMenubar:
return self.menubar 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: class PayloadMount:
def __init__(self, global_constants: constants.Constants, frame: wx.Frame) -> None: def __init__(self, global_constants: constants.Constants, frame: wx.Frame) -> None:
+9 -2
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 = wx.Gauge(frame, range=100, pos=(-1, subheader.GetPosition()[1] + subheader.GetSize()[1] + 5), size=(250, 20))
progress_bar.Center(wx.HORIZONTAL) 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 # Set size of frame
frame.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 35)) frame.SetSize((-1, progress_bar.GetPosition()[1] + progress_bar.GetSize()[1] + 35))
@@ -76,10 +78,10 @@ class SysPatchMenu(wx.Frame):
kdk_thread.start() kdk_thread.start()
while kdk_thread.is_alive(): while kdk_thread.is_alive():
progress_bar.Pulse()
wx.GetApp().Yield() wx.GetApp().Yield()
if self.kdk_obj.success is False: if self.kdk_obj.success is False:
progress_bar_animation.stop_pulse()
progress_bar.SetValue(0) progress_bar.SetValue(0)
wx.MessageBox(f"KDK download failed: {self.kdk_obj.error_msg}", "Error", wx.OK | wx.ICON_ERROR) wx.MessageBox(f"KDK download failed: {self.kdk_obj.error_msg}", "Error", wx.OK | wx.ICON_ERROR)
return False return False
@@ -107,13 +109,18 @@ class SysPatchMenu(wx.Frame):
subheader.Center(wx.HORIZONTAL) subheader.Center(wx.HORIZONTAL)
wx.GetApp().Yield() wx.GetApp().Yield()
progress_bar_animation.stop_pulse()
if self.kdk_obj.validate_kdk_checksum() is False: if self.kdk_obj.validate_kdk_checksum() is False:
progress_bar.SetValue(0)
logging.error("KDK checksum validation failed") logging.error("KDK checksum validation failed")
logging.error(self.kdk_obj.error_msg) 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 = wx.MessageDialog(frame, f"KDK checksum validation failed: {self.kdk_obj.error_msg}", "Error", wx.OK | wx.ICON_ERROR)
msg.ShowModal() msg.ShowModal()
return False return False
progress_bar.SetValue(100)
logging.info("KDK download complete") logging.info("KDK download complete")
return True return True