-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.py
174 lines (136 loc) · 6.22 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import os
import sys
import multiprocessing
from PyQt5 import QtWidgets, QtCore, QtGui
from backend.logger import Logger
from backend.error_dumper import ErrorDumper
from backend.utils import Utils
from backend.nyx_base import NyxBase
from backend.timer import Timer
from frontend.nyx import Nyx
# Ensure high DPI scaling attributes are set before creating QApplication
if hasattr(QtCore.Qt, 'AA_EnableHighDpiScaling'):
QtWidgets.QApplication.setAttribute(QtCore.Qt.ApplicationAttribute.AA_EnableHighDpiScaling, True)
if hasattr(QtCore.Qt, 'AA_UseHighDpiPixmaps'):
QtWidgets.QApplication.setAttribute(QtCore.Qt.ApplicationAttribute.AA_UseHighDpiPixmaps, True)
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
class AppRunner:
def __init__(self):
# Initialize the mutex to check for existing instances
self.mutex = QtCore.QSharedMemory("unique_application_key")
if self.mutex.attach(QtCore.QSharedMemory.ReadOnly):
# Only show notification if this is the main instance
if not hasattr(sys, '_called_from_test'):
self.show_instance_notification()
sys.exit(0) # Exit if another instance is running
# Try to create the mutex
if not self.mutex.create(1):
print("Failed to create mutex.")
sys.exit(1)
with Timer(__class__.__name__):
self.app = QtWidgets.QApplication(sys.argv)
self.logger = Logger()
self.utils = Utils()
self.nyx_base = NyxBase()
self.nyx_path, self.error_logs_path = self.utils.create_nyx_folders()
self.error_dumper = ErrorDumper(self.error_logs_path)
# Set the custom excepthook
sys.excepthook = self._custom_excepthook
self.tray_icon = None
def _custom_excepthook(self, exception_type, exception_value, traceback):
self.error_dumper.dump_error(exception_type.__name__, str(exception_value))
def show_instance_notification(self):
# Create a QApplication instance to show the notification
notification_app = QtWidgets.QApplication(sys.argv)
# Create a QDialog to show the message
msg_box = QtWidgets.QMessageBox()
msg_box.setIcon(QtWidgets.QMessageBox.Warning)
msg_box.setText("Another instance of Nyx is already running.")
msg_box.setInformativeText("Check the system tray for the running instance.")
msg_box.setWindowTitle("Nyx Already Running")
msg_box.setModal(True)
msg_box.exec_()
# Close the notification application
notification_app.quit()
def calculate_scale_factor(self, app):
screen = app.primaryScreen()
dpi = screen.logicalDotsPerInch()
base_dpi = self.nyx_base.get_dpi()
# Calculate the DPI scale factor
dpi_scale_factor = dpi / base_dpi
# Get the screen's current resolution
screen_resolution = screen.size()
base_resolution = self.nyx_base.get_screen_resolution()
# Calculate the resolution scale factor
res_scale_factor_width = screen_resolution.width() / base_resolution[0]
res_scale_factor_height = screen_resolution.height() / base_resolution[1]
# Use the smaller scale factor to ensure proper scaling
res_scale_factor = min(res_scale_factor_width, res_scale_factor_height)
# Calculate the final scale factor
scale_factor = dpi_scale_factor * res_scale_factor
return scale_factor
def hide_window(self):
self.main_window.hide()
if self.tray_icon:
self.tray_icon.setVisible(True)
def show_window(self):
self.main_window.showNormal()
self.main_window.activateWindow()
if self.tray_icon:
self.tray_icon.setVisible(False)
def exit_app(self):
if self.tray_icon:
self.tray_icon.setVisible(False)
QtWidgets.QApplication.quit()
def create_tray_icon(self):
# Load your custom icon
icon_path = os.path.join(os.path.dirname(sys.argv[0]), "frontend/icons/nyx.png")
if not os.path.exists(icon_path):
if hasattr(sys, '_MEIPASS'):
icon_path = os.path.join(sys._MEIPASS, "frontend/icons/nyx.png")
icon = QtGui.QIcon(icon_path)
self.tray_icon = QtWidgets.QSystemTrayIcon(icon, self.app)
# Create the context menu
tray_menu = QtWidgets.QMenu()
show_action = tray_menu.addAction("Show")
exit_action = tray_menu.addAction("Exit Nyx")
show_action.triggered.connect(self.show_window)
exit_action.triggered.connect(self.exit_app)
self.tray_icon.setContextMenu(tray_menu)
# Connect the activated signal to handle left-click event
self.tray_icon.activated.connect(self.on_tray_icon_activated)
self.tray_icon.show()
def on_tray_icon_activated(self, reason):
if reason == QtWidgets.QSystemTrayIcon.Trigger:
self.show_window()
def run(self):
self.logger.debug("Displaying main window")
try:
self.scale_factor = self.calculate_scale_factor(self.app)
self.logger.debug(f"Successful scale factor: {self.scale_factor}")
except Exception as e:
self.scale_factor = 1
self.logger.debug(f"Default scale factor: {self.scale_factor}, Exception: {e}")
self.main_window = QtWidgets.QMainWindow()
ui = Nyx(self.app, self.scale_factor)
ui.setupUi(self.main_window)
self.main_window.setWindowTitle("Nyx")
self.main_window.show()
# Override the close event
self.main_window.closeEvent = self.close_event
# Connect the minimize event
self.main_window.changeEvent = self.change_event
self.create_tray_icon()
sys.exit(self.app.exec())
def close_event(self, event):
event.ignore()
self.hide_window()
def change_event(self, event):
if event.type() == QtCore.QEvent.WindowStateChange:
if self.main_window.isMinimized():
self.hide_window()
if __name__ == "__main__":
# Pyinstaller fix
multiprocessing.freeze_support()
app_runner = AppRunner()
app_runner.run()