Bir programı başlangıçta nasıl küçültebilirim?


19

Sadece Telegram'ın çalışmasını istiyorum ve onu başlangıç ​​uygulamalarına ekledim. Mesele şu ki, minimize edilmesi gerekiyor. Herhangi bir komut var mı?


Telegram'ı başlatma komutu nedir ve uygulama başladıktan hemen sonra pencere adı nedir?
Jacob Vlijm

Kullandığım komut sadece uygulamanın yolu ve pencere adı Telegram Desktop
Hossein Soltanloo

Merhaba Hossien, pencere başlığı yerine pid'i kullanmayı tercih etmeniz durumunda cevabımı düzenledi.
Jacob Vlijm

@JacobVlijm Teşekkürler! Büyük ölçüde verimli ve kullanışlı! Ancak ilk yöntem değişken pencere adı durumlarında sorunsuz çalışır. Aferin!
Hossein Soltanloo

1
@SumeetDeshmukh inanılmaz güzel ve cömert bir insansın. Gerçekten mi!
Jacob Vlijm

Yanıtlar:


29

Bir uygulamayı en aza indirgeme

Bir uygulamayı simge durumuna küçültülmüş olarak başlatmak iki komut alır:

  • uygulamayı başlatmak
  • penceresini küçült

Bu nedenle, komut veya komut dosyasının "akıllı" olması gerekir; ikinci komut, uygulama penceresinin görünmesini beklemelidir.

Bir uygulamayı başlatmak için genel çözüm en aza indirilmiştir

Aşağıdaki komut dosyası bunu yapar ve bir uygulamayı en aza indirgemek için genel bir çözüm olarak kullanılabilir. Sadece sözdiziminde çalıştırın:

<script> <command_to_run_the_application> <window_name>

Senaryo

#!/usr/bin/env python3
import subprocess
import sys
import time

subprocess.Popen(["/bin/bash", "-c", sys.argv[1]])
windowname = sys.argv[2]

def read_wlist(w_name):
    try:
        l = subprocess.check_output(["wmctrl", "-l"]).decode("utf-8").splitlines()
        return [w.split()[0] for w in l if w_name in w][0]
    except (IndexError, subprocess.CalledProcessError):
        return None

t = 0
while t < 30:
    window = read_wlist(windowname)
    time.sleep(0.1)
    if window != None:
        subprocess.Popen(["xdotool", "windowminimize", window])
        break
    time.sleep(1)
    t += 1

Nasıl kullanılır

Senaryo hem ihtiyacı wmctrlve xdotool:

sudo apt-get install wmctrl xdotool

Sonra:

  1. Komut dosyasını boş bir dosyaya kopyalayın, startup_minimizd.py
  2. Komut dosyasını (örn.) Komutuyla test geditedin:

    python3 /path/to/startup_minimizd.py gedit gedit
    
  3. Her şey yolunda giderse, komutu (uygulamanız için) Startup Applications

açıklama

  • Komut dosyası uygulamayı başlatır ve ilk argüman olarak verdiğiniz komutu çalıştırır
  • Daha sonra komut dosyası wmctrl, ikinci argümanınızdan sonra adlandırılan pencereler için pencere listesini (yardımıyla ) denetler .
  • Pencere görünürse, xdotool pencerenin herhangi bir nedenle görünmemesi durumunda sonsuz bir döngüyü önlemek için komut dosyası, pencerenin görünmesi için 30 saniyelik bir zaman sınırı uygular.

Not

Komut dosyasını, komut dosyasının dışındaki bağımsız değişkenlerle çalıştırdığınız için, komut dosyasını aynı anda birden çok uygulama için kullanabileceğinizi belirtmenize gerek yoktur.


DÜZENLE

pencereyi pidesinden tanıma

Pencere başlığı emin veya değişken değilse veya pencerenin adında ad çakışması riski varsa, kullanmak piddaha güvenilir bir yöntemdir.

Aşağıdaki komut dosyası, hem wmctrl -lpve hem de çıktısında olduğu gibi uygulamanın pid'inin kullanımına dayanmaktadır ps -ef.

Kurulum hemen hemen aynıdır, ancak bu sürümde pencere başlığı gerekli değildir, bu nedenle çalıştırma komutu şöyledir:

