我经常发现自己同时打开了多个文件窗口。然后我必须查看每个窗口才能找到我需要的内容。文件窗口是允许您浏览目录和文件的窗口。
是否有一个操作系统或 GNOME 设置、应用程序或脚本可以自动关闭旧的/空闲的文件窗口?
我可以右键单击并关闭所有文件窗口,但我的目标是自动关闭旧文件窗口,同时保留较新的文件窗口。
答案1
听了 FedKad 的评论后,我能够创建一个 Python 脚本,在 N 秒后关闭 Nautilus 窗口。现在我的桌面可以自行清理,也就是说,旧的和大量的 Nautilus 窗口都会自动关闭。
这对我适用于 Ubuntu 22.04。
下面是我的 python 脚本,以及有关如何配置 cron 每 N 秒自动运行此 python 脚本的一些注释。
#!/usr/bin/env python3
import subprocess
import os
import re
import datetime
import json
# Sources:
# https://askubuntu.com/questions/860212/close-nautilus-window-automatically-after-drive-is-removed
# https://stackoverflow.com/questions/32483997/get-current-date-time-and-compare-with-other-date
# https://stackoverflow.com/questions/25325882/python-time-difference-in-if-statements
# https://stackoverflow.com/a/72069726/13003478
# https://superuser.com/questions/190801/linux-wmctrl-cannot-open-display-when-session-initiated-via-sshscreen
# Instructions
# ##############################################################################
# 1) Adjust variable_n_allowed_life_of_window_in_seconds to your liking and save the file
# 2) Use cron to configure this script to run every M seconds
# Expected result:
# After every M seconds, any window older than variable_n_allowed_life_of_window_in_seconds
# should be closed. The exception is if the window is actively being used, e.g. the window is
# above all other windows or is displayed vertically on the side.
# Instructions to configure with cron
# ##############################################################################
# 1) Run this script 1 time and determine what the DISPLAY and XAUTHORITY variables are. Comment or remove when no longer needed.
# print(os.environ.get("DISPLAY"))
# print(os.environ.get("XAUTHORITY"))
# 2) In cron, you can configure the python script as follows:
# */1 * * * * export DISPLAY=:1 && export XAUTHORITY\=/run/user/1000/gdm/Xauthority && python3 /home/apricot/Applications/auto_close_old_nautilus_windows.py >>/home/apricot/Applications/script.log 2>>/home/apricot/Applications/script.log
# @reboot export DISPLAY=:1 && export XAUTHORITY\=/run/user/1000/gdm/Xauthority && python3 /home/apricot/Applications/auto_close_old_nautilus_windows.py >>/home/apricot/Applications/script.log 2>>/home/apricot/Applications/script.log
# The line above is configured to run my python script every 1 minute. You can change to 5 minutes with: */5 * * * *
# If the DISPLAY and XAUTHORITY are not properly set, you will get this error.
# Cannot open display.
# Traceback (most recent call last):
# File "/home/usera/Applications/auto_close_old_nautilus_windows.py", line 55, in <module>
# wlist1 = [l.strip() for l in get(["wmctrl", "-lp"]).splitlines() if nautpid in l]
# AttributeError: 'NoneType' object has no attribute 'splitlines'
# Variables
# ##############################################################################
# Any window older than variable_n_allowed_life_of_window_in_seconds will be closed
variable_n_allowed_life_of_window_in_seconds = 300 # 5 minutes (5 min. * 60 sec. = 300 sec.)
location_to_store_json = '/home/apricot/Applications/20221028_auto_close_old_nautilus_windows/'
name_of_json_file = 'nautilus_windows_recently_opened.json'
# Main Logic
# ##############################################################################
os.chdir(location_to_store_json)
def get(cmd):
try:
return subprocess.check_output(cmd).decode('utf-8').strip()
except subprocess.CalledProcessError:
pass
def decide_to_keep_this_window(unique_identifier):
# Get the output of this: xprop -id 0x03030e9a | grep "_NET_WM_STATE(ATOM)"
arguments_a = ['xprop', '-id', unique_identifier]
output_a = get(arguments_a)
# If the window is currently being looked at, e.g. the state is _NET_WM_STATE_MAXIMIZED_VERT,
# do not close the window. Keep the window opened.
# _NET_WM_STATE_MODAL, ATOM
# _NET_WM_STATE_STICKY, ATOM
# _NET_WM_STATE_MAXIMIZED_VERT, ATOM # Keep the window
# _NET_WM_STATE_MAXIMIZED_HORZ, ATOM # Keep the window
# _NET_WM_STATE_SHADED, ATOM
# _NET_WM_STATE_SKIP_TASKBAR, ATOM
# _NET_WM_STATE_SKIP_PAGER, ATOM
# _NET_WM_STATE_HIDDEN, ATOM
# _NET_WM_STATE_FULLSCREEN, ATOM # Keep the window
# _NET_WM_STATE_ABOVE, ATOM # Keep the window
# _NET_WM_STATE_BELOW, ATOM
# _NET_WM_STATE_DEMANDS_ATTENTION, ATOM
# Per the source below, .match only works from the start, so you need to add '^.*' to find a match
# Source: https://stackoverflow.com/a/17680674/13003478
pattern = '^.*(_NET_WM_STATE_MAXIMIZED_VERT|_NET_WM_STATE_MAXIMIZED_HORZ|_NET_WM_STATE_FULLSCREEN|_NET_WM_STATE_ABOVE)'
pattern_b = '^.*_NET_WM_STATE_HIDDEN'
keep_window = False
if output_a is not None:
if re.match(pattern, output_a, re.IGNORECASE):
keep_window = True
if re.match(pattern_b, output_a, re.IGNORECASE):
keep_window = False
return keep_window
nautpid = get(['pgrep', 'nautilus'])
connected1 = [item_b for item_b in get('lsblk').splitlines() if 'media' in item_b]
wlist1 = []
if nautpid is not None:
wlist1 = [item_b.strip() for item_b in get(['wmctrl', '-lp']).splitlines() if nautpid in item_b]
# Read in the JSON if it exists
current_windows = []
if os.path.exists(name_of_json_file) is True:
with open(name_of_json_file) as json_file:
current_windows = json.load(json_file)
previous_list_of_unique_identifiers = []
for item_a in current_windows:
previous_list_of_unique_identifiers.append(item_a['unique_identifier'])
# For any new nautilus windows, store the unique identifier and the creation time
for item_a in wlist1:
date_and_time_window_detected = str(datetime.datetime.now())
date_and_time_window_detected = datetime.datetime.strptime(date_and_time_window_detected, '%Y-%m-%d %H:%M:%S.%f')
new_string = re.sub(r'\s+', ' ', item_a)
entries_a = new_string.split(' ')
# Only add new windows to the list
if (entries_a[0] in previous_list_of_unique_identifiers) is False:
current_windows.append({
'unique_identifier': entries_a[0],
'pid': entries_a[2],
'creation_time': str(date_and_time_window_detected),
'windows_was_terminated': False
})
# If the window is being actively used, reset its creation date and avoid appearing too old.
for i, item_a in enumerate(current_windows):
window_is_active = decide_to_keep_this_window(item_a['unique_identifier'])
if window_is_active is True:
date_and_time_window_detected = str(datetime.datetime.now())
date_and_time_window_detected = datetime.datetime.strptime(date_and_time_window_detected, '%Y-%m-%d %H:%M:%S.%f')
current_windows[i]['creation_time'] = str(date_and_time_window_detected)
# For windows that are too old, close the window
list_of_processes_to_close = []
for i, item_a in enumerate(current_windows):
time_when_created = item_a['creation_time']
time_when_created_date_object = datetime.datetime.strptime(time_when_created, '%Y-%m-%d %H:%M:%S.%f')
current_time_date_object = datetime.datetime.now()
total = current_time_date_object - time_when_created_date_object
if total.seconds > variable_n_allowed_life_of_window_in_seconds:
list_of_processes_to_close.append(item_a['unique_identifier'])
arguments_a = ['wmctrl', '-ic', item_a['unique_identifier']]
subprocess.Popen(arguments_a)
current_windows[i]['windows_was_terminated'] = True
# Keep only the non-terminated windows
filtered = filter(lambda item_a: item_a['windows_was_terminated'] is False, current_windows)
current_windows = list(filtered)
# Dump the information of the windows to a JSON file
with open(name_of_json_file, 'w') as convert_file:
convert_file.write(json.dumps(current_windows))