WayfireWM / wayfire

A modular and extensible wayland compositor
https://wayfire.org/
MIT License
2.41k stars 176 forks source link

hide or show a program #2318

Open Nosirus opened 7 months ago

Nosirus commented 7 months ago

and is it possible to show or hide an application, for example a terminal?

I would like to ideally reproduce hdrop (or tdrop) with foot or alacritty.

ammen99 commented 7 months ago

You could minimize or restore an animation, is that what you're looking for?

Nosirus commented 7 months ago

no not entirely, I really like drop-down terminals, on hyprland I was able to use hdrop. It hides the window, it doesn't minimize it, practical for quickly calling a terminal, letting it run without it remaining displayed

ammen99 commented 7 months ago

Ok, I see, you'll have to write a custom plugin for that. It shouldn't be too hard to implement, though.

Nosirus commented 6 months ago

Well, I didn't succeed at the moment. is there a possibility to start hiding a terminal and with a key to minimize or display? I would just have to hide the terminal in waybar taskbar.

it would be practical to be able to write the IPC rules more simply for noobs like me 😅

ammen99 commented 6 months ago

Well, I didn't succeed at the moment. is there a possibility to start hiding a terminal and with a key to minimize or display? I would just have to hide the terminal in waybar taskbar.

it would be practical to be able to write the IPC rules more simply for noobs like me 😅

Do you use the minimization feature in general?

Nosirus commented 6 months ago

very little, but it is present and works

ammen99 commented 6 months ago

I think in general it would be cool to have a proper plugin which does this, in the meantime I hacked together a script to kind-of achieve what you want. The catch: in order to be able to easily recognize the terminal, make sure to use a terminal for the drop down that you don't usually use (in this example I used foot, feel free to customize the script):

#!/usr/bin/python3
import json

import subprocess
import os
import time
from wayfire_socket import *

addr = os.getenv('WAYFIRE_SOCKET')
sock = WayfireSocket(addr)

TERMINAL_APPID = "foot"
TERMINAL_CMD = "foot"

def find_view():
    hidden_view = None
    shown_view = None
    # First look for a view which is minimized and matches
    views = sock.list_views()
    for v in views:
        if v['app-id'] == TERMINAL_APPID and v['minimized']:
            hidden_view = v
        elif v['app-id'] == TERMINAL_APPID:
            shown_view = v

    return hidden_view, shown_view

def show_view(hidden_view):
    print("Showing view ", hidden_view)
    # We have our view, just bring it to the front and center it
    msg = get_msg_template('wm-actions/set-minimized')
    msg['data']['view_id'] = hidden_view['id']
    msg['data']['state'] = False
    print(sock.send_json(msg))

    msg = get_msg_template('window-rules/get-focused-output')
    output = sock.send_json(msg)['info']
    print(output)

    msg = get_msg_template('window-rules/configure-view')
    msg['data']['id'] = hidden_view['id']
    msg['data']['output_id'] = output['id']

    # Center on current output
    msg['data']['geometry'] = {}
    msg['data']['geometry']['x'] = output['workarea']['x'] + output['workarea']['width'] // 2 - hidden_view['geometry']['width'] // 2
    msg['data']['geometry']['y'] = output['workarea']['y'] + output['workarea']['height'] // 2 - hidden_view['geometry']['height'] // 2
    msg['data']['geometry']['width'] = hidden_view['geometry']['width']
    msg['data']['geometry']['height'] = hidden_view['geometry']['height']
    print("want to configure with ", json.dumps(msg,indent=4))
    print(output['workarea'])
    print(sock.send_json(msg))

def hide_view(shown_view):
    print("Hiding view ", shown_view)
    # Hide existing view
    # We have our view, just bring it to the front and center it
    msg = get_msg_template('wm-actions/set-minimized')
    msg['data']['view_id'] = shown_view['id']
    msg['data']['state'] = True
    sock.send_json(msg)

hidden_view, shown_view = find_view()
if not shown_view and not hidden_view:
    print("Starting a new view")
    subprocess.Popen(TERMINAL_CMD, start_new_session=True)
    time.sleep(1)
    hidden_view, shown_view = find_view()
    if shown_view:
        show_view(shown_view)
    else:
        print("Failed to start new terminal!")
elif shown_view:
    hide_view(shown_view)
else:
    show_view(hidden_view)

You also need the ipc-scripts/wayfire_socket.py file, put it in the same directory as this script, and you can bind it to a keybinding with the command plugin (make sure to enable wm-actions, ipc-rules and ipc for this to work though!)

The script does the following:

Nosirus commented 6 months ago

oh this looks exactly like what I was looking for and my terminal happens to be foot

I will try this as soon as possible, thank you very much 🤩

Nosirus commented 6 months ago

