Могу ли я иметь окно, показывающее небольшой предварительный просмотр другого рабочего пространства?


29

Можно ли отразить текущий раздел одной рабочей области так, чтобы он был виден в текущей рабочей области как окно, которое можно перемещать?

На днях на моем хосте Ubuntu 16.04 была запущена виртуальная машина Windows 10, на обновление которой ушло очень много времени. Я продолжал следить за его продвижением через Экспо ( Super+ S) на Ubuntu. Это заставило меня задуматься о том, что эта проблема, скорее всего, уже решена, поскольку такие инструменты, как simplescreenrecorder, можно настроить для записи только части экрана. Однако я не знаю подходящей терминологии для поиска в Google.

Я хотел бы видеть скриншот 300x150 ниже в форме плавающего окна (с обновлениями в реальном времени) в правом верхнем углу любого рабочего пространства, которое является текущим.

введите описание изображения здесь


1
@serg вот новый проект для вас
Rinzwind

@Rinzwind, вы должны ненавидеть Серга ... Мы (оба) смотрели на что-то подобное раньше, не удалось.
Джейкоб Влейм

1
На этот раз я даже наградил его: =) доберитесь до этого @JacobVlijm
Rinzwind

Было бы крутой функцией :) Это не поможет в случае с виртуальной машиной, но есть решение для терминальных приложений: использование Konsole. У него есть две полезные опции: «уведомлять об активности» и «уведомлять о тишине». Первый отправит вам уведомление, когда в терминале появится новая строка (полезно при использовании tail -F file | grep patternв журналах для предупреждения о некоторых событиях), второй отправит вам уведомление, когда прошло некоторое время с момента последней написанной строки (полезно для знать, когда сборка закончилась).
Кик

@Rinzwind Святое дерьмо, это сработает ...
Джейкоб Влейм

Ответы:


26

РЕДАКТИРОВАТЬ

(Новый ответ)

СДЕЛАННЫЙ.
Ответ ниже теперь доступен в отшлифованной форме, в качестве индикатора, в качестве ppa для Trusty, Xenial, Yakkety и Zesty:

sudo apt-add-repository ppa:vlijm/windowspy
sudo apt-get update
sudo apt-get install windowspy

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

введите описание изображения здесь

В то же время я нашел полезным следить за окном AU; посмотреть, есть ли сообщения :)


СТАРЫЙ ОТВЕТ

( первая вторая грубая концепция)

Иметь минимизированное представление окна в другом рабочем пространстве

К моему собственному (большому) удивлению, это может быть эффективно сделано, будь то с помощью обмана и обмана; иметь обновленное представление окна в другом рабочем пространстве. Не подходит для просмотра фильмов, безусловно, достаточно хорош, чтобы следить за окном в другом месте (пример: окно моей ТВ-карты):

Как это работает на практике

  1. С окном впереди, нажмите клавишу быстрого доступа:

    введите описание изображения здесь

    (окно свернется)

  2. Перейдите в другое рабочее пространство, снова нажмите клавишу быстрого вызова, появится небольшое представление окна, обновляемое каждые 4 секунды:

    введите описание изображения здесь

    Окно всегда отображается поверх других окон. Как таковое, окно имеет 300px (ширину), но может быть установлено на любой размер.

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

