├── .gitignore
├── LICENSE
├── README.md
├── envycontrol.py
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Victor Bayas
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EnvyControl
2 |
3 | EnvyControl is a program aimed to provide an easy way to switch GPU modes on Nvidia Optimus systems (i.e laptops with Intel + Nvidia or AMD + Nvidia configurations) under Linux.
4 |
5 | ### License
6 |
7 | Envycontrol is licensed under the MIT license which is a permissive, free software license (see LICENSE).
8 |
9 | ### Compatible distros
10 |
11 | EnvyControl should work on any distribution of Linux, see [tested distros](https://github.com/geminis3/envycontrol/wiki/Frequently-Asked-Questions#tested-distros).
12 |
13 | **If you're using Ubuntu please [read this](https://github.com/geminis3/envycontrol/wiki/Frequently-Asked-Questions#a-note-for-ubuntu-users).**
14 |
15 | ### Supported display managers
16 |
17 | - GDM
18 | - SDDM
19 | - LightDM
20 |
21 | If your display manager isn't currently supported by EnvyControl you might have to [manually configure it](https://github.com/geminis3/envycontrol/wiki/Frequently-Asked-Questions#what-to-do-if-my-display-manager-is-not-supported).
22 |
23 | ### A note for SDDM users
24 |
25 | If `/usr/share/sddm/scripts/Xsetup` file is missing on your system please run `sudo envycontrol --reset_sddm`.
26 |
27 | ### Supported graphics modes
28 |
29 | - integrated
30 | - hybrid
31 | - nvidia (X.org only)
32 |
33 | Read a detailed explanation [here](https://github.com/geminis3/envycontrol/wiki/Frequently-Asked-Questions#graphics-modes-explained).
34 |
35 | ## Get EnvyControl
36 |
37 | ### Arch Linux and its derivatives
38 |
39 | Install the [envycontrol](https://aur.archlinux.org/packages/envycontrol/) package from the AUR manually or by using an AUR helper:
40 |
41 | ```
42 | # with Paru
43 | paru -S envycontrol
44 |
45 | # with Yay
46 | yay -S envycontrol
47 |
48 | # with Pamac (Manjaro)
49 | pamac install envycontrol
50 | ```
51 |
52 | Now you can run `sudo envycontrol -s ` to switch graphics modes.
53 |
54 | ### Other distros
55 |
56 | - Clone this repository with `git clone https://github.com/geminis3/envycontrol.git` or download the latest tarball from the releases page.
57 | - Run `sudo python envycontrol.py -s ` from the root of the repository to switch to a different graphics mode.
58 |
59 | You can also install EnvyControl globally as a pip package:
60 |
61 | - From the root of the cloned repository run `sudo pip install .`
62 | - Now you can run `sudo envycontrol -s ` from any directory to switch graphics modes.
63 |
64 | ## Usage
65 |
66 | ```
67 | usage: envycontrol.py [-h] [-v] [-s MODE] [-q] [--dm DISPLAY_MANAGER] [--reset_sddm]
68 |
69 | options:
70 | -h, --help show this help message and exit
71 | -v, --version show this program's version number and exit
72 | -s MODE, --switch MODE
73 | switch the graphics mode, supported modes: integrated, hybrid, nvidia
74 | -q, --query query the current graphics mode set by EnvyControl
75 | --dm DISPLAY_MANAGER Manually specify your Display Manager. This is required only for systems without systemd. Supported DMs: gdm, sddm, lightdm
76 | --reset_sddm restore original SDDM Xsetup file
77 | ```
78 |
79 | ### Examples
80 |
81 | Set current graphics mode to `integrated` (power off the Nvidia dGPU):
82 |
83 | ```
84 | sudo envycontrol -s integrated
85 | ```
86 |
87 | Set current graphics mode to `nvidia` (automatic display manager setup)
88 |
89 | ```
90 | sudo envycontrol -s nvidia
91 | ```
92 |
93 | Set current graphics mode to `nvidia` and setup `SDDM` display manager
94 |
95 | ```
96 | sudo envycontrol -s nvidia --dm sddm
97 | ```
98 |
99 | Query the current graphics mode:
100 |
101 | ```
102 | envycontrol --query
103 | ```
104 |
105 | ### Gnome Extension
106 |
107 | The [GPU profile selector](https://github.com/LorenzoMorelli/GPU_profile_selector) extension provides a simple way to switch between graphics modes in a few clicks, you can get it from [here](https://extensions.gnome.org/extension/5009/gpu-profile-selector/).
108 |
109 | PD: Just make sure to have EnvyControl installed globally ;)
110 |
111 | 
112 |
113 | ## New in 2.0
114 |
115 | The following options can now be enabled when switching graphics mode:
116 |
117 | ### hybrid
118 |
119 | - RTD3 power management (for Turing and newer GPUs)
120 |
121 | ### nvidia
122 |
123 | - ForceCompositionPipeline (fixes tearing on external screens wired to the Nvidia GPU)
124 | - Coolbits (allows overclocking on supported GPUs)
125 |
126 | ## Frequently Asked Questions
127 |
128 | [See here](https://github.com/geminis3/envycontrol/wiki/Frequently-Asked-Questions).
129 |
130 | Also read [fixes for some common problems](https://github.com/DaVikingMan/EnvyControl/wiki/Fixes-for-some-common-problems)
131 |
132 | ## What to do if you have found a bug
133 |
134 | Feel free to open an issue, don't forget to provide some basic info.
135 |
136 | - Linux distribution
137 | - Linux kernel version and type
138 | - Desktop Environment or Window Manager as well as your Display Manager
139 | - Nvidia driver version
140 | - EnvyControl version
141 |
--------------------------------------------------------------------------------
/envycontrol.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import argparse
3 | import sys
4 | import os
5 | import re
6 | import subprocess
7 |
8 | VERSION = '2.1.1'
9 |
10 | BLACKLIST_PATH = '/etc/modprobe.d/blacklist-nvidia.conf'
11 |
12 | BLACKLIST_CONTENT = '''# Automatically generated by EnvyControl
13 |
14 | blacklist nouveau
15 | blacklist nvidia
16 | blacklist nvidia_drm
17 | blacklist nvidia_uvm
18 | blacklist nvidia_modeset
19 | alias nouveau off
20 | alias nvidia off
21 | alias nvidia_drm off
22 | alias nvidia_uvm off
23 | alias nvidia_modeset off
24 | '''
25 |
26 | UDEV_INTEGRATED_PATH = '/lib/udev/rules.d/50-remove-nvidia.rules'
27 |
28 | UDEV_INTEGRATED = '''# Automatically generated by EnvyControl
29 |
30 | # Remove NVIDIA USB xHCI Host Controller devices, if present
31 | ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{power/control}="auto", ATTR{remove}="1"
32 |
33 | # Remove NVIDIA USB Type-C UCSI devices, if present
34 | ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{power/control}="auto", ATTR{remove}="1"
35 |
36 | # Remove NVIDIA Audio devices, if present
37 | ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{power/control}="auto", ATTR{remove}="1"
38 |
39 | # Remove NVIDIA VGA/3D controller devices
40 | ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x03[0-9]*", ATTR{power/control}="auto", ATTR{remove}="1"
41 | '''
42 |
43 | UDEV_PM_PATH = '/lib/udev/rules.d/80-nvidia-pm.rules'
44 |
45 | UDEV_PM = '''# Automatically generated by EnvyControl
46 |
47 | # Remove NVIDIA USB xHCI Host Controller devices, if present
48 | ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1"
49 |
50 | # Remove NVIDIA USB Type-C UCSI devices, if present
51 | ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1"
52 |
53 | # Remove NVIDIA Audio devices, if present
54 | ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1"
55 |
56 | # Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind
57 | ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
58 | ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"
59 |
60 | # Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind
61 | ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
62 | ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"
63 | '''
64 |
65 | XORG_PATH = '/etc/X11/xorg.conf'
66 |
67 | XORG_INTEL = '''# Automatically generated by EnvyControl
68 |
69 | Section "ServerLayout"
70 | Identifier "layout"
71 | Screen 0 "nvidia"
72 | Inactive "intel"
73 | EndSection
74 |
75 | Section "Device"
76 | Identifier "nvidia"
77 | Driver "nvidia"
78 | BusID "PCI:{}"
79 | EndSection
80 |
81 | Section "Screen"
82 | Identifier "nvidia"
83 | Device "nvidia"
84 | Option "AllowEmptyInitialConfiguration"
85 | EndSection
86 |
87 | Section "Device"
88 | Identifier "intel"
89 | Driver "modesetting"
90 | EndSection
91 |
92 | Section "Screen"
93 | Identifier "intel"
94 | Device "intel"
95 | EndSection
96 | '''
97 |
98 | XORG_AMD = '''# Automatically generated by EnvyControl
99 |
100 | Section "ServerLayout"
101 | Identifier "layout"
102 | Screen 0 "nvidia"
103 | Inactive "amdgpu"
104 | EndSection
105 |
106 | Section "Device"
107 | Identifier "nvidia"
108 | Driver "nvidia"
109 | BusID "PCI:{}"
110 | EndSection
111 |
112 | Section "Screen"
113 | Identifier "nvidia"
114 | Device "nvidia"
115 | Option "AllowEmptyInitialConfiguration"
116 | EndSection
117 |
118 | Section "Device"
119 | Identifier "amdgpu"
120 | Driver "amdgpu"
121 | EndSection
122 |
123 | Section "Screen"
124 | Identifier "amd"
125 | Device "amdgpu"
126 | EndSection
127 | '''
128 |
129 | EXTRA_PATH = '/etc/X11/xorg.conf.d/10-nvidia.conf'
130 |
131 | EXTRA_CONTENT = '''# Automatically generated by EnvyControl
132 |
133 | Section "OutputClass"
134 | Identifier "nvidia"
135 | MatchDriver "nvidia-drm"
136 | Driver "nvidia"
137 | '''
138 |
139 | TEARING_FIX = f' Option "ForceCompositionPipeline" "true"\n'
140 |
141 | COOLBITS = f' Option "Coolbits" "28"\n'
142 |
143 | MODESET_PATH = '/etc/modprobe.d/nvidia.conf'
144 |
145 | MODESET_CONTENT = '''# Automatically generated by EnvyControl
146 |
147 | options nvidia-drm modeset=1
148 | '''
149 |
150 | MODESET_PM = '''# Automatically generated by EnvyControl
151 |
152 | options nvidia-drm modeset=1
153 | options nvidia "NVreg_DynamicPowerManagement=0x02"
154 | '''
155 |
156 | SDDM_XSETUP_PATH = '/usr/share/sddm/scripts/Xsetup'
157 |
158 | SDDM_XSETUP_CONTENT = '''#!/bin/sh
159 | # Xsetup - run as root before the login dialog appears
160 |
161 | '''
162 |
163 | LIGHTDM_SCRIPT_PATH = '/etc/lightdm/nvidia.sh'
164 |
165 | LIGHTDM_CONFIG_PATH = '/etc/lightdm/lightdm.conf.d/20-nvidia.conf'
166 |
167 | LIGHTDM_CONFIG_CONTENT = '''# Automatically generated by EnvyControl
168 |
169 | [Seat:*]
170 | display-setup-script=/etc/lightdm/nvidia.sh
171 | '''
172 |
173 | NVIDIA_XRANDR_SCRIPT = '''#!/bin/sh
174 | # Automatically generated by EnvyControl
175 |
176 | xrandr --setprovideroutputsource "{}" NVIDIA-0
177 | xrandr --auto
178 | '''
179 |
180 | def _switcher(mode, display_manager = ''):
181 | _check_root()
182 | yes = ('yes', 'y', 'ye')
183 | if mode == 'integrated':
184 | _cleanup()
185 | try:
186 | # Blacklist all nouveau and Nvidia modules
187 | _create_file(BLACKLIST_PATH, BLACKLIST_CONTENT)
188 | # Power off the Nvidia GPU with udev rules
189 | _create_file(UDEV_INTEGRATED_PATH, UDEV_INTEGRATED)
190 | except Exception as e:
191 | print(f'Error: {e}')
192 | sys.exit(1)
193 | _rebuild_initramfs()
194 | elif mode == 'hybrid':
195 | _cleanup()
196 | # Enable modeset for Nvidia driver
197 | choice = input('Enable RTD3 Power Management? (y/N): ').lower()
198 | if choice in yes:
199 | _create_file(UDEV_PM_PATH, UDEV_PM)
200 | _create_file(MODESET_PATH, MODESET_PM)
201 | else:
202 | _create_file(MODESET_PATH, MODESET_CONTENT)
203 | _rebuild_initramfs()
204 | elif mode == 'nvidia':
205 | _cleanup()
206 | # detect if Intel or AMD iGPU
207 | igpu_vendor = _get_igpu_vendor()
208 | # get the Nvidia dGPU PCI bus
209 | pci_bus = _get_pci_bus()
210 | # get display manager
211 | if display_manager == '':
212 | display_manager = _check_display_manager()
213 | try:
214 | # Create X.org config
215 | if igpu_vendor == 'intel':
216 | _create_file(XORG_PATH, XORG_INTEL.format(pci_bus))
217 | _setup_display_manager(display_manager)
218 | elif igpu_vendor == 'amd':
219 | _create_file(XORG_PATH, XORG_AMD.format(pci_bus))
220 | _setup_display_manager(display_manager)
221 | # Enable modeset for Nvidia driver
222 | _create_file(MODESET_PATH, MODESET_CONTENT)
223 | choice = input('Enable ForceCompositionPipeline? (y/N): ').lower()
224 | if choice in yes:
225 | enable_comp = True
226 | else:
227 | enable_comp = False
228 | choice = input('Enable Coolbits? (y/N): ').lower()
229 | if choice in yes:
230 | enable_coolbits = True
231 | else:
232 | enable_coolbits = False
233 | if enable_comp and enable_coolbits:
234 | _create_file(EXTRA_PATH,EXTRA_CONTENT+TEARING_FIX+COOLBITS+'EndSection')
235 | elif enable_comp:
236 | _create_file(EXTRA_PATH,EXTRA_CONTENT+TEARING_FIX+'EndSection')
237 | elif enable_coolbits:
238 | _create_file(EXTRA_PATH,EXTRA_CONTENT+COOLBITS+'EndSection')
239 | except Exception as e:
240 | print(f'Error: {e}')
241 | sys.exit(1)
242 | _rebuild_initramfs()
243 | else:
244 | print('Error: provided graphics mode is not valid')
245 | print('Supported graphics modes: integrated, nvidia, hybrid')
246 | sys.exit(1)
247 | print(f'Graphics mode set to: {mode}\nPlease reboot your computer for changes to apply!')
248 |
249 | def _cleanup():
250 | # Remove all files created by EnvyControl
251 | to_remove = (BLACKLIST_PATH,UDEV_INTEGRATED_PATH, UDEV_PM_PATH, XORG_PATH, EXTRA_PATH, '/etc/X11/xorg.conf.d/90-nvidia.conf', MODESET_PATH, LIGHTDM_SCRIPT_PATH, LIGHTDM_CONFIG_PATH)
252 | for file in to_remove:
253 | try:
254 | os.remove(file)
255 | except OSError as e:
256 | if e.errno != 2:
257 | print(f'Error: {e}')
258 | sys.exit(1)
259 | # restore Xsetup backup if found
260 | if os.path.exists(SDDM_XSETUP_PATH+'.bak'):
261 | with open(SDDM_XSETUP_PATH+'.bak', mode='r', encoding='utf-8') as f:
262 | _create_file(SDDM_XSETUP_PATH, f.read())
263 |
264 | def _get_igpu_vendor():
265 | pattern_intel = re.compile(r'(VGA).*(Intel)')
266 | pattern_amd = re.compile(r'(VGA).*(ATI|AMD|AMD\/ATI)')
267 | lspci = subprocess.run(['lspci'], stdout=subprocess.PIPE).stdout.decode('utf-8')
268 | if pattern_intel.findall(lspci):
269 | return 'intel'
270 | elif pattern_amd.findall(lspci):
271 | return 'amd'
272 | else:
273 | print('Error: could not find Intel or AMD iGPU')
274 | sys.exit(1)
275 |
276 | def _get_amd_igpu_name():
277 | pattern = re.compile(r'(name:).*(ATI*|AMD*|AMD\/ATI)*')
278 | xrandr = subprocess.run(['xrandr', '--listproviders'], capture_output=True, text=True).stdout
279 |
280 | if pattern.findall(xrandr):
281 | name = re.search(pattern, xrandr).group(0)[5:]
282 | else:
283 | name = "Error: could not find AMD iGPU"
284 | return name
285 |
286 | def _get_pci_bus():
287 | pattern = re.compile(
288 | r'([0-9a-f]{2}:[0-9a-z]{2}.[0-9]).*(VGA compatible controller: NVIDIA|3D controller: NVIDIA)')
289 | lspci = subprocess.run(['lspci'], stdout=subprocess.PIPE).stdout.decode('utf-8')
290 | try:
291 | # Need to return Bus ID in PCI:X:X:X format
292 | return ':'.join([str(int(element, 16)) for element in pattern.findall(lspci)[0][0].replace('.', ':').split(':')])
293 | except Exception:
294 | print(f'Error: switching directly from integrated to Nvidia mode is not supported\nTry switching to hybrid mode first!')
295 | sys.exit(1)
296 |
297 | def _check_display_manager():
298 | # automatically detect the current Display Manager
299 | # this depends on systemd
300 | pattern = re.compile(r'(\/usr\/bin\/|\/usr\/sbin\/)(.*)')
301 | try:
302 | with open('/etc/systemd/system/display-manager.service',mode='r', encoding='utf-8') as f:
303 | display_manager = pattern.findall(f.read())[0][1]
304 | except Exception:
305 | display_manager = ''
306 | print('Warning: automatic Display Manager detection is not available')
307 | finally:
308 | return display_manager
309 |
310 | def _setup_display_manager(display_manager):
311 | # setup the Xrandr script if necessary
312 | # get igpu vendor to use if needed
313 | igpu_vendor = _get_igpu_vendor()
314 | if display_manager == 'sddm':
315 | # backup Xsetup
316 | if os.path.exists(SDDM_XSETUP_PATH):
317 | with open(SDDM_XSETUP_PATH, mode='r', encoding='utf-8') as f:
318 | _create_file(SDDM_XSETUP_PATH+'.bak', f.read())
319 | if igpu_vendor == "intel":
320 | _create_file(SDDM_XSETUP_PATH, NVIDIA_XRANDR_SCRIPT.format("modesetting"))
321 | else:
322 | amd_name = _get_amd_igpu_name()
323 | _create_file(SDDM_XSETUP_PATH, NVIDIA_XRANDR_SCRIPT.format(amd_name))
324 | subprocess.run(['chmod','+x',SDDM_XSETUP_PATH], stdout=subprocess.DEVNULL)
325 | elif display_manager == 'lightdm':
326 | if igpu_vendor == "amd":
327 | amd_name = _get_amd_igpu_name()
328 | _create_file(LIGHTDM_SCRIPT_PATH, NVIDIA_XRANDR_SCRIPT.format(amd_name))
329 | else:
330 | _create_file(LIGHTDM_SCRIPT_PATH, NVIDIA_XRANDR_SCRIPT.format("modesetting"))
331 | subprocess.run(['chmod','+x',LIGHTDM_SCRIPT_PATH], stdout=subprocess.DEVNULL)
332 | # create config
333 | if not os.path.exists(os.path.dirname(LIGHTDM_CONFIG_PATH)):
334 | _create_file(LIGHTDM_CONFIG_PATH, LIGHTDM_CONFIG_CONTENT)
335 | elif display_manager not in ['', 'gdm', 'gdm3']:
336 | print('Error: provided Display Manager is not valid')
337 | print('Supported Display Managers: gdm, sddm, lightdm')
338 | sys.exit(1)
339 |
340 | def _rebuild_initramfs():
341 | # Debian and Ubuntu derivatives
342 | if os.path.exists('/etc/debian_version'):
343 | command = ['update-initramfs', '-u', '-k', 'all']
344 | # RHEL and SUSE derivatives
345 | elif os.path.exists('/etc/redhat-release') or os.path.exists('/usr/bin/zypper'):
346 | command = ['dracut', '--force', '--regenerate-all']
347 | else:
348 | command = []
349 | if len(command) != 0:
350 | print('Rebuilding initramfs...')
351 | p = subprocess.run(command, stdout=subprocess.DEVNULL)
352 | if p.returncode == 0:
353 | print('Successfully rebuilt initramfs!')
354 | else:
355 | print('Error: an error ocurred rebuilding the initramfs')
356 |
357 | def _check_root():
358 | if not os.geteuid() == 0:
359 | print('Error: this operation requires root privileges')
360 | sys.exit(1)
361 |
362 | def _create_file(path, content):
363 | # Create parent folders if needed
364 | if not os.path.exists(os.path.dirname(path)):
365 | os.makedirs(os.path.dirname(path))
366 | with open(path, mode='w', encoding='utf-8') as f:
367 | f.write(content)
368 |
369 | def _query_mode():
370 | if os.path.exists(BLACKLIST_PATH) and os.path.exists(UDEV_INTEGRATED_PATH):
371 | mode = 'integrated'
372 | elif os.path.exists(XORG_PATH) and os.path.exists(MODESET_PATH):
373 | mode = 'nvidia'
374 | else:
375 | mode = 'hybrid'
376 | print(f'Current graphics mode is: {mode}')
377 |
378 | def _reset_sddm():
379 | _check_root()
380 | try:
381 | _create_file(SDDM_XSETUP_PATH, SDDM_XSETUP_CONTENT)
382 | subprocess.run(['chmod', '+x', SDDM_XSETUP_PATH], stdout=subprocess.DEVNULL)
383 | except Exception as e:
384 | print(f'Error: {e}')
385 | sys.exit(1)
386 | print('Operation completed successfully!')
387 |
388 | def _print_version():
389 | print(f'EnvyControl version {VERSION}')
390 |
391 | def main():
392 | # argument parsing
393 | parser = argparse.ArgumentParser()
394 | parser.add_argument('-v', '--version', action='store_true', help='show this program\'s version number and exit')
395 | parser.add_argument('-s', '--switch', type=str, metavar='MODE', action='store', help='switch the graphics mode, supported modes: integrated, hybrid, nvidia')
396 | parser.add_argument('-q', '--query', action='store_true', help='query the current graphics mode set by EnvyControl')
397 | parser.add_argument('--dm', type=str, metavar='DISPLAY_MANAGER', action='store',
398 | help='Manually specify your Display Manager. This is required only for systems without systemd. Supported DMs: gdm, sddm, lightdm')
399 | parser.add_argument('--reset_sddm', action='store_true', help='restore original SDDM Xsetup file')
400 | # print help if no arg is provided
401 | if len(sys.argv) == 1:
402 | parser.print_help()
403 | sys.exit(1)
404 | args = parser.parse_args()
405 | if args.query:
406 | _query_mode()
407 | elif args.version:
408 | _print_version()
409 | elif args.reset_sddm:
410 | _reset_sddm()
411 | elif args.switch:
412 | if args.dm and args.switch == 'nvidia':
413 | _switcher(args.switch, args.dm)
414 | else:
415 | _switcher(args.switch)
416 | elif args.dm and not args.switch:
417 | print('Error: this option is intended to be used with --switch nvidia')
418 | print('Example: sudo envycontrol --switch nvidia --dm sddm')
419 | sys.exit(1)
420 |
421 | if __name__ == '__main__':
422 | main()
423 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from setuptools import setup
3 | import envycontrol
4 |
5 |
6 | setup(
7 | name='envycontrol',
8 | version=envycontrol.VERSION,
9 | description='Easy GPU switching for Nvidia Optimus laptops under Linux',
10 | url='http://github.com/geminis3/EnvyControl',
11 | author='Victor Bayas',
12 | author_email='victorsbayas@gmail.com',
13 | license='MIT',
14 | py_modules=['envycontrol'],
15 | entry_points={
16 | 'console_scripts': [
17 | 'envycontrol=envycontrol:main',
18 | ],
19 | },
20 | keywords=['nvidia', 'optimus', 'prime', 'gpu', 'linux'],
21 | classifiers=[
22 | 'Development Status :: 4 - Beta',
23 | 'License :: OSI Approved :: MIT License',
24 | 'Programming Language :: Python :: 3',
25 | 'Operating System :: POSIX :: Linux'
26 | ],
27 | )
--------------------------------------------------------------------------------