already a little feedback, I couldn't wait to try. That's exactly what I wanted ! I hide icon foot from waybar.

On the other hand, it only opens on the first workspace, maybe add a sticky option? But yes, a plugin would do great things !

marcusbritanicus commented 6 months ago

A little bit of shameless self-promotion here. While you develop the plugin, may be you can use the app I have built: DesQ Dropdown + DesQ Term.

You can add a command+binding to wayfire config:

binding_dropdown = KEY_F12
command_dropdown = /usr/bin/desq-dd

PS: If you're interested, I can also combine the two and make a single app for you without many extra dependencies

Nosirus commented 6 months ago

I just had to add to fix the problem and it's totally functional

msg = get_msg_template('wm-actions/set-sticky')
msg['data']['view_id'] = hidden_view['id']
msg['data']['state'] = True
print(sock.send_json(msg))

I don't know if wlroots allows it, but for future plugins add the possibility of not displaying an icon, would allow others not to touch the waybar or other config and maybe also being able to deactivate the window decoration could be useful

ammen99 commented 6 months ago

I don't know if wlroots allows it, but for future plugins add the possibility of not displaying an icon, would allow others not to touch the waybar or other config and maybe also being able to deactivate the window decoration could be useful

Yeah if done with a plugin it will make it sticky by default and also won't show up in the taskbar, that's certain.

About removing decoration, I would say that decorations are kind-of orthogonal issue, but the built-in decoration plugin has an option to disable decorations for a particular windows with a criteria, maybe take a look at that.

mark-herbert42 commented 6 months ago

I use tilda-wayland (fork of tilda) a s a dropdown terminal and it manages to do it well, without any effort from wayfire.

https://github.com/shih-liang/tilda-wayland

To make it look nice - adding config lines added in wayfire.ini for tilda only

[animate] zoom_enabled_for = ( app_id contains "tilda" )

[firedecor] (hopefully same can be done with any other decorator as well) ignore_views = ( app_id contains "tilda" & type is "toplevel" )

[window-rules] (adjust to the position you want) rule_4 = on created if ( app_id contains "tilda" & type is "toplevel" ) then move 100 36

Also for toggle hide-unhide map key combination in [command ] section to the following command

dbus-send --session --type=method_call --dest=com.github.lanoxx.tilda.Actions0 /com/github/lanoxx/tilda/Actions0 com.github.lanoxx.tilda.Actions.Toggle

This fork is behind the main tilda tree - but it has Xorg stripped out and native wayland programmed in - so works very nice with all dropdown terminal features, tabs, nice customization options. And it is normal C program, not he python wrapper around something.

killown commented 3 months ago

simplified ammen99 script version:

install wayfire python module

pip install wayfire

#!/usr/bin/python3
import os
import time
from subprocess import Popen
from wayfire.ipc import *

TERMINAL_APPID = "foot"
TERMINAL_CMD = "foot"
TERMINAL_WIDTH = 1000
TERMINAL_HEIGHT = 600
VIEW_STICKY = True # show the terminal in all workspaces, set False to disable
VIEW_ALWAYS_ON_TOP = True # always on top even if another view get the focus, Set False to disable

addr = os.getenv('WAYFIRE_SOCKET')
sock = WayfireSocket(addr)

def find_view():
    hidden_view = shown_view = None
    for v in sock.list_views():
        if v['app-id'] == TERMINAL_APPID:
            if v['minimized']:
                hidden_view = v
            else:
                shown_view = v
    return hidden_view, shown_view

def configure_view(view, output):
    if TERMINAL_WIDTH == 0 or TERMINAL_HEIGHT == 0:
        return
    wa = output['workarea']
    geom = view['geometry']
    x = wa['x'] + wa['width'] // 2 - geom['width'] // 2
    y = wa['y'] + wa['height'] // 2 - geom['height'] // 2
    sock.configure_view(view["id"], x, y, TERMINAL_WIDTH, TERMINAL_HEIGHT)
    sock.set_view_sticky(view["id"], VIEW_STICKY)
    sock.set_view_always_on_top(view["id"], VIEW_ALWAYS_ON_TOP)

def show_view(hidden_view):
    sock.set_view_minimized(hidden_view['id'], False)
    configure_view(hidden_view, sock.get_focused_output())

def hide_view(shown_view):
    sock.set_view_minimized(shown_view['id'], True)

hidden_view, shown_view = find_view()
if not shown_view and not hidden_view:
    Popen(TERMINAL_CMD, start_new_session=True)
    time.sleep(1)
    hidden_view, shown_view = find_view()
    if shown_view:
        show_view(shown_view)
    else:
        print("Failed to start new terminal!")
elif shown_view:
    hide_view(shown_view)
else:
    show_view(hidden_view)