Luncurkan aplikasi hanya jika belum terbuka

16

Saya ingin meniru penggunaan Alfred di Mac OS X, di mana jika Anda mencoba membuka aplikasi setelah mencarinya, itu hanya akan membuka jendela baru jika program belum berjalan, jika tidak maka akan menetapkan fokus pada sedang menjalankan instance dari aplikasi itu. Apakah ada cara untuk mengubah perilaku default peluncur untuk memeriksa ini sebelum membuka jendela baru?

Dan Jenson
sumber
Juga @pidge Untuk melakukan ini tidak akan sulit, tetapi itu juga akan mempengaruhi perilaku klik kanan "terbuka dengan". Saya kira itu adalah efek samping yang tidak dapat diterima.
Jacob Vlijm
1
Saya pikir Anda harus dapat membuat skrip yang dapat memeriksa apakah proses tertentu sudah berjalan dan memutuskan untuk meluncurkan proses baru atau memberikan fokus ke jendela yang ada. Sayangnya, saya belum begitu baik dalam scripting ... Tapi @JacobVlijm dikenal sebagai seorang pria dengan skrip untuk setiap tujuan;) Anda harus mengganti semua peluncur asli dengan skrip masing-masing. Tidak yakin apakah Anda ingin / dapat melakukan itu - saya tidak akan ...
Byte Commander
2
Jika Anda menggunakan rute skrip, Anda dapat menggunakan skrip ini sebagai titik awal. Saya menulisnya untuk LXDE / Openbox pada awalnya, tetapi seharusnya juga berfungsi di Unity. Informasi lebih lanjut tentang skrip dan penggunaannya di sini .
Glutanimate
1
@ByteCommander persis itulah yang ada dalam pikiran saya. Anda bahkan dapat mengganti skrip perintah dalam .desktopfile. Jika Anda mengganti perintah dalam .desktopfile, klik kanan terbuka dengan opsi rusak.
Jacob Vlijm
1
Untuk Lingkungan Desktop mana?
j0h

Jawaban:

6

Perbarui 7 April: Versi yang berbeda ditambahkan dan ditemukan Albert, lihat pembaruan dan Bonus di bawah !!!

Mengenai fungsionalitas dasbor : Anda telah bertanya " Apakah ada untuk mengubah perilaku default peluncur untuk memeriksa ini sebelum membuka jendela baru ". Jawaban dasarnya adalah, tidak, sebagai pengguna biasa Anda tidak memiliki cara untuk menambahkan perilaku itu ke tanda hubung. Namun, jika akan ada pengembang ruang lingkup persatuan yang bersedia menerapkannya, Anda dapat mendekati mereka atau mengembangkannya sendiri jika Anda memiliki tekad dan mau belajar. Keterampilan pengkodean saya sangat sederhana, oleh karena itu saya menggunakan skrip shell dan grafis front-end yang tersedia untuk skrip sebagai solusi.

Informasi terkait

Pos asli:

Saya telah menulis sebuah skrip yang menggunakan dialog zenity dan wmctrl untuk mencapai apa yang Anda minta. Perhatikan bahwa ini adalah skrip grafis, artinya skrip hanya akan berfungsi dengan windows, di GUI, dan tidak akan berfungsi jika Anda mencoba meluncurkan sesuatu dalam tty. Selain itu, dari apa yang saya mengerti, Alfred melakukan hal yang persis sama. Anda dapat membuat pintasan desktop atau pintasan peluncur untuknya, seperti dijelaskan di sini dan di sini .

Naskah:

#!/bin/bash
# Author: Serg Kolo
# Description: A launcher script that checks whether
#       or not a window of a particular program already exists
#       If a window of such program is open, bring it to focus
#       Otherwise - launch a new window
#       Written for /ubuntu//q/440142/295286
# Date: April 6 , 2015
#


MYPROG=$( zenity --entry --title='MY LAUNCHER' --text='Type the name of application to run' )
sleep 0.5
wmctrl -lx | awk '{print $3}' | grep -i "$MYPROG"