Сценарии

  1. Контрольный скрипт

    #!/usr/bin/env python3
    import subprocess
    import os
    import sys
    import time
    
    # paths
    imagepath = os.path.join(os.environ["HOME"], ".showcase")
    wfile = os.path.join(imagepath, "currentwindow")
    vpfile = os.path.join(imagepath, "last_vp")
    # setup path
    if not os.path.exists(imagepath):
        os.mkdir(imagepath)
    
    def get(command):
        try:
            return subprocess.check_output(command).decode("utf-8").strip()
        except subprocess.CalledProcessError:
            pass
    
    def get_vp():
        open(vpfile, "wt").write(get(["wmctrl", "-d"]).split()[5])
    
    def run(command):
        subprocess.Popen(command)
    
    def convert_tohex(widxd):
        return widxd[:2]+((10-len(widxd))*"0")+widxd[2:]
    
    def check_windowtype(wid):
        check = get(["xprop", "-id", wid])
        return not any([s in check for s in [
            "_NET_WM_WINDOW_TYPE_DOCK",
            "_NET_WM_WINDOW_TYPE_DESKTOP"]])
    
    def edit_winprops(wid, convert=True):
        run(["xdotool", "windowminimize", wid])
        if convert:
            widxd = convert_tohex(hex(int(wid)))
        else:
            widxd = wid
        run(["wmctrl", "-i", "-r", widxd, "-b", "add,sticky"])
        get_vp()
        open(os.path.join(imagepath, "currentwindow"), "wt").write(widxd)
    
    def initiate_min():
        # if not, minmize window, write the file
        wid = get(["xdotool", "getactivewindow"])
        if check_windowtype(wid):
            edit_winprops(wid)
        else:
            pidinfo = [l.split() for l in wlist.splitlines()]
            match = [l for l in pidinfo if all([
                get(["ps", "-p", l[2], "-o", "comm="]) == "VirtualBox",
                not "Manager" in l])]
            if match:
                edit_winprops(match[0][0], convert=False)
    
    # windowlist
    wlist = get(["wmctrl", "-lp"])
    
    if "Window preview" in wlist:
        # kill the miniwindow
        pid = get(["pgrep", "-f", "showmin"])
        run(["kill", pid])
        window = open(wfile).read().strip()
        viewport = open(vpfile).read().strip()
        run(["wmctrl", "-o", viewport])
        time.sleep(0.3)
        run(["wmctrl", "-i", "-r", window, "-b", "remove,sticky"])
        run(["wmctrl", "-ia", window])
        os.remove(wfile)
    
    else:
        # check if windowfile exists
        wfileexists = os.path.exists(wfile)
        if wfileexists:
            # if file exists, try to run miniwindow
            window = open(wfile).read().strip()
            if window in wlist:
                # if the window exists, run!
                run(["showmin", window])
            else:
                # if not, minmize window, write the file
                initiate_min()
        else:
            # if not, minmize window, write the file
            initiate_min()
  2. Представление окна

    #!/usr/bin/env python3
    import gi
    gi.require_version('Gtk', '3.0')
    from gi.repository import Gtk, GObject
    from PIL import Image
    import os
    import subprocess
    import time
    from threading import Thread
    import sys
    
    wid = sys.argv[1]
    xsize = 300
    
    imagepath = os.path.join(os.environ["HOME"], ".showcase")
    if not os.path.exists(imagepath):
        os.mkdir(imagepath)
    img_in = os.path.join(imagepath, "image.png")
    resized = os.path.join(imagepath, "resized.png")
    
    def get_img():
        subprocess.Popen([
            "import", "-window", wid, "-resize", str(xsize),  resized
            ])
    
    get_img()
    
    class Splash(Gtk.Window):
    
        def __init__(self):
            Gtk.Window.__init__(self, title="Window preview")
            maingrid = Gtk.Grid()
            self.add(maingrid)
            self.image = Gtk.Image()
            # set the path to the image below
            self.resized = resized
            self.image.set_from_file(self.resized)
            maingrid.attach(self.image, 0, 0, 1, 1)
            maingrid.set_border_width(3)
            self.update = Thread(target=self.update_preview)
            self.update.setDaemon(True)
            self.update.start()
    
        def update_preview(self):
            while True:
                get_img()
                time.sleep(3)
                GObject.idle_add(
                    self.image.set_from_file, self.resized,
                    priority=GObject.PRIORITY_DEFAULT
                    )
    
    def miniwindow():
        window = Splash()
        window.set_decorated(False)
        window.set_resizable(False)
        window.set_keep_above(True)
        window.set_wmclass("ShowCase", "showcase")
        window.connect("destroy", Gtk.main_quit)
        GObject.threads_init()
        window.show_all()
        window.move(70, 50)
        Gtk.main()
    
    miniwindow()

Как использовать

  1. Установить python3-pil, xdotoolиwmctrl

    sudo apt-get install xdotool wmctrl python3-pil
    
  2. Создайте, если он еще не существует, каталог ~/bin.

  3. Скопируйте скрипт 1, он управляет скриптом, как (точно) showcase_control(без расширения) ~/bin, и сделает его исполняемым .
  4. Скопируйте сценарий 2, сценарий мини-окна, как (точно) showmin(без расширения) ~/binи сделайте его исполняемым .
  5. Выйдите из системы, войдите в нее и добавьте следующую команду в ярлык на ваш выбор:

    showcase_control
    

    Выберите: «Системные настройки»> «Клавиатура»> «Ярлыки»> «Пользовательские ярлыки». Нажмите «+» и добавьте команду:

    showcase_control
    

    и это должно работать!

    • Нажмите клавишу один раз, чтобы получить текущее окно
    • переместитесь в другое рабочее пространство, где вы хотите мини-окно
    • Нажмите еще раз, чтобы показать мини-окно
    • Нажмите еще раз, чтобы вернуться к исходному рабочему пространству, (автоматически) свернуть оригинальное окно и закрыть мини-одно.