python3 /path/to/startup_minimizd.py <command_to_run_application>

Sadece ilk senaryosu gibi, ihtiyacı hem wmctrlvexdotool

Senaryo

#!/usr/bin/env python3
import subprocess
import sys
import time

command = sys.argv[1]
command_check = command.split("/")[-1]

subprocess.Popen(["/bin/bash", "-c", command])

t = 1
while t < 30:
    try:
        w_list = [l.split() for l in subprocess.check_output(["wmctrl", "-lp"]).decode("utf-8").splitlines()]
        proc = subprocess.check_output(["pgrep", "-f", command_check]).decode("utf-8").strip().split()
        match = sum([[l[0] for l in w_list if p in l] for p in proc], [])
        subprocess.Popen(["xdotool", "windowminimize", match[0]])
        break
    except (IndexError, subprocess.CalledProcessError):
        pass
    t += 1
    time.sleep(1)

İkinci kod hakkında not

Genel olarak ikinci sürüm daha güvenilir olmakla birlikte, uygulamanın bir sarıcı komut dosyası tarafından başlatılması durumunda, komutun pid'i nihayet çağrılan uygulamadan farklı olacaktır.

Bu gibi durumlarda, ilk komut dosyasını kullanmanızı öneririm.



EDIT2 Steam için komut dosyasının belirli bir sürümü

Bir yorumda istendiği gibi, bir versiyonun altında, STEAM'ı başlatmak için özel olarak yapılmıştır.

Neden Steam için belirli bir sürüm?

Bu çıkıyor Steam"normal" bir uygulamadan oldukça farklı davranır:

  • Anlaşılan bir pid Steamçalıştırmıyor , ancak (testimde) sekizden az değil !
  • Steambaşlangıçta en az iki pencere (bir sıçrama benzeri pencere) ile çalışır, ancak bazen ek bir mesaj penceresi görünür.
  • Windows of Steam pid 0, senaryoda olduğu gibi bir sorundur.
  • Ana pencere oluşturulduktan sonra, pencere bir saniye kadar sonra ikinci kez kaldırılır, böylece tek bir küçültme gerçekleşmez.

Bu istisnai davranış Steam, betiğin aşağıda eklenen özel bir sürümünü ister. Senaryo başlar Steamve 12 saniye boyunca, WM_CLASSminimize olup olmadıklarını kontrol ederek ilgili tüm yeni pencerelere göz atar. Değilse, komut dosyası bunların olmasını sağlar.

Orijinal komut dosyası gibi, bunun da yüklenmesi wmctrlve xdotoolyüklenmesi gerekir.

Senaryo

#!/usr/bin/env python3
import subprocess
import time

command = "steam"
subprocess.Popen(["/bin/bash", "-c", command])

def get(cmd):
    return subprocess.check_output(cmd).decode("utf-8").strip()

t = 0

while t < 12:
    try:
        w_list = [l.split()[0] for l in get(["wmctrl", "-l"]).splitlines()]
        for w in w_list:
            data = get(["xprop", "-id", w])
            if all(["Steam" in data, not "_NET_WM_STATE_HIDDEN" in data]):
                subprocess.Popen(["xdotool", "windowminimize", w])
    except (IndexError, subprocess.CalledProcessError):
        pass

    t += 1
    time.sleep(1)

Kullanmak için

  • Boş bir dosyaya kopyalayın, kaydedin runsteam_minimized.py
  • Komut ile çalıştırın:

    python3 /path/to/runsteam_minimized.py
    

vay, harika bir tane! Gerçi except:sadece Yok dönmek için yakalamak olmaz . Muhtemelen daha iyi başarısız olmasına izin verin, böylece neyin başarısız olduğunu göreceksiniz; Aksi takdirde, her türlü farklı nedenden dolayı kırılabilir ve reklamsız olarak geçer.
fedorqui

1
@fedorqui İyi bir, iki istisna olabilir: subprocess.CalledProcesError ( bir hata sonucu wmctrl) ve IndexError(normal istisna) bir dakika içinde düzenlenir :).
Bahsettiğiniz

@HosseinSoltanloo Senaryoyu çalıştırdığınız komut tam olarak nedir?
Jacob Vlijm

