Para mi propia sorpresa, funciona bastante bien, Siempre y cuando no tengas demasiadas otras cosas en tu escritorio. .
Trabajé con él durante un tiempo, y parece un extraño, pero extrañamente bonito alternativa a los frecuentes cambios de espacio de trabajo. Refrescante por su sencillez.
En la práctica
En realidad, la solución es más o menos la que describes:
-
Al pulsar una combinación de teclas, la ventana se "encajona" en el escritorio, desde una ventana:
![enter image description here]()
en un icono, con la apariencia de la aplicación:
![enter image description here]()
-
Haga doble clic en el icono, la ventana volverá a aparecer y el icono desaparecerá.
Cómo funciona
La historia corta (explicación):
En .desktop
añadirá una serie de argumentos adicionales, como el id de la ventana, el nombre (de archivo) del .desktop
archivo.
Posteriormente:
-
En .desktop
para convertirlo en un objeto sobre el que se puede hacer doble clic.
-
Cuando el .desktop
se hace doble clic en el archivo, la ventana se (re)asigna, el .desktop
de su escritorio.
Cómo instalarlo
-
Como prácticamente siempre, cuando se quiere jugar con Windows, el script necesita tanto wmctrl
y xdotool
:
sudo apt-get install xdotool wmctrl
-
Crear el directorio ~/bin
( ~
representa su directorio personal)
-
Copie el script siguiente en un archivo vacío, guárdelo como windowbox
(sin extensión) en ~/bin
.
#!/usr/bin/env python3
import subprocess
import sys
import os
# --- On Unity, there is a (y-wise) deviation in window placement
# set to zero for other window managers
deviation = 28
# ---
args = sys.argv[1:]
get = lambda cmd: subprocess.check_output(cmd).decode("utf-8").strip()
def find_dtop():
# get the localized path to the Desktop folder
home = os.environ["HOME"]
dr_file = home+"/.config/user-dirs.dirs"
return [home+"/"+ l.split("/")[-1].strip() \
for l in open(dr_file).readlines() \
if l.startswith("XDG_DESKTOP_DIR=")][0].replace('"', "")
def check_windowtype(w_id):
# check the type of window; only unmap "NORMAL" windows
return "_NET_WM_WINDOW_TYPE_NORMAL" in get(["xprop", "-id", w_id])
def get_process(w_id):
# get the name of the process, owning the window and window x/y position
w_list = get(["wmctrl", "-lpG"]).splitlines()
pid = [l for l in w_list if w_id in l][0].split()
proc = get(["ps", "-p", pid[2], "-o", "comm="])
xy = (" ").join(pid[3:5])
return (proc, xy)
def read_f(f, string, proc):
# search for a possible match in a targeted .desktop file
try:
with open(f) as read:
for l in read:
if all([l.startswith(string), proc in l]):
in_f = True
break
else:
in_f = False
except:
in_f = False
return in_f
def get_icon(proc, w_name):
# search appropriate icon in /usr/share/applications
exceptions = [item for item in [
["soffice", "libreoffice-main"],
["gnome-terminal", "utilities-terminal"],
["nautilus", "folder"],
] if item[0] in proc]
if exceptions:
if exceptions == [["soffice", "libreoffice-main"]]:
loffice = [
["Calc", "libreoffice-calc"],
["Writer", "libreoffice-writer"],
["Base", "libreoffice-base"],
["Draw", "libreoffice-draw"],
["Impress", "libreoffice-impress"],
]
match = [m[1] for m in loffice if m[0] in w_name]
if match:
return match[0]
else:
return exceptions[0][1]
else:
return exceptions[0][1]
else:
default = "/usr/share/applications"
dtfiles = [default+"/"+f for f in os.listdir(default)]
for f in dtfiles:
if read_f(f, "Exec=", proc) == True:
for l in open(f).readlines():
if l.startswith("Icon="):
icon = l.replace("Icon=", "").strip()
print(f)
break
break
return icon
def create_name():
# create unique (file-) name for boxed window
n = 1
while True:
name = dtop+"/"+"boxed_"+str(n)+".desktop"
if os.path.exists(name):
n += 1
else:
break
return name
def convert_wid(w_id):
# convert window- id, xdotool format, into wmctrl format
w_id = hex(int(w_id))
return w_id[:2]+(10-len(w_id))*"0"+w_id[2:]
def create_icon(w_id, w_name, icon, pos):
# create the launcher, representing the boxed window
boxedwindow = create_name()
f_content =[
"[Desktop Entry]",
"Name=[WINDOW] "+w_name,
"Exec=windowbox show "+w_id+" '"+boxedwindow+"' "+pos,
"Icon="+icon,
"Type=Application",
]
if icon == "generic":
f_content.pop(3)
with open(boxedwindow, "wt") as boxed:
for l in f_content:
boxed.write(l+"\n")
command = "chmod +x "+"'"+boxedwindow+"'"
subprocess.call(["/bin/bash", "-c", command])
if args[0] == "box":
dtop = find_dtop()
w_id = convert_wid(get(["xdotool", "getactivewindow"]))
w_name = get(["xdotool", "getwindowname", w_id])
if check_windowtype(w_id) == True:
procdata = get_process(w_id)
procname = procdata[0]
icon = get_icon(procname, w_name); icon = icon if icon != None else "generic"
create_icon(w_id, w_name, icon, procdata[1])
subprocess.call(["xdotool", "windowunmap", w_id])
elif args[0] == "show":
w_id = args[1]
subprocess.call(["xdotool", "windowmap", w_id])
subprocess.call(["xdotool", "windowmove", "--sync", w_id, args[3], str(int(args[4])-deviation)])
os.remove(args[2])
-
Hacer ejecutable el script
-
Para que el directorio recién creado "aparezca" en $PATH
cierre la sesión o ejecute source ~/.profile
(desde una ventana de terminal)
-
Prueba- ejecuta el script desde una ventana de terminal mediante el comando:
windowbox box
La ventana debería desaparecer, la ventana "en caja" debería aparecer en tu escritorio.
-
Si todo funciona bien, añade el siguiente comando a una tecla de acceso directo: elige el icono del engranaje en la parte superior derecha de tu pantalla:
![Gear icon]()
-
Ir a System Settings → Keyboard → Shortcuts → Custom Shortcuts . Haga clic en el botón + y añade el comando:
windowbox box
Con eso debería bastar.
Nota importante
El script utiliza xdotool
's windowunmap
para hacer invisible la ventana. La "caja" (icono) creada en tu escritorio es la única "puerta" a la ventana oculta. En otras palabras: no elimines el/los archivo(s) del escritorio manualmente. La ventana se perderá para siempre si lo haces.
Trabajo por hacer [editar 20-12: hecho ]
El script aún podría perfeccionarse:
- La geometría de la ventana no se restaura por definición. Se puede arreglar muy bien, pero pensé en mostrar el primer resultado.
- En la mayoría de los casos, la ventana en caja tiene su icono correcto. La función
get_process(w_id)
Sin embargo, podría mejorarse. Si el proceso no se encuentra como un comando en /usr/share/applications
el archivo tiene un icono genérico.
Dar a los iconos de las ventanas en recuadro un tamaño diferente al de los demás iconos.
El script nombra a los creados .desktop
archivos siempre boxed_1.desktop
, boxed_2.desktop
etc., en función del nombre "disponible" en el momento de la creación (nombres de archivo, no el nombre visualizado).
Puedes cambiar el tamaño de los archivos (en general), haciendo clic con el botón derecho del ratón > tamaño del icono. La buena noticia es que si eliminas el archivo y lo vuelves a crear, el tamaño se recuerda. Incluso si creas el archivo de nuevo después de un reinicio. Esto significa que si ever redimensionado el cuadro de Windows (por ejemplo) 1-5, se siempre ¡tengan el mismo tamaño cuando usted (el script) los cree de nuevo!
![enter image description here]()
0 votos
Pregunta rara, pero interesante :) Se me ocurre algo así. ¿Importaría el icono o podría ser uno genérico? ¿Cómo se comporta? como un icono en el escritorio o una "ventana" mínima.
0 votos
@JacobVlijm El icono no es genérico. Cada aplicación tiene su propio icono como los iconos de Windows minimizados en Unity)
0 votos
También se podría hacer dentro de Unity, pero la ventana estaría iconizada en el escritorio (con el icono de la aplicación correspondiente y el nombre de la ventana). ¿Te apetece intentarlo? (sería un trabajo interesante, pero desafiante, mejor preguntar antes de empezar :) )
1 votos
Sí, esto puede serme útil. Tengo que trabajar con muchas ventanas abiertas y esta forma de organizarlas es mejor en mi opinión. No sé nada sobre Unity, así que sólo puedo ayudar con las pruebas.