Рейтинг:2

Как отслеживать события приложений, такие как открытие, закрытие, свертывание в Ubuntu?

флаг cc

Я хотел бы знать, возможно ли отслеживать события открытия/закрытия/минимизации приложений в Ubuntu. Моя первоначальная цель — отслеживать, сколько раз я открываю телеграмму для проверки сообщений.

PS: я использую Ubuntu 20.04LTS (X11).

Jacob Vlijm avatar
флаг by
Это зависит от того, находитесь ли вы на X (не Wayland)?
Sasha R Adler avatar
флаг cc
@JacobVlijm Да, X11, а не Wayland.
Jacob Vlijm avatar
флаг by
Вполне возможно. Нужен сценарий и некоторые пояснения. Я напишу крошечный пример, если никто не будет быстрее меня :), но не уверен, что сегодня.
Рейтинг:3
флаг by

Просто для удовольствия, так как вы находитесь на X

Используя python (или кучу других языков) Мы можем использовать сигналы от Wnck.Экран и Wnck.Window следить за созданием и/или изменением состояния окон. Это включает в себя максимизацию и минимизацию окон.

Это именно то, что делает приведенный ниже скрипт. Впоследствии он поддерживает файл журнала, который будет обновляться, если вы создаете, сворачиваете или разворачиваете окно определенного WM_CLASS (и, следовательно, приложения). Вы можете найти WMCLASS целевого приложения, открыв терминал, введите xprop WM_CLASS + Возвращаться, затем нажмите на тему окна («telegramdesktop» для телеграммы или что-то в этом роде).

Имейте в виду, что я заставил скрипт сбрасывать файл журнала после каждого сеанса (регистрации), иначе файл журнала со временем стал бы огромным.

Что в лог-файле?

Лог-файл (~/.windowlog.txt) будет хранить записи о создании, закрытии и изменении состояния окон данного WM_Class. Каждый раз, когда окно разворачивается, счетчик добавляет единицу, поэтому в конце дня вы можете увидеть активность:

найдено окно: Telegram
состояние изменено: визуальное(1)
состояние изменено: свернуто
состояние изменено: визуальное(2)
состояние изменено: свернуто
состояние изменено: визуальное(3)
окно закрыто: Telegram
новое окно: Telegram
состояние изменено: визуальное(4)
состояние изменено: свернуто
состояние изменено: визуальное(5)

Запись что сценарий написан с расчетом на одно окно для приложения, как в вашем вопросе. Чтобы вести более подробную запись за окно, обработка данных потребует более сложного кодирования.

Сценарий

#!/usr/bin/env python3
импорт ги
gi.require_version("Gtk", "3.0")
gi.require_version("Wnck", "3.0")
из gi.repository импортировать Gtk, Wnck
импорт ОС
импорт системы


класс WatchWindow:

    защита __init__(я, wmclass):
        self.visual = Нет
        self.count_visual = 0
        self.wnck_scr = Wnck.Screen.get_default()
        self.wmclass = wmкласс
        self.logpath = os.environ["HOME"] + "/.windowlog.txt"
        self.run_watching()
        Gtk.main()

    def write_to_log (я, новая строка):
        с open(self.logpath, "a+") в качестве файла журнала:
            logfile.write(новая строка + "\n")

    def readable_state (самостоятельно, свернуто):
        п = ""
        если не свернуто:
            self.count_visual = self.count_visual + 1
            n = "(" + str(self.count_visual) + ")"
        return ["свернутый", "визуальный"][[True, False].index(свернутый)] + n
    
    def logstate (я, окно, * аргументы):
        old_state = self.visual
        новое_состояние = окно.is_minimized()
        # регистрируем только в том случае, если свернутое состояние действительно изменилось
        если старое_состояние != новое_состояние:
            self.visual = новое_состояние
            message = "состояние изменено: " + self.readable_state(self.visual) # журнал
            распечатать (сообщение)
            self.write_to_log(сообщение)

    def log_new (я, экран, окно):
        если window.get_class_group_name().lower() == self.wmclass:
            message = "новое окно:" + window.get_name() # запись нового
            распечатать (сообщение)
            self.write_to_log(сообщение)
            self.watch_window (окно)
            self.logstate(окно)

    def log_closed (я, экран, окно):
        если window.get_class_group_name().lower() == self.wmclass:
            имя = окно.get_name()
            self.visual = Нет
            print("окно закрыто:", name) # журнал закрыт
    
    def watch_window(self, window, firstcall=False):
        если window.get_class_group_name().lower() == self.wmclass:
            если первый вызов:
                message = "найдено окно:" + window.get_name()
                print(message) # зарегистрируйте пожалуйста
                self.write_to_log("Найдено окно: " + window.get_name())
                self.logstate(окно)
            window.connect("state_changed", self.logstate)

    определение run_watching (я):
        пытаться:
            os.remove(self.logpath)
        кроме FileNotFoundError:
            проходят
        self.wnck_scr.force_update()
        для w в self.wnck_scr.get_windows():
            self.watch_window(w, Истина)
        self.wnck_scr.connect("окно открыто", self.log_new)
        self.wnck_scr.connect("окно закрыто", self.log_closed)

