How to use one key-binding to spawn tag-specific program in awesome-wm? - awesome-wm

Introduction:
In my wrokflow, I am using tags for specific purposes (WEB, IDE, EMAIL, File Manager,>Terminal/Taskwarrior-tui/Timewarrior) and I want to stick to this. So whenever I go to tag 1 I want to have a browser there.
Problem: I would like to minimize the number of key bindings for the most important programs.
Question: How can I use one keybinding for launching a "default program for the tag"??
Example: Let's say that I am currently on tag 1 (called WEB) which default application would be qutebrowser (at least in my case) so I would like to hit MOD+D to spawn qutebrowser. But when I hit the same keybinding (MOD+D) on tag 2 i want awesome-wm to spawn Rstudio.
Note that I am not asking how to make a rule of spawning a certain program on specific tag (with a keybinding assigned to spawning this program) as there are a lot of answers to that around the web. I want to have conditional rule, based on which tag is active, to spawn a predefined app in this tag with one keybinding.

awful.keyboard.append_global_keybindings({
awful.key({ modkey }, "d", function()
local t = awful.screen.focused().selected_tag
if t.name == "WEB" then
-- launch qutebrowser
elseif t.name == "tag 2 name" then
-- launch Rstudio
end
end,
{description = "description", group = "group"})
})

Related

Awesome-WM: Spawn client on same tag as parent

My goal is to let clients that have a parent spawn on the same tag as their parents. Clients w/o parents should spawn on the active tag (as usual).
My first approach is to connect a signal using client.connect_signal("manage", ...). However, I couldn't find a way to get the parent of a client or to check if it has a parent.
Thank you for taking a look at my problem!
Update 1: I found client:get_transient_for_matching (matcher), but the documentation is not very helpful.
Update 2: Thanks to Uli for the hint to use client::transient_for as an easier way to get the transient. Using
client.connect_signal("manage", function (c)
parent = c.transient_for
naughty.notify({ preset = naughty.config.presets.critical,
title = "Debug",
text = tostring(c.window) .. " " .. (parent and tostring(parent.window) or "") })
if parent then
-- move new client to same tag and screen as parent
tag = parent.first_tag
screen = parent.screen
c:move_to_tag(tag)
c:move_to_screen(screen)
end
end)
I tried to achieve my goals and added a simple debug output using notifications. Now, only a very few new clients actually have a transient that is not nil. E.g., spawning git gui from a terminal does not have a transient. However, I strongly believe it should (or I misunderstood what a transient is).
Ubuntu 20LTS, Awesome WM version 4.3-4, awesome-extra 2019021001
You are looking for c.transient_for. This contains the client object for the "parent" window or nil.

Awesomewm update watch widget on keypress