if [ $? -eq 0 ]; then
    sleep 1         
    wmctrl -xa $MYPROG
   #as an alternative try the line bellow
   #wmctrl -a $MYPROG
    exit 1
else 
    $MYPROG &
    exit 0
fi

Catatan samping: dalam versi sebelumnya, skrip menggunakan echo $ ?, untuk menguji apakah ekspresi sebelumnya berhasil keluar. Sesuai saran muru (dari hasil edit), saya mengubah kodenya ke versi yang lebih ringkas, jadi saya sarankan Anda melihat pada versi sebelumnya dan saat ini.

Juga, sebelumnya wmctrl -a $MYPROGtidak bekerja dengan pengujian google-chrome atau chromium-browser; untuk beberapa alasan bodoh beberapa program memiliki properti WM_CLASS dari jendela dengan dpkg --get-selectionshuruf besar , sedangkan program seperti yang tercantum dalam huruf kecil (hanya membaca man wmctrldan menjalankan wmctrl -lx, Anda akan tahu). Menambahkan bahwa -ax harus menangani ini. Script menampilkan jendela chromium yang sudah terbuka sebagaimana mestinya

Hal lain - wmctlr agak aneh karena kadang-kadang perlu penundaan (punya pengalaman dengan itu di skrip lain), jadi saya harus menambahkan sleep 1baris. Sebelumnya akan menjadi semacam dan mematikan dengan firefox, tetapi sekarang berfungsi dengan baik.

Script beraksi

Dalam animasi di bawah ini, Anda dapat melihat bahwa pada menjalankan pertama skrip, ada satu contoh open firefox, dan skrip beralih fokus ke jendela itu; pada tes kedua, saya membuka contoh baru google-chrome, yang belum pernah dibuka sebelumnya. (Catatan: Jika Anda curiga tentang desktop, omong-omong, itu adalah openbox dengan cairo dock)

Per saran dalam komentar, animasi tersemat dihapus, hanya tautan yang diposting. Laporkan jika rusak, tolong! http://i.stack.imgur.com/puuPZ.gif

Pembaruan, 7 April

Saya sedikit memperbaiki skrip untuk membuat semua program yang terdaftar di kotak masuk drop-down zenity. Sekarang pengguna tidak harus mengingat setiap program, tetapi cukup menggulir daftar mereka menggunakan tombol panah atau hanya membuka menu drop down. Juga, versi yang ditingkatkan ini memunculkan windows bukan berdasarkan nama, tetapi berdasarkan id jendela, yang memberikan kinerja yang jauh lebih baik. Catatan, cara saya menelusuri file .desktop agak berlebihan, menggunakan perintah cut dua kali, tapi karena skrip-fu saya tidak begitu baik sejauh ini, ini yang bisa saya lakukan. Saran untuk perbaikan dipersilahkan!

#!/bin/bash
# Author: Serg Kolo
# Description: Second version of a launcher script that checks whether
#       or not a window of a particular program already exists
#       If a window of such program is open, bring it to focus
#       Otherwise - launch a new window
#       Written for /ubuntu//q/440142/295286
# Date: April 7 , 2015
#

set -x