аргументы = sys.argv[1:]
если не аргументы:
    print("Недостаточно аргументов! Нам нужен wm_class для наблюдения...")
еще:
    Окно наблюдения (аргументы [0])

Настраивать

  1. Скопируйте скрипт в пустой файл, сохраните его как виндоггер.py и сделать его исполняемым

  2. Тест-запустите его в окне терминала, запустите его с WM_CLASS в качестве аргумента (я полагаю телеграмдесктоп), так:

    /путь/к/windowlogger telegramdesktop
    
  3. Посмотрите, в порядке ли вывод в терминале, см. Внутри лог-файла ~/.windowlog.txt если все работает как надо.

  4. Добавьте его в свои приложения для запуска, если хотите.

NB

Возможно, вам нужно добавить одну или несколько библиотек, проверьте вывод терминала.

Окно регистрации активно?

Из комментария я понимаю, что вы считаете окно «используемым» (только), если это активное окно.
В этом случае мы можем значительно упростить сценарий, так как мы Только нужно посмотреть на active_window_changed сигнал. Если мы также регистрируем использование времени (за использование / общее время использования), вы можете получить четкое представление о том, сколько времени вы потратили, глядя на (любое) окно телеграммы. Затем файл журнала выглядит так:

start_time: woensdag, 06 октября 2021, 11:32:53
окно активировано (1)
окно скрыто или закрыто, было активно: 0:00:04 всего: 0:00:04
окно активировано (2)
окно скрыто или закрыто, было активно: 0:00:06 всего: 0:00:10
окно активировано (3)
окно скрыто или закрыто, было активно: 0:00:12 всего: 0:00:22
окно активировано (4)
окно скрыто или закрыто, было активно: 0:00:07 всего: 0:00:29

Скрипт в таком случае:

#!/usr/bin/env python3
импорт ги
gi.require_version("Gtk", "3.0")
gi.require_version("Wnck", "3.0")
из gi.repository импортировать Gtk, Wnck
импорт ОС
импорт системы
время импорта
импорт даты и времени

класс WatchWindow:

    def __init__(я, wmclass):
        self.visual = Ложь
        self.count_visual = 1
        self.wnck_scr = Wnck.Screen.get_default()
        self.wmclass = wmкласс
        self.logpath = os.environ["HOME"] + "/.windowlog.txt"
        self.total_time = 0
        self.last_time = время.время ()
        self.run_watching()
        Gtk.main()

    def write_to_log (я, новая строка):
        с open(self.logpath, "a+") в качестве файла журнала:
            logfile.write(новая строка + "\n")

    def get_readable_time (самостоятельно, истекло):
        вернуть строку (datetime.timedelta (секунды = прошедшее))

    def log_active (я, * аргументы):
        пытаться:
            # active_class может быть None, например. при запуске
            active_class = self.wnck_scr.get_active_window().get_class_group_name()
        кроме AttributeError:
            актив_класс = ""
        newvisual = active_class.lower() == self.wmclass.lower()
        старый визуал = self.visual
        текущее время = время.время()
        если новое визуальное != старое визуальное:
            если новый визуал:
                self.last_time = текущее время
                message = "окно активировано (" + str(self.count_visual) + ")"
                self.count_visual = self.count_visual + 1
            еще:
                winactive_time = текущее время - self.last_time
                self.last_time = текущее время
                self.total_time = self.total_time + winactive_time
                message = "окно скрыто или закрыто, было активно: " + \
                          self.get_readable_time (раунд (winactive_time)) +\
                          "\t" + "всего:" +\
                          self.get_readable_time (раунд (self.total_time))
            self.write_to_log(сообщение)
        self.visual = новый визуал

    определение run_watching (я):
        пытаться:
            os.remove(self.logpath)
        кроме FileNotFoundError:
            проходят
        time_stamp_message = "start_time: " + time.strftime(" %A, %B %d %Y, %H:%M:%S")
        self.write_to_log (time_stamp_message)
        self.wnck_scr.force_update()
        self.wnck_scr.connect ("активное окно изменено", self.log_active)
        self.log_active()

аргументы = sys.argv[1:]
если не аргументы:
    print("Недостаточно аргументов! Нам нужен wm_class для наблюдения...")
еще:
    Окно наблюдения (аргументы [0])

Настройка такая же.

vanadium avatar
флаг cn
Теперь нам это нужно и на Wayland, чтобы мы могли переключиться ;)
Jacob Vlijm avatar
флаг by
@vanadium Хе-хе, верно.
Sasha R Adler avatar
флаг cc
Спасибо, это то, что я хочу. Кроме того, я добавил сигнал «active-window-changed», чтобы отслеживать, переключается ли активное окно обратно на телеграмму.
Sasha R Adler avatar
флаг cc
@JacobVlijm Конечно, это будет здорово.
Jacob Vlijm avatar
флаг by
@SashaRAdler готово.
Sasha R Adler avatar
флаг cc
@JacobVlijm Круто, спасибо.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.