Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added sharedtags-greedyview to recipes #126

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions recipes.mdwn
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ to improve your Awesome setup.
* [Collision geometric navigation keybindings](https://github.com/Elv13/collision)
* [Tyrannical dynamic tag managment framework](https://github.com/Elv13/tyrannical)
* [Repetitive dynamic keybindings and macros](https://github.com/Elv13/repetitive)
* [Alternative tag management for multiple screens](../recipes/sharedtags-greedyview)

## Others

Expand Down
190 changes: 190 additions & 0 deletions recipes/sharedtags-greedyview.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
--- Provides functionality to share tags across all screens in awesome WM.
-- @module sharedtags
-- @author Albert Diserholt
-- @copyright 2016 Albert Diserholt
-- @license MIT

-- Grab environment we need
local awful = require("awful")
local capi = {
screen = screen
}

local sharedtags = {
_VERSION = "sharedtags v1.0.0 for v4.0",
_DESCRIPTION = "Share tags for awesome window manager v4.0 with greedyview",
_URL = "https://github.com/awesome-www/recipes",
_LICENSE = [[
MIT LICENSE

Copyright (c) 2018 Albert Diserholt

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
]]
}

-- Add a signal for each new screen, which just listens for the remove
-- event, and moves over all tags when it happens.
awful.screen.connect_for_each_screen(function(s)
-- When the screen is removed, all tags need to be moved over to an existing
-- screen. If they are not, accessing the tags will result in an error. It
-- doesn't make sense to fix the error, since clients on the now-hidden tags
-- will automatically be moved to a tag on a visible screen.
s:connect_signal("removed",function()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two signal connections can be replaced with just capi.screen.connect_signal("removed", function(s).

-- The screen to move the orphaned tags to.
local newscreen = capi.screen.primary
-- The currently selected tags on that screen.
local seltags = newscreen.selected_tags

-- Move over all tags to an existing screen.
for _,tag in ipairs(s.tags) do
sharedtags.movetag(tag, newscreen)
end

-- Restore the viewed tags on the new screen.
for i,tag in ipairs(seltags) do
if i == 1 then
tag:view_only()
else
awful.tag.viewtoggle(tag)
end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm... assuming I understood this correctly, this is the same as awful.tag.viewmore(seltags, s), except that it does not mess up the tag history as badly.

end)
end)

--- Create new tag objects.
-- The first tag defined for each screen will be automatically selected.
-- @tparam table def A list of tables with the optional keys `name`, `layout`
-- and `screen`. The `name` value is used to name the tag and defaults to the
-- list index. The `layout` value sets the starting layout for the tag and
-- defaults to the first layout. The `screen` value sets the starting screen
-- for the tag and defaults to the first screen. The tags will be sorted in this
-- order in the default taglist.
-- @treturn table A list of all created tags. Tags are assigned numeric values
-- corresponding to the input list, and all tags with non-numerical names are
-- also assigned to a key with the same name.
-- @usage local tags = sharedtags(
-- -- "main" is the first tag starting on screen 2 with the tile layout.
-- { name = "main", layout = awful.layout.suit.tile, screen = 2 },
-- -- "www" is the second tag on screen 1 with the floating layout.
-- { name = "www" },
-- -- Third tag is named "3" on screen 1 with the floating layout.
-- {})
-- -- tags[2] and tags["www"] both refer to the same tag.
function sharedtags.new(def)
local tags = {}

for i,t in ipairs(def) do
tags[i] = awful.tag.add(t.name or i, {
screen = (t.screen and t.screen <= capi.screen.count()) and t.screen or capi.screen.primary,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's up with t.screen <= capi.screen.count()? That seems (a) pointless (if screens are numbers) or (b) broken (if screen objects are used, which I think is actually the case).

layout = t.layout,
sharedtagindex = i
})

-- Create an alias between the index and the name.
if t.name and type(t.name) ~= "number" then
tags[t.name] = tags[i]
end

-- If no tag is selected for this screen, then select this one.
if not tags[i].screen.selected_tag then
tags[i]:view_only() -- Updates the history as well.
end
end

return tags
end

--- Move the specified tag to a new screen, if necessary.
-- @param tag The tag to move.
-- @tparam[opt=awful.screen.focused()] number screen The screen to move the tag to.
-- @treturn bool Whether the tag was moved.
function sharedtags.movetag(tag, screen)
screen = screen or awful.screen.focused()
local oldscreen = tag.screen

-- If the specified tag is allocated to another screen, we need to move it.
if oldscreen ~= screen then
-- greedyview xmonad-style
if tag.selected then
screen.selected_tag.screen = oldscreen
oldscreen.selected_tag:view_only()
end
tag.screen = screen

if oldscreen.selected_tag == tag then
-- The tag has been moved away. In most cases the tag history
-- function will find the best match, but if we really want we can
-- try to find a fallback tag as well.
if not oldscreen.selected_tag then
local newtag = awful.tag.find_fallback(oldscreen)
if newtag then
newtag:view_only()
end
end
end

-- Also sort the tag in the taglist, by reapplying the index. This is just a nicety.
local unpack = unpack or table.unpack
for _,s in ipairs({ screen, oldscreen }) do
local tags = { unpack(s.tags) } -- Copy
table.sort(tags, function(a, b) return a.sharedtagindex < b.sharedtagindex end)
for i,t in ipairs(tags) do
t.index = i
end
end

return true
end

return false
end

--- View the specified tag on the specified screen.
-- @param tag The only tag to view.
-- @tparam[opt=awful.screen.focused()] number screen The screen to view the tag on.
function sharedtags.viewonly(tag, screen)
sharedtags.movetag(tag, screen)
tag:view_only()
end

--- Toggle the specified tag on the specified screen.
-- The tag will be selected if the screen changes, and toggled if it does not
-- change the screen.
-- @param tag The tag to toggle.
-- @tparam[opt=awful.screen.focused()] number screen The screen to toggle the tag on.
function sharedtags.viewtoggle(tag, screen)
local oldscreen = tag.screen

if sharedtags.movetag(tag, screen) then
-- Always mark the tag selected if the screen changed. Just feels a lot
-- more natural.
tag.selected = true
-- Update the history on the old and new screens.
oldscreen:emit_signal("tag::history::update")
tag.screen:emit_signal("tag::history::update")
else
-- Only toggle the tag unless the screen moved.
awful.tag.viewtoggle(tag)
end
end

return setmetatable(sharedtags, { __call = function(self, args) return sharedtags.new(args) end })

-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
115 changes: 115 additions & 0 deletions recipes/sharedtags-greedyview.mdwn
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Different tag management for multiple monitors

The [[sharedtags-greedyview.lua|sharedtags-greedyview.lua]] script implements the xmonad default
behaviour in which tags are handled for multiple monitors, namely:
* A list of tags is shared between all screens
* Selecting a tag shows it on the screen that is focused, regardless of the previous screen of the tag (greedyview)
* If the selected tag was already visible on the other screen, swap tags between screens

# Credit

I forked the script from https://github.com/Elv13/awesome-sharedtags and only added a few lines to implement the
swapping behaviour described above.

# Setup

The process of setting up this script is as follows:

1. Create a file called `sharedtags-greedyview.lua` in your file system (preferably in
awesome's folder) with the [[script|sharedtags-greedyview.lua]] content.

2. Import the script in your `rc.lua`

```lua
local sharedtags = require("sharedtags-greedyview")
```

3. Create the tags using the `sharedtags()` method, instead of the original
ones created with `awful.tag()`. They should be created at the file level,
i.e. outside of any function.

```lua
local tags = sharedtags({
{ name = "main", layout = awful.layout.layouts[2] },
{ name = "www", layout = awful.layout.layouts[10] },
{ name = "game", layout = awful.layout.layouts[1] },
{ name = "misc", layout = awful.layout.layouts[2] },
{ name = "chat", screen = 2, layout = awful.layout.layouts[2] },
{ layout = awful.layout.layouts[2] },
{ screen = 2, layout = awful.layout.layouts[2] }
})
```
4. Remove or uncomment the code which creates the tags when a screen is
connected, in the `connect_for_each_screen` callback.

```lua
awful.screen.connect_for_each_screen(function(s)
-- Each screen has its own tag table.
--awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, awful.layout.layouts[1])

-- Here is a good place to add tags to a newly connected screen, if desired:
--sharedtags.viewonly(tags[4], s)
end)
```
5. The code for handling tags and clients needs to be changed to use the
library and pick the correct tag.

```lua
for i = 1, 9 do
globalkeys = gears.table.join(globalkeys,
-- View tag only.
awful.key({ modkey }, "#" .. i + 9,
function ()
local screen = awful.screen.focused()
local tag = tags[i]
if tag then
sharedtags.viewonly(tag, screen)
end
end,
{description = "view tag #"..i, group = "tag"}),
-- Toggle tag display.
awful.key({ modkey, "Control" }, "#" .. i + 9,
function ()
local screen = awful.screen.focused()
local tag = tags[i]
if tag then
sharedtags.viewtoggle(tag, screen)
end
end,
{description = "toggle tag #" .. i, group = "tag"}),
-- Move client to tag.
awful.key({ modkey, "Shift" }, "#" .. i + 9,
function ()
if client.focus then
local tag = tags[i]
if tag then
client.focus:move_to_tag(tag)
end
end
end,
{description = "move focused client to tag #"..i, group = "tag"}),
-- Toggle tag on focused client.
awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
function ()
if client.focus then
local tag = tags[i]
if tag then
client.focus:toggle_tag(tag)
end
end
end,
{description = "toggle focused client on tag #" .. i, group = "tag"})
)
end
```
6. Lastly, any rules referencing the screen and tag should use the newly
created `tags` array instead.

```lua
awful.rules.rules = {
-- Set Firefox to always map on tag number 2.
{ rule = { class = "Firefox" },
properties = { tag = tags[2] } }, -- or tags["www"] to map it to the name instead
}
```
7. Restart or reload *awesome*.