@JacobVlijm Komut dosyası iyi çalışıyor ancak düzeltebileceğiniz başka bir sorun daha var. Okunmamış mesajım olduğunda ve uygulamayı açtığımda, okunmamış iki mesaj olduğu için pencere adı "Telegram (2)" gibi bir şeye dönüşür ve bu şekilde komut dosyası addaki değişiklikten dolayı çalışmaz.
Hossein Soltanloo

2
@JDHolland Eminim düzeltilebilir. Önümüzdeki birkaç gün içinde bir yere bakacağız :)
Jacob Vlijm

3

Kullanıcı72216 ve Sergey tarafından soruna genel çözümler olarak verilen komut dosyalarına sahip olmak iyidir, ancak bazen en aza indirmek istediğiniz uygulamanın zaten istediğiniz şeyi yapacak bir anahtarı vardır.

İlgili başlangıç ​​programı komut dizelerine sahip birkaç örnek:

  • Telegram (sürüm 0.7.10'dan beri) -startintrayseçeneği vardır:<path-to-Telegram>/Telegram -startintray
  • Steam şu -silentseçeneğe sahiptir:/usr/bin/steam %U -silent
  • İletim --minimizedseçeneği vardır:/usr/bin/transmission-gtk --minimized

Unity'de bu uygulamalar, başlatıcıdaki simgeler yerine üst menü çubuğunda simgeler olarak simge durumuna küçültülür, ancak uygulamayı kullanmaya başladığınızda normal başlatma simgesi görünmeye devam eder. Diğer uygulamalar farklı davranabilir.


1

Jacob'un senaryolarını aldım ve daha evrensel bir senaryo oluşturmak için biraz değiştirdim.

#!/usr/bin/python

import os
import subprocess
import sys
import time
import signal

WAIT_TIME = 10


def check_exist(name):
    return subprocess.Popen("which "+name,
                            shell=True,
                            stdout=subprocess.PIPE
                            ).stdout.read().rstrip("-n")


def killpid(pidlist):
    for pid in pidlist:
        args = ["xdotool",
                "search",
                "--any",
                "--pid",
                pid,
                "--name",
                "notarealprogramname",
                "windowunmap",
                "--sync",
                "%@"]
        subprocess.Popen(args)


def killname(name):
    args = ["xdotool",
            "search",
            "--any",
            "--name",
            "--class",
            "--classname",
            name,
            "windowunmap",
            "--sync",
            "%@"]
    subprocess.Popen(args)


sys.argv.pop(0)

if check_exist(sys.argv[0]) == "":
    sys.exit(1)
if check_exist("xdotool") == "":
    sys.stderr.write("xdotool is not installed\n")
    sys.exit(1)
if check_exist("wmctrl") == "":
    sys.stderr.write("wmctrl is not installed\n")
    sys.exit(1)

try:
    prog = subprocess.Popen(sys.argv, preexec_fn=os.setsid)
except OSError, e:
    sys.exit(1)

time.sleep(WAIT_TIME)
idlist = subprocess.Popen("pgrep -g " + str(prog.pid),
                          shell=True,
                          stdout=subprocess.PIPE
                          ).stdout.read().splitlines()

ps1 = os.fork()
if ps1 > 0:
    ps2 = os.fork()

if ps1 == 0:  # Child 1
    os.setpgid(os.getpid(), os.getpid())
    killpid(idlist)
    sys.exit(0)
elif ps2 == 0:  # Child 2
    killname(os.path.basename(sys.argv[0]))
    sys.exit(0)
elif ps1 > 0 and ps2 > 0:  # Parent
    time.sleep(WAIT_TIME)
    os.killpg(os.getpgid(int(ps1)), signal.SIGTERM)
    os.kill(ps2, signal.SIGTERM)
    os.waitpid(ps1, 0)
    os.waitpid(ps2, 0)
    sys.exit(0)
else:
    exit(1)

Temel farklar:

  • Program, işlem için grup kimliğini (GID) ayarlar. Böylece, tüm çocuk süreçleri ve pencereleri kolayca bulunabilir
  • xdotool - while döngüsü yerine sync seçeneği kullanılır
  • Komut dosyası, programa argüman aktarmaya izin verir

WAIT_TIME, programın alt süreçlerini çatallamasına izin verecek kadar büyük ayarlanmalıdır. Bilgisayarımda buhar gibi büyük programlar için yeterli. Gerekirse artırın.

İlave

xdotoolseçeneği windowunmapbazı uygulamalarda ve tepsi programlarında (örneğin linux nane tepsisi) korkak çalışabilir, bu nedenle bu istisnalar için komut dosyasının alternatif bir sürümü.

#!/usr/bin/python

import os
import subprocess
import sys
import time
import signal

WAIT_TIME = 10


def check_exist(name):
    return subprocess.Popen("which "+name,
                            shell=True,
                            stdout=subprocess.PIPE
                            ).stdout.read().rstrip("-n")


def killpid(pidlist):
    for pid in pidlist:
        args = ["xdotool",
                "search",
                "--sync",
                "--pid",
                pid]
        for i in subprocess.Popen(args,
                                  stdout=subprocess.PIPE).\
                stdout.read().splitlines():
            if i != "":
                subprocess.Popen("wmctrl -i -c " +
                                 hex(int(i)), shell=True)


def killname(name):
    args = ["xdotool",
            "search",
            "--sync",
            "--any",
            "--name",
            "--class",
            "--classname",
            name]
    for i in subprocess.Popen(args,
                              preexec_fn=os.setsid,
                              stdout=subprocess.PIPE)\
            .stdout.read().splitlines():
        if i != "":
            subprocess.Popen("wmctrl -i -c " + hex(int(i)),
                             shell=True)


sys.argv.pop(0)

if check_exist(sys.argv[0]) == "":
    sys.exit(1)
if check_exist("xdotool") == "":
    sys.stderr.write("xdotool is not installed\n")
    sys.exit(1)
if check_exist("wmctrl") == "":
    sys.stderr.write("wmctrl is not installed\n")
    sys.exit(1)


try:
    prog = subprocess.Popen(sys.argv, preexec_fn=os.setsid)
except OSError, e:
    sys.exit(1)

time.sleep(WAIT_TIME)
idlist = subprocess.Popen("pgrep -g " + str(prog.pid),
                          shell=True,
                          stdout=subprocess.PIPE
                          ).stdout.read().splitlines()

ps1 = os.fork()
if ps1 > 0:
    ps2 = os.fork()

if ps1 == 0:  # Child 1
    os.setpgid(os.getpid(), os.getpid())
    killpid(idlist)
    sys.exit(0)
elif ps2 == 0:  # Child 2
    killname(os.path.basename(sys.argv[0]))
    sys.exit(0)
elif ps1 > 0 and ps2 > 0:  # Parent
    time.sleep(WAIT_TIME)
    os.killpg(os.getpgid(int(ps1)), signal.SIGTERM)
    os.kill(ps2, signal.SIGTERM)
    os.waitpid(ps1, 0)
    os.waitpid(ps2, 0)
    sys.exit(0)
else:
    exit(1)

İlk senaryonuzu denedim. Bu işe yaramadı ya da yeterince hızlı bir şekilde en aza indirmedi. Olarak kaydettim startminimized. Sonra koştum startminimized gnome-calendar. Takvim açık ve yayınlanmaya devam ediyor mu?
Khurshid Alam

1
Değişkeni artırmayı deneyebilirsiniz WAIT_TIME. Zayıf bilgisayarlar için 40 saniyelik gecikme kullanıyorum. Ayrıca, uygulamayı en aza indirmek için farklı bir komut kullandığı için ikinci komut dosyasını deneyebilirsiniz.
Sergey

1

Program tepsiye kapatılıyorsa, aslında başlangıçta program penceresini simge durumuna küçültmek yerine kapatmak isteyebilirsiniz. Böyle bir programa örnek olarak Viber verilebilir. Bu durumda aşağıdaki komut dosyası kullanılabilir start_closed.sh:

#!/bin/bash

# Check that there is only one input argument
if [[ $# -gt 1 ]]; then
echo "Usage: $0 <program-to-start>"
exit 1
fi

$1 &                               # Start program passed in first argument
pid=$!                             # Get PID of last started program
xdotool search --sync --pid $pid | # Wait for window with PID to appear...
xargs wmctrl -i -c                 # ...and close it

Kullanımı: <path-to-script> <program-to-start>


1
xdotoolWayland ile kurulumlarda düzgün çalışmayacağını belirtmek isteyebilirsiniz .
Videonauth

0

Sadece sörf yapıyordum ve bu soruya rastladım, bu yüzden işletim sisteminizin ne olduğunu merak ediyordum? Bana gelince ben UBUNTU BUDGIE 18.04 LTS kullanıyorum bu yüzden bu işletim sisteminde çok basit.

Sadece menüye gidin

Menüden Budgie Masaüstü Ayarlarına gidin

ve

Masaüstü Ayarından Otomatik Başlat'a gidin

Size "+" eklemenizden 2 seçenek sunar

1. Uygulama Ekle

2. Komut Ekle

Uygulama Ekle'yi seçerek tüm uygulamalar listelenir ve istediğiniz herhangi bir uygulamayı seçin ve bilgisayarınızı başlattığınızda başlar ve simge durumuna küçültülür.


0

Tepsiye kapalı programlara ihtiyacım vardı, küçültülmedi ve burada yayınlanan tüm komut dosyalarını denedim, çalışanlar, sadece bazı programlar için çalıştı, diğerleri için değil. Bu yüzden çok daha iyi çalışan bir kod yazdım (neredeyse pencerenin göründüğünü görmüyorsunuz, sadece tepsi simgesi, yerel görünüyor) ve denediğim tüm programlar için çalışıyor. Yakup'un esasına dayanıyor. Bu komut dosyasıyla, programa bağlı olarak bir argüman eklemeniz gerekebilir (aşağıya bakın), ancak her zaman benim için çok sayıda programla çalıştı, ayrıca buharla da çalışmalıdır.

Kullanımı:

  1. sudo apt-get install wmctrl xdotool
  2. Komut dosyasını startup_closed.pyyürütme izinleri olarak kaydedin ve çalıştırınpython3 ./startup_closed.py -c <command to open program>
  3. Program tepsisi simgesi gösterilmiyorsa veya pencere gösterilmiyorsa, şu bağımsız değişkenlerden birini eklemeniz gerekir: -splashveya -hidedeneme yanılma yoluyla. Örneğin: python3 ./startup_closed.py -hide -c teamviewerveyapython3 ./startup_closed.py -splash -c slack
  4. Daha fazla argüman var ama muhtemelen onlara ihtiyacınız yok. Ayrıca, yardımda argümanların tam olarak ne zaman ve neden gerekli olduğuna dair tam ayrıntılar vardır:./startup_closed.py --help

Senaryo:

#!/usr/bin/env python3
import subprocess
import sys
import time
import argparse
import random

parser = argparse.ArgumentParser(description='This script executes a command you specify and closes or hides the window/s that opens from it, leaving only the tray icon. Useful to "open closed to tray" a program. If the program does not have a tray icon then it just gets closed. There is no magic solution to achieve this that works for all the programs, so you may need to tweek a couple of arguments to make it work for your program, a couple of trial and error may be required with the arguments -splash and -hide, you probably will not need the others.')

parser.add_argument("-c", type=str, help="The command to open your program. This parameter is required.", required=True)
parser.add_argument("-splash", help="Does not close the first screen detected. Closes the second window detected. Use in programs that opens an independent splash screen. Otherwise the splash screen gets closed and the program cannot start.", action='store_true', default=False)
parser.add_argument("-hide", help="Hides instead of closing, for you is the same but some programs needs this for the tray icon to appear.", action='store_true', default=False)
parser.add_argument("-skip", type=int, default=0, help='Skips the ammount of windows specified. For example if you set -skip 2 then the first 2 windows that appear from the program will not be affected, use it in programs that opens multiple screens and not all must be closed. The -splash argument just increments by 1 this argument.', required=False)
parser.add_argument("-repeat", type=int, default=1, help='The amount of times the window will be closed or hidden. Default = 1. Use it for programs that opens multiple windows to be closed or hidden.', required=False)
parser.add_argument("-delay", type=float, default=10, help="Delay in seconds to wait before running the application, useful at boot to not choke the computer. Default = 10", required=False)
parser.add_argument("-speed", type=float, default=0.02, help="Delay in seconds to wait between closing attempts, multiple frequent attempts are required because the application may be still loading Default = 0.02", required=False)

args = parser.parse_args()

if args.delay > 0:
    finalWaitTime = random.randint(args.delay, args.delay * 2);
    print(str(args.delay) + " seconds of delay configured, will wait for: " + str(finalWaitTime))
    time.sleep(finalWaitTime)
    print("waiting finished, running the application command...")

command_check = args.c.split("/")[-1]
subprocess.Popen(["/bin/bash", "-c", args.c])

hasIndependentSplashScreen = args.splash
onlyHide = args.hide
skip = args.skip
repeatAmmount = args.repeat
speed = args.speed

actionsPerformed = 0
lastWindowId = 0

if hasIndependentSplashScreen:
    skip += 1

while True:
    try:
        w_list = [l.split() for l in subprocess.check_output(["wmctrl", "-lp"]).decode("utf-8").splitlines()]
        proc = subprocess.check_output(["pgrep", "-f", command_check]).decode("utf-8").strip().split()
        match = sum([[l[0] for l in w_list if p in l] for p in proc], [])
        if len(match) > 0:
            windowId = match[0]
            if windowId != lastWindowId:
                if skip > 0:
                    skip -= 1
                    print("skipped window: " + windowId)
                    lastWindowId = windowId
                else:
                    print("new window detected: " + windowId)
                    if onlyHide:
                        subprocess.Popen(["xdotool", "windowunmap", windowId])
                        print("window was hidden: " + windowId)
                    else:
                        subprocess.Popen(["xdotool", "key", windowId, "alt+F4"])
                        print("window was closed: " + windowId)

                    actionsPerformed += 1
                    lastWindowId = windowId

            if actionsPerformed == repeatAmmount:
                break

    except (IndexError, subprocess.CalledProcessError):
        break

    time.sleep(speed)

print("finished")

0

Sadece zarif bir çözümle geldim xdotoolve Telegram gibi "minimize edilmiş bir başlangıç" argümanı olmayan uygulamalar için oldukça kullanışlıdır .

Tek dezavantajı, çözümün her uygulama için manuel olarak hazırlanması gerektiğidir, ancak bunun bir sorun olmadığını varsayarsak (örneğin: belirli bir uygulamayı giriş yaptıktan sonra ekranınızı kirletmesine izin vermeden otomatik olarak başlatmak istiyorsanız) , bu çok daha basit ve kolaydır .

Gerçek Örnekler

## Starts Telegram and immediately closes it
xdotool search --sync --onlyvisible --name '^Telegram$' windowclose &
telegram-desktop &
## Starts WhatsApp and immediately closes it
xdotool search --sync --onlyvisible --name '(\([0-9]*\) ){0,1}(WhatsApp$|WhatsApp Web$)' windowclose &
whatsapp-nativefier &

Çözüm

İlk bakışta, 'PID veya sınıf sürecini eşleşmek için kullanmanın daha iyi olduğunu düşünebilirsiniz, ancak aynı PID için sıklıkla birden fazla sonuç alacağınız için aslında bu ters etki yaratır. Örnek olarak bir bildirim, bir systray simgesi veya başka bir "gizli" pencere bekleyen bir 0x0 penceresi gösterilebilir.

Çözüm, her zaman yalnızca bir benzersiz pencere döndüren bir xdotool komutu hazırlamaktır . --nameBununla birlikte yapılan her iki --all örneğimde de, birden fazla seçiciyi (örneğin: verilen bir sınıf adını + bir sınıf adını + bir ad regex ile eşleştirebilirsiniz) birleştirebilirsiniz . Genellikle iyi bir --nameregex hile yapar.

Koşullarınızı hazırladıktan sonra , parametre ve koşullarınızla bir searchxdotool örneği (kabuktan ayrılmış)--sync ve ardından takip edin windowclose. Daha sonra uygulamanızı çalıştırın:

xdotool search --sync [... myapp-match-conditions] windowclose &
my-app

xdotool search --helpTam olarak istediğiniz pencereyi hedefleyebilmek için ayarlayabileceğiniz tüm kombinasyon olanaklarına göz atın . Bazen zorlaşır ve birkaç koşulu birleştirmeniz gerekir, ancak bitirdiğinizde nadiren başarısız olur (bir güncelleme uygulamayı değiştirmediği ve uygulamanızı bozmadığı sürece).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.