Недостатки?

  • Настройка, как это происходит в настоящее время, добавляет некоторую работу для вашего процессора. Однако в моей (очень) старой системе это добавляет (в среднем) ок. 4-5% , я считаю, что я не заметил в какой - либо образом.

    Обновление: Оказывается, importможно изменить размер изображения за один шаг, вместе с извлечением окна изображения. Это означает значительное снижение нагрузки на процессор. В то же время время обновления короче (теперь 3 секунды), но при меньших «затратах».

объяснение

  • Моей отправной точкой было то, как OP упомянул, что хочет использовать опцию, чтобы следить за окном в другом рабочем пространстве, ожидая, когда что-то закончится.
  • Хотя буквально иметь точную (мини) копию окна в другом рабочем пространстве кажется невозможным, мы можем создать изображение существующего окна с помощью команды import-com, как только у нас будет идентификатор окна. Хотя и то, и другое работает на свернутых окнах или окнах без фокуса, тем не менее есть одна проблема: окно должно находиться в текущей рабочей области. .
  • Хитрость заключается в том, чтобы временно (пока используется мини-окно) сделать окно «липким» (быть практически доступным во всех рабочих пространствах) с wmctrl , но одновременно свернуть его.
  • Поскольку все выполняется автоматически, разница фактически не равна нулю, поскольку возврат к исходному окну просмотра, «снятие липкости» с исходного окна и его минимизация, выполняется автоматически.

Короче:

  1. Нажатие на ярлык один раз: целевое окно становится липким, но свернуто
  2. Повторное нажатие (предположительно в другом рабочем пространстве): в верхнем левом углу появляется небольшая мини-версия окна, обновляемая раз в четыре секунды.
  3. Повторное нажатие: мини-окно закрывается, рабочий стол перемещается в начальную рабочую область окна, окно восстанавливается незаметно и не свернуто.

Специально для VirtualBox

Когда окно VBox находится впереди, оказывается, что горячие клавиши Ubuntu отключены (!), Поэтому скрипт управления нужно запускать другим способом. Ниже несколько кратких.

Опция 1

Я отредактировал контрольный скрипт. Теперь только в случае VirtualBox:

  • Нажмите в любом месте на рабочем столе, затем нажмите клавишу быстрого доступа. После этого просто используйте клавишу быстрого доступа, чтобы показать окно и выйти.

    Объяснение: Сценарий управления был создан для выхода, если окно было типа «рабочий стол», так как вы не хотели бы свернуть рабочий стол. Теперь сценарий сначала ищет возможные существующие окна VirtualBox, если целью является текущее активное окно рабочего стола.

Вариант 2

  • Скопируйте значок ниже (щелкните правой кнопкой мыши -> сохранить как), сохраните его как minwinicon.png

    введите описание изображения здесь

  • Скопируйте строки ниже в пустой файл, сохраните его как minwin.desktopв ~/.local/share/applications:

    [Desktop Entry]
    Type=Application
    Name=Window Spy
    Exec=showcase_control 
    Icon=/path/to/minwinicon.png
    StartupNotify=false
    

    Вам нужно выйти и снова войти, чтобы программа запуска "нашла" локальный ~/binпуть!
    Перетащите значок на панель запуска, чтобы использовать его.

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


Итак, старый добрый importможет сделать это, а скриншот гнома - нет. Очень, очень интересно Я брезгливый, в чем именно разница между тем, как они работают
Сергей Колодяжный

@ Серг, да, я был очень удивлен, подумав, что это невозможно сделать с помощью только кухонных инструментов :)
Джейкоб Влийм,

1
@ThatGuy работает над этим :)
Джейкоб Влейм

1
@jymbob Спасибо за комментарий! Они не сомневаются в системе, но вопрос в том, доступны ли они извне. Если разработчики не предоставляют опцию cli или API каким-либо образом, взломать код будет задачей совершенно другого порядка. Я хотел бы иметь возможность, хотя.
Джейкоб Влейм

1
@JacobVlijm Честная точка зрения. Возможно, больше информации здесь stackoverflow.com/questions/18595951/… но намного выше моего уровня компетенции!
Jymbob

1

Open Broadcaster - это то, что кажется излишним, но полностью работает для этой цели . В списке «Источники» нажмите «плюс», выберите «Захват окна», затем следуйте инструкциям, чтобы выбрать интересующее вас окно. Нет смысла нажимать на запись; просто используйте предварительный просмотр. Он доступен для почти любого ОС , с инструкциями для Ubuntu здесь , который я скопированные ниже.

sudo apt-get install ffmpeg
sudo add-apt-repository ppa:obsproject/obs-studio
sudo apt-get update
sudo apt-get install obs-studio

Если вам это нравится, вы можете перейти в меню «Вид» и скрыть все элементы пользовательского интерфейса.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.