MYPROG=$(zenity --entry --text 'Select program from list' --entry-text $(ls /usr/share/applications/*.desktop | cut -d'/' -f5 | cut -d'.' -f1 | xargs echo))
sleep 0.5
# Do we have a window of such program ?
wmctrl -lx| awk '{print $3}'  | grep -i $MYPROG

if [ $? -eq 0 ]; then
    sleep 0.5 # if yes, find that window id, and raise it
    WINID=$(wmctrl -lx | grep -i $MYPROG | awk 'NR==1{print $1}')
    wmctrl -ia $WINID &
 #  exit 0  
else
    echo $MYPROG | grep -i libreoffice
    if [ $? -eq 0  ]
    then
        MYPROG=$(echo $MYPROG | sed 's/-/ --/g')
    fi
    $MYPROG &

#  exit 0 
fi

masukkan deskripsi gambar di sini

Bonus:

Saya sebenarnya telah menemukan Albert , yang merupakan versi Linux dari Alfred, tetapi belum mencobanya sendiri. Layak untuk dicoba. Namun, seperti yang sudah dicatat Yakub, masih buggy.

Ada sebuah aplikasi bernama Gnome-Do, yang secara grafik terlihat mirip dengan Alfred, namun tidak memiliki fungsi yang sama dengan skrip ini.

masukkan deskripsi gambar di sini

Beri tahu saya jika Anda menyukai skrip ini, jika ada sesuatu yang perlu diperbaiki, dan jangan lupa untuk memperbaiki jawabannya jika Anda merasa bermanfaat

Sergiy Kolodyazhnyy
sumber
Omong-omong, perhatikan bagaimana saya mengetik nama-nama program - persis seperti yang tercantum di dpkg --get-selectons. Meluncurkan libreoffice writer dengan mengetikkan "writer" tidak akan berfungsi, tetapi Anda dapat membuat symlink ke dalamnya di folder ~ / bin, / bin atau / usr / bin Anda atau gunakan alias di .bashrc atau .profile.
Sergiy Kolodyazhnyy
Perhatikan juga, bahwa Anda perlu wmctl diinstal, itu tidak datang secara default, tetapi cukup praktis. Saya juga menggunakannya untuk membuat ini
Sergiy Kolodyazhnyy
Bisakah Anda mengganti annimation dengan gambar, menautkan ke annimation? Browser saya terus "memuat" halaman, jadi saya tidak bisa menyegarkannya. (dan pembatalan tidak berjalan :))
Jacob Vlijm
Terima kasih! Tautan berfungsi dengan baik di Chrome, bukan di Firefox.
Jacob Vlijm
@ JacobVlijm Ugh, begitu juga. Tidak yakin mengapa firefox menolak untuk memainkannya. Itu hanya tautan imgur ke apa yang saya unggah semula
Sergiy Kolodyazhnyy
5

1. Dash the Second

Di bawah ini skrip yang dapat digunakan sebagai alternatif untuk Dash, ketika datang untuk menjalankan aplikasi seperti yang dijelaskan dalam pertanyaan Anda.

Itu ada dari jendela dengan fungsi yang sama dengan Dash; jika mengetik satu atau lebih karakter aplikasi, aplikasi akan muncul dalam daftar. Tekan Enteruntuk memulai atau menaikkan aplikasi, tergantung pada apakah aplikasi itu sudah berjalan atau belum.

Anda dapat memanggilnya dari kombinasi tombol pintas, atau mengatur ikon di peluncur untuk menggunakannya mirip dengan Dash (lihat lebih lanjut di bawah), atau keduanya.

masukkan deskripsi gambar di sini

Naskah

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

user = getpass.getuser()
get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8")
skip = ["%F", "%U", "%f", "%u"]; trim = ["chrome", "chromium", "nautilus"]

def apply(command):
    if "libreoffice" in command:
        proc = [l.split()[0] for l in get("ps -u "+user).splitlines() if "soffice.bin" in l]
        module = command.split("--")[-1]
        time.sleep(0.1)
        try:
            ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w and module in w.lower()] for process in proc], [])[0]
            subprocess.call(["wmctrl", "-ia", ws])
        except IndexError:
            subprocess.Popen(["/bin/bash", "-c", command+"&"])
    else:
        check = command.split("/")[-1][:14]
        proc = [p.split()[0] for p in get("ps -u "+user).splitlines() if check in p]
        time.sleep(0.5)
        try:
            ws = sum([[w.split()[0] for w in get("wmctrl -lp").splitlines() if process in w] for process in proc], [])
            if command == "nautilus":
                real_window = [w for w in ws if "_NET_WM_WINDOW_TYPE_NORMAL" in get("xprop -id "+w)][0]
            else:
                real_window = ws[0]
            subprocess.call(["wmctrl", "-ia", real_window])
        except IndexError:
            subprocess.Popen(["/bin/bash", "-c", command+"&"])
# default directories of .desktop files; globally, locally, LibreOffice- specific when separately installed
globally = "/usr/share/applications"; locally = os.environ["HOME"]+"/.local/share/applications"; lo_dir = "/opt/libreoffice4.4/share/xdg"
# create list of .desktop files; local ones have preference
local_files = [it for it in os.listdir(locally) if it.endswith(".desktop")]
global_files = [it for it in os.listdir(globally) if it.endswith(".desktop")]
lo_spec = [it for it in os.listdir(lo_dir) if it.endswith(".desktop")] if os.path.exists(lo_dir) else []
for f in [f for f in local_files if f in global_files]:
    global_files.remove(f)
for f in [f for f in local_files if f in lo_spec]:
    lo_spec.remove(f)
dtfiles = [globally+"/"+f for f in global_files]+[locally+"/"+f for f in local_files]+[lo_dir+"/"+f for f in lo_spec]
# create list of application names / commands
valid = []
for f in dtfiles:
    content = open(f).read()
    if all(["NoDisplay=true" not in content,"Exec=" in content]):
        lines = content.splitlines()
        name = [l.replace("Name=", "") for l in lines if "Name=" in l][0]
        command = [l.replace("Exec=", "") for l in lines if all(["Exec=" in l, not "TryExec=" in l])][0]
        valid.append((name, command))
valid.sort(key=lambda x: x[0])
# create zenity list + window
list_items = '"'+'" "'.join([f[0] for f in valid])+'"'
proposed = 'zenity --list --text "Type one or more characters... " --column="Application List" '+\
           '--title="Dash the Second" --height 450 --width 300 '+list_items
try:
    choice = subprocess.check_output(["/bin/bash", "-c", proposed]).decode("utf-8").strip().split("|")[0]
    command = [r[1] for r in valid if r[0] == choice][0]
    # command fixes:
    for s in skip:
        command = command.replace(" "+s, "")
    for t in trim:
        if t in command:
            command = t
    apply(command)
except subprocess.CalledProcessError:
    pass

Cara Penggunaan

Script perlu wmctrldiinstal:

sudo apt-get install wmctrl

Kemudian:

  1. Rekatkan skrip di atas ke dalam file kosong, simpan sebagai dash_alternative.py
  2. Tambahkan ke kombinasi tombol pintas: Pilih: Pengaturan Sistem> "Keyboard"> "Pintasan"> "Pintasan Khusus". Klik "+" dan tambahkan perintah:

    python3 /path/to/dash_alternative.py
    

Penjelasan

Ketika skrip dijalankan, itu daftar semua aplikasi, diwakili dalam /usr/share/applications. Itu mencari .dektopfile, membuat daftar semua nama aplikasi (dari baris "Name =" pertama) dan perintah untuk menjalankan aplikasi (dari baris "Exec =" pertama).

Selanjutnya, daftar Zenity dibuat, menampilkan semua aplikasi dengan cara diurutkan.

Setiap kali aplikasi dipilih, skrip akan terlihat dalam daftar proses yang berjalan jika aplikasi sedang berjalan. Jika demikian, jendela yang sesuai dinaikkan. Jika tidak, instance baru dibuka.

Catatan

  1. Untuk menjalankan skrip pada 12.04 (karena pertanyaan asli telah ditandai, 12.04cukup ubah shebang ke #!/usr/bin/env pythondan jalankan dengan perintah

    python /path/to/dash_alternative.py
    
  2. Sejauh saya mengujinya, skrip berfungsi dengan baik. Perintah dan (tidak) nama proses yang sesuai (mis. LibreOffice<> soffice.bin), Tipe jendela berbeda ( nautilusmemiliki beberapa tipe jendela berbeda, selain jendela "nyata"), beberapa pids per aplikasi ( Chromium, Google-chrome) dapat menyebabkan pengecualian, yang saya perbaiki dalam contoh atas. Jika ada yang mengalami masalah, sebutkan saja.

2. Tambahan: mengaturnya sebagai alternatif untuk Dash "nyata" untuk menjalankan aplikasi

  1. Salin dan simpan skrip seperti yang disebutkan di atas
  2. Simpan ikon di bawah ini (klik kanan> safe as) as dash_alternative.png

    masukkan deskripsi gambar di sini

  3. Salin kode di bawah ini ke file kosong, simpan ~/.local/share/applicationssebagai dash_thesecond.desktop. Tetapkan jalur yang benar untuk /path/to/dash_alternative.py(skrip) dan /path/to/dash_alternative.png(ikon)

    [Desktop Entry]
    Name=Dash the Second
    Exec=python3 /path/to/dash_alternative.py
    Icon=/path/to/dash_alternative.png
    Type=Application
    Hidden=false
    
  4. Seret .desktopfile ke peluncur:

Yakub Vlijm
sumber
1
Senang mengetahui ada seluruh folder file .desktop! Saya bertanya-tanya bagaimana aplikasi asli dan apt-instal didaftar dengan nama alih-alih perintah. Kerja bagus di sana!
Sergiy Kolodyazhnyy
@Serg, terima kasih! dan sama untuk Anda :). Ada juga direktori lokal untuk .desktopfile: ~/.local/share/applications. Saya pikir saya akan membatasi pencarian untuk aplikasi yang terinstal secara global.
Jacob Vlijm
Yakub, saya tidak tahu python, tapi mungkin ini akan berguna bagi Anda dalam meningkatkan skrip Anda dengan mengubahnya menjadi ruang lingkup kesatuan. Pemahaman saya adalah bahwa ini adalah satu-satunya cara untuk mengubah fungsi dasbor persis seperti yang diinginkan OP
Sergiy Kolodyazhnyy
@Serg, terima kasih! itu adalah posting yang menarik, pasti akan melihatnya dengan baik!
Jacob Vlijm
0

Untuk peluncur (panel vertikal di sisi kiri layar), ini sudah merupakan perilaku default, karena merupakan antarmuka pengalihan tugas.

Untuk tanda hubung (bit besar yang terbuka ketika Anda mengklik logo Ubuntu), tidak ada cara untuk mengubah perilaku dengan cara ini, tanpa modifikasi yang mungkin signifikan untuk kode sumber itu sendiri.

Namun beberapa aplikasi, mungkin sudah melakukan ini, karena dirancang untuk berperilaku seperti itu. Semua aplikasi tidak, dan tidak harus, diimplementasikan sedemikian rupa.

Namun sebagai fitur lain, jika Anda membuka penyebaran jendela dengan Super+ W, dan mulai mengetikkan nama aplikasi, jendela untuk aplikasi itu akan menjadi satu-satunya yang ditampilkan.

dobey
sumber
Saya sebenarnya telah menemukan versi Linux dari apa yang diinginkan OP, lihat posting saya, bagian bonus. Rupanya orang lain punya ide untuk membawa Alfred ke Linux
Sergiy Kolodyazhnyy
1
@Serg, silakan coba Albert; Albert masih memiliki "bug LibreOffice", "bug Chromium" dan "bug Chrome". Bahkan "File bug" ... Albert selalu membuka contoh baru dari aplikasi tersebut. LibreOffice tidak berfungsi sama sekali. Juga, di komentar di bawah tautan Anda, Anda dapat menemukan sejumlah masalah.
Jacob Vlijm
@Serg Tidak, Anda menemukan solusi, dengan menambahkan perangkat lunak tambahan yang berjalan di latar belakang, yang memberikan pengalaman pengguna yang sama sekali berbeda, dan membutuhkan pelatihan ulang cara menemukan aplikasi. Apa pertanyaan yang diajukan adalah bagaimana cara kerjanya di dasbor Unity. Anda mungkin bisa mendapatkan fitur serupa di luar Unity itu sendiri, tetapi satu-satunya cara untuk mengubah Unity untuk melakukan ini, adalah dengan mengubah kode sumber.
dobey
@obey Yah, itu benar; mengubah fungsionalitas dasbor berada di luar jangkauan kami, jadi. . . harus lakukan dengan apa yang kita miliki, kan? Kecuali ada pengembang yang bersedia untuk membuat kode lingkup kesatuan dengan fungsi tersebut. . .
Sergiy Kolodyazhnyy