I am a new user to awesomewm (but have used other WMs before: i3, bspwm, xmonad, etc). I like to have some shell scripts that I have written in my wibar (I think that's what its called, the bar at the top of the screen with the taglist) to display stuff like battery, audio, etc (as I know is common). Currently I am using the "wibar.widget.watch" to do this, as shown below.
-- Right widgets
layout = wibox.layout.fixed.horizontal,
awful.widget.watch('musicbar', 5),
wibox.widget.textbox(' | '),
awful.widget.watch('wifibar', 5),
wibox.widget.textbox(' | '),
awful.widget.watch('audiobar', 0.5),
wibox.widget.textbox(' | '),
awful.widget.watch('batbar', 5),
In the code above stuff like "audiobar" are scripts that return information as standard output. It all works perfectly, even displays the emojis well :). I have one problem (maybe just an optimization).
Currently I have the audiobar running twice a second, this is because that is the only one which directly changes based on my input (changing volume) and so I want it to change immediately (obviously this still has a <= 0.5 second delay, which is annoying). This means that most of the time it is updating twice a second unnecesarily.
So, I'm wondering if there is a way to have it update when I change the volume, which I've bound to the XF86 audio keys in rc.lua, instead of changing based on a timer. Based on my reading of the documentation, there is no way to do this with the watch widget, but as I said I am new to awesome.
Below is how I bound the keys (shouldn't make a difference, but I imagine that this is where the change would be made).
awful.key(
{},
"XF86AudioLowerVolume",
function()
awful.spawn("amixer -q set Master 5%-")
end,
{description = "lower volume", group = "control"}
),
I know that I can use some of the pre-made widgets on github to display volume and stuff but I like the shell scripts because they let me easily move between WMs and are simpler than those widgets (which I like because it means that I can more easily address problems with them and make them display exactly what I want, as well as learn).
edit: I am willing to learn to do this with lua, I just first want to see if I can easily do it with shell scripts.
You need to keep a reference to the timer around that awful.widget.watch creates internally. To do this, you need to do something like this in global context (i.e. outside of the definitions of the widgets or keybindings):
local musicbar_widget, musicbar_timer = awful.widget.watch('musicbar', 5)
You now add musicbar_widget to your wibox (instead of calling awful.widget.watch there). Now, you can "force-update" the widget via musicbar_timer:emit_signal("timeout"). This "pretends" to the widget that the timeout happened again.
In your keybinding (yes, I am mixing up your widgets here, most likely musicbar has nothing to do with the volume):
awful.key(
{},
"XF86AudioLowerVolume",
function()
awful.spawn("amixer -q set Master 5%-")
musicbar_timer:emit_signal("timeout")
end,
{description = "lower volume", group = "control"}
),
Note that this might or might not work. awful.spawn only starts the command, but does not wait for it to finish. So now you are changing the volume at the same time that your are querying it. If querying finishes faster than changing the volume, then the update does not actually occur.
To only update the widget after changing the volume is done, do something like the following:
awful.spawn.with_line_callback(
"amixer -q set Master 5%-", {
exit = function()
musicbar_timer:emit_signal("timeout")
end
})
I ran into a similar problem with streetturtle's volumearc widget. By default, it runs an update command:
Everytime the volume is modified through the widget.
Every second to catch any external volume changes (like with key bindings defined in rc.lua).
watch(get_volume_cmd, 1, update_graphic, volumearc)
Of course this has the following disadvantages:
A slight delay in the volume update (one second in still very perceptible).
On my machine, a constant 1% CPU load just for this task. A trifle I know, but little things add up.
Using a returned update function
A possible solution is to return an update function, available in the context of rc.lua and call this update along the volume modifications.
In volumearc.lua, in the worker function, we put the widget update into a dedicated function:
local ext_update = function()
spawn.easy_async(get_volume_cmd,
function(stdout, stderr, exitreason, exitcode)
update_graphic(volumearc, stdout, stderr, exitreason, exitcode) end)
end
And we return it both from the worker function:
return volumearc, ext_update
and from the widget itself:
volumearc, ext_update = { __call = function(_, ...) return worker(...) end }
return setmetatable(widget, volumearc), ext_update
Now we can use it in rc.lua:
local volumearc_widget = require("widgets.volume-widget.volumearc")
-- ...
local GET_VOLUME = "amixer sget Master"
local INC_VOLUME = "amixer sset Master 3%+"
local DEC_VOLUME = "amixer sset Master 3%-"
local TOG_VOLUME = "amixer sset Master toggle"
myvolume, volume_update = volumearc_widget({get_volume_cmd=GET_VOLUME,
inc_volume_cmd=INC_VOLUME,
dec_volume_cmd=DEC_VOLUME,
tog_volume_cmd=TOG_VOLUME})
-- `myvolume` is the widget that can be added as usual in the wibox.
-- `volume_update` is the function to call in order to trigger an update.
-- ...
-- In the key bindings:
awful.key({}, "XF86AudioMute",
function () awful.spawn(TOG_VOLUME) volume_update() end,
{description="mute", group = "media"}),
awful.key({}, "XF86AudioRaiseVolume",
function () awful.spawn(INC_VOLUME) volume_update() end,
{description="raise volume", group = "media"}),
awful.key({}, "XF86AudioLowerVolume",
function () awful.spawn(DEC_VOLUME) volume_update() end,
{description="lower volume", group="media"}),
Now the volume will be updated both when changed from the widget or from the media keys, instantly and without the need for polling.
Caveat
This does not catch changes made through other interfaces, such as alsamixer for example. To catch these changes, you might want to run the watch function with a very low time frequency (say once per minute).
The code given here is specific to streetturtle's widget, but the concept of returning an internal update function applies for any widget.

How to clean old deployed versions in Firebase hosting?

Every time you deploy to Firebase hosting a new deploy version is created so you can roll back and see who deployed. This means that each time every file you deploy is stored and occupying more space.
Other than manually deleting each deployed version one by one, is there any automated way to clean those useless files?
You're correct. You'll need to delete the old deployed versions one by one using the Firebase Hosting console.
There's no other way to do this, so I'd suggest you to file a feature request to enable deletion of multiple deployed version in the Firebase Hosting console.
Update:
You can vote here (please avoid +1 spam, use reactions) https://github.com/firebase/firebase-tools/issues/215#issuecomment-314211730 for one of the alternatives proposed by the team (batch delete, keep only X versions, keep versions with published date < Y)
UPDATE Mar/2019
There's now a proper solution: "Version history settings" which allows to keep the last X versions.
https://support.google.com/firebase/answer/9242086?hl=en
UPDATE Feb/2019
Confirmed by Google employee # github.com/firebase/firebase-tools/issues/...
It is actively being worked on. 🙂
🎉🎉🎉
Before continuing reading:
You can vote here (please avoid +1 spamming, use reactions) https://github.com/firebase/firebase-tools/issues/215#issuecomment-314211730 for one of the alternatives proposed by the team
So, by using Chrome Dev tools I found a way to delete multiple versions. Keep in mind it requires a bit for work (proceed with care since deleted versions can't be restored and you won't get any warnings like when using the UI).
Step 1. Retrieving the version list.
Open Chrome Dev Tools (if you don't know how to chances are you should wait for a proper solution by Firebase's team).
Open Firebase's Console and go to the "Hosting" tab.
Go to the "Network" tab on CDT and use the Websockets filter.
Select the request named .ws?v=5&ns=firebase
Open the "Frames" tab
Now comes the tedious part: Select the frames with the highest "length" value. (Depending on your data, it could be 2-n frames. In my case, 3 frames with 14k-16k length)
Paste each of the frame's data in order (which will form a valid JSON object).
Extracting the data: There are several ways to do it. I opted for simple JS on CDT's console.
var jsonString = '...';
var json = JSON.parse(jsonString);
var ids = Object.keys(json.d.b.d);
Step 2. Performing the requests
Almost there :P
Now that you have the IDs, perform the following requests:
DELETE https://firebasehosting.clients6.google.com/v1beta1/sites/PROJECT_NAME/versions/-VERSION_ID?key=KEY
I used Sublime (to create the request strings) + Paw.
The "KEY" can be copied from any of CDT's requests. It doesn't match Firebase's Web API key
=> Before performing the requests: take note of the version you don't want to delete from the table provided by Firebase. (Each version listed on the website has the last 6 digits of it's ID under your email)
(Screenshots weren't provided since all of them would require blurring and a bit of work)
This script is not yet super-solid, so use it at your own risk. I'll try to update it later, but worked for me for now.
Just some javascript to click on buttons to delete deployed items one by one.
var deleteDeployment = function(it) {
it.click()
setTimeout(function() {
$('.md-dialog-container .delete-dialog button.md-raised:contains("Delete")').click()
}, 300)
}
$('.h5g-hist-status-deployed').map((i, a) => $(a).parent()).map((i, a) => $(a).find('md-menu button:contains(Delete)')).each((i, it) => {
setTimeout(function() {
deleteDeployment(it)
}, (i + 1) * 2000)
})
Firebase finally implemented a solution for this.
It is now possible to set a limit of retained versions.
https://firebase.google.com/docs/hosting/deploying#set_limit_for_retained_versions
EDIT: previous link is outdated. Here is a new link that works:
https://firebase.google.com/docs/hosting/usage-quotas-pricing#control-storage-usage
This may be a bit brittle due to the selectors' reliance on current DOM structure and classes on the Hosting Dashboard, but it works for me!
NOTE: This script (if executed from the console) or bookmarklet will click and confirm delete on all of the rows in the current view. I'm fairly certain that even if you click delete on the current deployment it will not delete it.
Function for running in console:
let deleteAllHistory = () => {
let deleteBtns = document.querySelectorAll('.table-row-actions button.md-icon-button');
const deleteBtn = (pointer) => {
deleteBtns[pointer].click();
setTimeout(() => {
document.querySelector('.md-open-menu-container.md-clickable md-menu-item:last-child button').click();
setTimeout(() => {
document.querySelector('.fb-dialog-actions .md-raised').click();
if(pointer < deleteBtns.length - 1) {
deleteBtn(pointer + 1);
}
}, 500);
}, 500);
};
deleteBtn(0);
};
Bookmarklet:
javascript:(function()%7Bvar%20deleteBtns%3Ddocument.querySelectorAll('.table-row-actions%20button.md-icon-button')%2CdeleteBtn%3Dfunction(a)%7BdeleteBtns%5Ba%5D.click()%2CsetTimeout(function()%7Bdocument.querySelector('.md-open-menu-container.md-clickable%20md-menu-item%3Alast-child%20button').click()%2CsetTimeout(function()%7Bdocument.querySelector('.fb-dialog-actions%20.md-raised').click()%2Ca%3CdeleteBtns.length-1%26%26deleteBtn(a%2B1)%7D%2C500)%7D%2C500)%7D%3BdeleteBtn(0)%7D)()
Nathan's option is great, but I have a quick-and-dirty method using AutoHotkey. Takes about a second per version to delete, so you can knock out a page in 10 seconds.
#a::
Click
MouseGetPos, xpos, ypos
MouseMove, xpos, ypos + 30
Sleep 300
Click
Sleep 400
Click 1456, 816
MouseMove, xpos, ypos + 82
return
#s::
Click
MouseGetPos, xpos, ypos
MouseMove, xpos, ypos - 820
return
You'll likely need to modify the exact pixel values for your screen, but this works perfectly on my 1920x1080.
Win + a is delete and move to the next entry, Win + s is move to the next page. Put your mouse on the first 3-dot menu and go for it!
On top of the release history table, click the tool bar and select "Version history settings". Set to desired amount and click save.This will auto delete older deployments.
I don't know it can help you or not but I can delete old deployments from "hosting" menu like this:
Delete or rollback old deployment

How to show in GNU Screen hardstatus tabs that have an activity?

Each time I have more than 4 tabs, I really like to know in which one there's activity.
Until now, I used to benefit from rxvt tabbing system. It displays a * next to tabs which are not shown, but have an activity. It's really usefull when you're on a IRC channel for example.
How can I do it with zsh/screen ?
Here's my .zshrc :
function precmd {
echo -ne "\033]83;title zsh\007"
}
function preexec {
local foo="$2 "
local bar=${${=foo}[1]}
echo -ne "\033]83;title $bar\007"
}
and my .screenrc
hardstatus off
hardstatus alwayslastline
hardstatus string '%{= kG}[ %{G}%H %{g}][%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B} %m-%d %{W} %c %{g}]'
[...]
shell "/usr/bin/zsh"
aclchg :window: -rwx #?
aclchg :window: +x title
This is documented in the manual:
monitor [on|off]
Toggles activity monitoring of windows. When monitoring is
turned on and an affected window is switched into the background,
you will receive the activity notification message in the status
line at the first sign of output and the window will also be
marked with an `#' in the window-status display. Monitoring is
initially off for all windows.
You can manually toggle monitoring for the current window via C-a M, or if you want monitoring on for all windows by default, add defmonitor on to your screenrc. Once on, any windows to the left or right of the current one in your hardstatus line (as expanded by %-Lw and %+Lw respectively in your hardstatus string line) will show an # symbol after the hyphen which follows the window number. You'll also get an alert message which can be configured via the activity command.
On my system, the # doesn't appear until something else in the window changes. This can be fixed by removing hardstatus off from your config file.
Finally, I strongly recommend that you try tmux. Development on GNU screen has mostly stalled, and tmux is an actively maintained and developed replacement which has pretty much a large superset of screen's functionality.

Having the apps in the task bar always in the same order. Open apps on the right of the others

I would like to have some apps (which I open when starting my session) always in the same order in the task bar. Is that possible?
Vim | Chrome | Terminal
Another question: for now, when I open an app, it is opened on the left part of the task bar, is there a way to open it rather on the right side, after the already open apps?
I have this lines in rc.lua:
-- Add widgets to the wibox - order matters
mywibox[s].widgets = {
{
mylauncher,
mytaglist[s],
mypromptbox[s],
layout = awful.widget.layout.horizontal.leftright
},
mylayoutbox[s],
mytextclock,
s == 1 and mysystray or nil,
mytasklist[s],
layout = awful.widget.layout.horizontal.rightleft
}
Javi
To place new windows to the end of the list (make them slave) you can add rule to the rc.lua file
{ rule = { }, properties = { }, callback = awful.client.setslave }
To autostart apps use
awful.util.spawn_with_shell("App1 -with -keys")
awful.util.spawn_with_shell("App2 -with -keys")
They will run in this order I believe. And make sure that you added awful in the rc.lua. You can do it by function require("awful")
Take a look at the FAQ
P.S. Sorry, I'm not sure do I understand you right.

Resources