Add rpm installer for Linux
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 shutdown4life
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -7,10 +7,12 @@ This is a fork of [corsair_lcd_tool](https://github.com/UDPSendToFailed/corsair_
|
||||
- Low resources usage compared to iCUE.
|
||||
|
||||
# Planned Features
|
||||
- .rpm installer
|
||||
- Overlay text
|
||||
- Implement temperatures
|
||||
|
||||
# TODO:
|
||||
- fix tray icon with .rpm
|
||||
|
||||
# Usage
|
||||
- Install [Python](https://www.python.org/downloads/ "Python") 3.6 or newer.
|
||||
- Clone the repo or download as ZIP and extract it to a new folder.
|
||||
@@ -28,7 +30,7 @@ It might work on Windows but to get sure use the original [corsair_lcd_tool by U
|
||||
|
||||
# WHY
|
||||
Because Corsair decided to do nothing for Linux users.
|
||||
If I have some time I might also integrate RGB Controllers in another repo!
|
||||
If I have some time I might also integrate RGB Controllers in another repo with a fork of this!
|
||||
|
||||
# Thanks to
|
||||
- [UDPSendToFailed](https://github.com/UDPSendToFailed "UDPSendToFailed") for the work. The main functionality is all in [corsair_lcd_tool](https://github.com/UDPSendToFailed/corsair_lcd_tool "corsair_lcd_tool")
|
||||
|
||||
8
corsair_lcd_tool.desktop
Normal file
8
corsair_lcd_tool.desktop
Normal file
@@ -0,0 +1,8 @@
|
||||
[Desktop Entry]
|
||||
Name=Corsair LCD Tool v2
|
||||
Comment=Manage Corsair LCD screens
|
||||
Exec=corsair-lcd-tool
|
||||
Icon=corsair-lcd-tool
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility;System;
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import logging, os, platform, sys, cv2, numpy as np, yaml, usb.core, errno
|
||||
from dataclasses import dataclass
|
||||
from PyQt6.QtCore import Qt, QTimer, QPointF, pyqtSignal, QThread, pyqtSlot, QRectF
|
||||
@@ -5,10 +6,13 @@ from PyQt6.QtGui import QPixmap, QPainter, QMovie, QIcon, QTransform, QImage, QA
|
||||
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QFileDialog, QSlider, QWidget, QGraphicsScene, \
|
||||
QGraphicsView, QGraphicsPixmapItem, QSystemTrayIcon, QMenu, QStyleFactory, QGraphicsItem, QCheckBox
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
import winshell
|
||||
elif platform.system() == 'Linux':
|
||||
import subprocess
|
||||
match platform.system():
|
||||
case 'Windows':
|
||||
import winshell
|
||||
case 'Linux':
|
||||
pass
|
||||
case _:
|
||||
raise RuntimeError("Unsupported platform. This script is designed for Windows or Linux.")
|
||||
|
||||
# Set up logging
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
@@ -89,7 +93,11 @@ class UpdateDeviceThread(QThread):
|
||||
device.set_configuration()
|
||||
except usb.core.USBError as e:
|
||||
if e.errno == errno.EACCES:
|
||||
raise PermissionError("[Access denied] Please set appropriate udev rules (Linux) or use administrator rights (Windows).")
|
||||
match platform.system():
|
||||
case 'Windows':
|
||||
raise PermissionError("[Access denied] Please use administrator rights.")
|
||||
case 'Linux':
|
||||
raise PermissionError("[Access denied] Please set appropriate udev rules.")
|
||||
elif e.errno == errno.EBUSY:
|
||||
raise RuntimeError("[Device busy] Device is blocked by another process or the kernel.")
|
||||
else:
|
||||
@@ -177,7 +185,9 @@ class MainWindow(QMainWindow):
|
||||
self.pixmap_item.setPos(QPointF(0, 0))
|
||||
|
||||
self.tray_icon = QSystemTrayIcon(self)
|
||||
self.tray_icon.setIcon(QIcon('icon.ico'))
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
icon_path = os.path.join(script_dir, 'corsair-lcd-tool.png')
|
||||
self.tray_icon.setIcon(QIcon(icon_path))
|
||||
|
||||
self.window_state_handler = WindowStateHandler(self)
|
||||
|
||||
@@ -193,7 +203,8 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.container = QWidget(self)
|
||||
self.container.setGeometry(60, 20, 480, 480)
|
||||
self.container.setStyleSheet("border: 0px")
|
||||
# black background so the empty space is not visible on the LCD
|
||||
self.container.setStyleSheet("background-color: #000000; border: 0px")
|
||||
|
||||
self.scene = QGraphicsScene(self.container)
|
||||
self.view = NoScrollGraphicsView(self.scene, self.container)
|
||||
@@ -219,16 +230,14 @@ class MainWindow(QMainWindow):
|
||||
|
||||
if platform.system() == "Windows":
|
||||
self.startup_folder = winshell.startup()
|
||||
|
||||
self.shortcut_path = os.path.join(self.startup_folder, 'corsair_lcd_tool.lnk')
|
||||
else:
|
||||
pass
|
||||
|
||||
self.python_path = sys.executable
|
||||
|
||||
self.startup_checkbox = QCheckBox("Run at startup", self)
|
||||
self.startup_checkbox.setGeometry(60, 580, 120, 30)
|
||||
self.startup_checkbox.clicked.connect(self.update_startup)
|
||||
if platform.system() == "Windows":
|
||||
self.startup_checkbox = QCheckBox("Run at startup", self)
|
||||
self.startup_checkbox.setGeometry(60, 580, 120, 30)
|
||||
self.startup_checkbox.clicked.connect(self.update_startup)
|
||||
|
||||
self.slider = QSlider(Qt.Orientation.Horizontal, self)
|
||||
self.slider.setGeometry(60, 510, 480, 20)
|
||||
@@ -250,7 +259,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.tray_icon.setContextMenu(self.tray_menu)
|
||||
|
||||
self.setWindowIcon(QIcon('icon.ico'))
|
||||
self.setWindowIcon(QIcon(icon_path))
|
||||
self.movie = None
|
||||
|
||||
logging.debug("MainWindow initialized")
|
||||
@@ -284,10 +293,11 @@ class MainWindow(QMainWindow):
|
||||
self.save_state_handler = SaveStateHandler(self)
|
||||
self.save_state_handler.load_image_state()
|
||||
|
||||
if not self.startup_checkbox.isChecked():
|
||||
self.show()
|
||||
else:
|
||||
QTimer.singleShot(5, self.window_state_handler.minimize_window)
|
||||
if platform.system() == "Windows":
|
||||
if not self.startup_checkbox.isChecked():
|
||||
self.show()
|
||||
else:
|
||||
QTimer.singleShot(5, self.window_state_handler.minimize_window)
|
||||
logging.debug("UI Initialized")
|
||||
|
||||
def update_startup(self):
|
||||
@@ -308,36 +318,6 @@ class MainWindow(QMainWindow):
|
||||
if os.path.exists(self.shortcut_path):
|
||||
os.remove(self.shortcut_path)
|
||||
logging.debug("Shortcut removed.")
|
||||
elif platform.system() == "Linux":
|
||||
service_name = os.path.basename(self.script_path).replace(".py", ".service")
|
||||
service_path = os.path.join(os.path.expanduser("~"), ".config/systemd/user", service_name)
|
||||
|
||||
service_content = f"""[Unit]
|
||||
Description=Corsair LCD Tool
|
||||
|
||||
[Service]
|
||||
ExecStart={self.python_path} {self.script_path}
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
"""
|
||||
|
||||
os.makedirs(os.path.dirname(service_path), exist_ok=True)
|
||||
|
||||
if state:
|
||||
with open(service_path, 'w') as f:
|
||||
f.write(service_content)
|
||||
|
||||
subprocess.run(["systemctl", "--user", "daemon-reload"], check=True)
|
||||
subprocess.run(["systemctl", "--user", "enable", service_name], check=True)
|
||||
logging.debug("Systemd user service created and enabled.")
|
||||
else:
|
||||
if os.path.exists(service_path):
|
||||
os.remove(service_path)
|
||||
subprocess.run(["systemctl", "--user", "daemon-reload"], check=True)
|
||||
subprocess.run(["systemctl", "--user", "disable", service_name], check=True)
|
||||
logging.debug("Systemd user service removed.")
|
||||
|
||||
def open_image(self):
|
||||
logging.debug("Entering open_image function")
|
||||
@@ -354,7 +334,7 @@ class MainWindow(QMainWindow):
|
||||
pixmap.fill(Qt.GlobalColor.transparent)
|
||||
painter = QPainter(pixmap)
|
||||
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||
painter.setBrush(QColor(0, 0, 0, 50))
|
||||
painter.setBrush(QColor(0, 0, 0, 150))
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
painter.drawRect(0, 0, size, size)
|
||||
painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_Clear)
|
||||
@@ -473,7 +453,8 @@ class SaveStateHandler:
|
||||
self.main.slider.setValue(state.get('last_slider_value'))
|
||||
self.main.view.horizontalScrollBar().setValue(state.get('last_scrollbar_pos')[0])
|
||||
self.main.view.verticalScrollBar().setValue(state.get('last_scrollbar_pos')[1])
|
||||
self.main.startup_checkbox.setChecked(state.get('startup_checkbox_state', False))
|
||||
if platform.system() == "Windows":
|
||||
self.main.startup_checkbox.setChecked(state.get('startup_checkbox_state', False))
|
||||
logging.debug(f"Loaded state: {state}")
|
||||
else:
|
||||
logging.warning(
|
||||
@@ -504,9 +485,10 @@ class SaveStateHandler:
|
||||
'last_scene_rect': [self.main.scene.sceneRect().x(), self.main.scene.sceneRect().y(),
|
||||
self.main.scene.sceneRect().width(), self.main.scene.sceneRect().height()],
|
||||
'last_scrollbar_pos': [self.main.view.horizontalScrollBar().value(),
|
||||
self.main.view.verticalScrollBar().value()],
|
||||
'startup_checkbox_state': self.main.startup_checkbox.isChecked()
|
||||
self.main.view.verticalScrollBar().value()]
|
||||
}
|
||||
if sys.platform.startswith("win"):
|
||||
state['startup_checkbox_state'] = self.main.startup_checkbox.isChecked()
|
||||
with open('state.yaml', 'w') as file:
|
||||
yaml.dump(state, file)
|
||||
logging.debug(f"Saved state to disk: {state}")
|
||||
|
||||
@@ -10,4 +10,4 @@ sudo cp udev/99-corsair.rules /etc/udev/rules.d/
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger
|
||||
|
||||
echo "✅ Done! Please replug the USB device now."
|
||||
echo "✅ Done!"
|
||||
@@ -1,7 +1,5 @@
|
||||
hidapi
|
||||
numpy
|
||||
opencv-python
|
||||
openrgb-python
|
||||
PyQt6
|
||||
pyyaml
|
||||
winshell
|
||||
|
||||
63
rpm/corsair_lcd_tool_v2.spec
Normal file
63
rpm/corsair_lcd_tool_v2.spec
Normal file
@@ -0,0 +1,63 @@
|
||||
Name: corsair_lcd_tool_v2
|
||||
Version: 1.0.0
|
||||
Release: 1%{?dist}
|
||||
Summary: Tool for managing Corsair LCDs via Python
|
||||
|
||||
License: MIT
|
||||
URL: https://github.com/shutdown4life/corsair_lcd_tool_v2
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
BuildArch: noarch
|
||||
BuildRequires: python3-devel
|
||||
Requires: python3
|
||||
Requires: python3-numpy
|
||||
Requires: python3-opencv
|
||||
Requires: python3-PyQt6
|
||||
Requires: python3-PyYAML
|
||||
Requires: python3-pyusb
|
||||
|
||||
%description
|
||||
A Python-based tool to manage Corsair LCD screens. This package includes an installer script and a setup script that runs automatically upon installation.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
# No build step is required for plain Python and shell scripts
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
mkdir -p %{buildroot}/usr/share/%{name}
|
||||
cp -a install.sh corsair_lcd_tool.py %{buildroot}/usr/share/%{name}/
|
||||
chmod +x %{buildroot}/usr/share/%{name}/install.sh
|
||||
chmod +x %{buildroot}/usr/share/%{name}/corsair_lcd_tool.py
|
||||
cp corsair-lcd-tool.png %{buildroot}/usr/share/%{name}/corsair-lcd-tool.png
|
||||
|
||||
mkdir -p %{buildroot}/usr/share/applications
|
||||
cp corsair_lcd_tool.desktop %{buildroot}/usr/share/applications/
|
||||
|
||||
mkdir -p %{buildroot}/usr/bin
|
||||
ln -sr %{buildroot}/usr/share/%{name}/install.sh %{buildroot}/usr/bin/%{name}-install
|
||||
ln -sr %{buildroot}/usr/share/%{name}/corsair_lcd_tool.py %{buildroot}/usr/bin/corsair-lcd-tool
|
||||
|
||||
mkdir -p %{buildroot}/usr/share/icons/hicolor/48x48/apps
|
||||
cp corsair-lcd-tool.png %{buildroot}/usr/share/icons/hicolor/48x48/apps/corsair-lcd-tool.png
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
%doc README.md
|
||||
/usr/share/%{name}/install.sh
|
||||
/usr/share/%{name}/corsair_lcd_tool.py
|
||||
/usr/share/%{name}/corsair-lcd-tool.png
|
||||
/usr/bin/%{name}-install
|
||||
/usr/bin/corsair-lcd-tool
|
||||
/usr/share/applications/corsair_lcd_tool.desktop
|
||||
/usr/share/icons/hicolor/48x48/apps/corsair-lcd-tool.png
|
||||
|
||||
%post
|
||||
echo "Running install.sh to set up udev rules..." > /tmp/corsair_lcd_tool_post.log
|
||||
/bin/bash /usr/share/%{name}/install.sh >> /tmp/corsair_lcd_tool_post.log 2>&1 || echo "install.sh failed" >> /tmp/corsair_lcd_tool_post.log
|
||||
|
||||
%changelog
|
||||
* Thu Jun 19 2025 ShUtDoWn discord @shutdown4life - 1.0.0-1
|
||||
- Initial RPM release with automatic post-install script
|
||||
Reference in New Issue
Block a user