Some suggestions

Added by Sae Hirak over 4 years ago

I would first like to say that I very deeply appreciate the work you have done on subtle; out of all the window managers I've tried (xmonad, awesome, wmii, and StumpWM) it is by FAR the best. It is top notch in every way: the window manager itself, the configuration, the documentation, AND the support. It's clear that you're dedicated to doing a good job, and I would gladly pay you if I had more cash to spare.

However, there are several things that I think would make subtle even better for myself, and possibly others as well, listed in the order of most important to least:

1) I want to be able to set clients to a view without giving them a tag. I understand that subtle uses so-called "strict tagging" and that's fine (even desirable), but if a user wants to hack up a Ruby script that uses "weak tagging", I think they should be able to.

I think the best way to accomplish this is to make the views method of clients mutable, like gravity, geometry, etc. This would be soooo convenient and useful. For instance, on the Snippets wiki page ( the "Move windows" code could be significantly simplified to this:

# Add nine C-< number> grabs
(1..9).each do |i|
  grab "C-%d" % [ i ] do |c|
    views = Subtlext::View.all

    # Sanity check
    if i <= views.size
      c.views = [ views[i - 1] ]

Same for "Current view":

# Assign tags to clients
on :client_create do |c|
  tags = { |t| }

  # Exclusive for clients with default tag only
  if tags.include?("default") and 1 == tags.size
    c.views = [ Subtlext::View.current ]

2) Personally, I find tiling window managers to be far superior to stacking. I want all of my windows to be tiled (not overlapping at all) except for floating windows. Because of this, the gravities system (although very cool, unique, and flexible) doesn't help me more than a good column/row system. And so, I end up using the :horz and :vert tiling modes a lot.

There is one major tiling mode that I really want, though, and that's :grid, which is where the windows are given equal space in a horizontal and vertical grid. Which means if you had 8 windows, it would look like this:

#   #   #   #
#   #   #   #
#   #   #

I tried to hack up my own version in subtle.rb, using the :client_create event and client.geometry to automatically place the windows in a grid, but I haven't gotten it working yet.

3) As far as I can tell, you can't style (border, padding, margin, etc.) the :tray at all, the one where notification icons like Pidgin show up.

4) The :title element of the panel seems to be cut off on long titles. I understand this is probably a feature, but it would be nice to be able to configure it in some way, giving it a custom cutoff length, or disable cutoff completely (showing the full title no matter what)

Perhaps the simplest way to do that would be to have a max_width style property, though that works based on pixels rather than characters. I can see why people might want either a character limit, a pixel limit, or both, so I think both kinds of limits should be supported, though I'm not sure how to support the character limiting (another style property, maybe?)

5) I think things like xfdesktop shouldn't be counted for whether a tag is "visible" (affected by dynamic or not). I mention this because I want to make a view containing the default tag dynamic, but doing so doesn't work, because xfdesktop is assigned to the default tag. Perhaps it shouldn't be assigned to a tag by default?

6) For matching clients/tags, I think it would be better if the string syntax "foo" meant an exact match, equivalent to /^foo$/ If you want to use regexp matching, you can use the /.../ regexp syntax. This is good not only because it makes it clear whether it's an exact/regexp match, but it's more convenient as well:

"^foo$"         ->  "foo" 
"foo\\.bar\\d"  ->  /foo\.bar\d/

7) As far as I can tell, there's no way to set up "global defaults" for things like tags or views. For instance, if I wanted all views to be dynamic true unless I overwrite a particular one with dynamic false, I don't see a way to do that.

8) Is there any way to create a global :mouse_down event? I would like to have clients focused on click because they sometimes aren't autofocused properly (though fixing the autofocus would be good, having a :mouse_down event might prove useful for other things in the future).

9) Kind of a nitpick, but Subtlext::View (and others) don't accept arbitrary expressions like Subtlext::View[i - 1], you have to use Subtlext::View[:all][i - 1]. Is there a technical reason for this (like Ruby not allowing it)?

Replies (15)

RE: Some suggestions. - Added by Sae Hirak over 4 years ago

I also found what I believe to be bugs, and shall be posting them on the Issue tracker.

RE: Some suggestions - Added by Christoph Kappel over 4 years ago


thanks and also thanks for the suggestions. I will try to answer all of them with some details why I did a certain thing or not, since some of the suggestions aren't entirely new.

1) Tagging is meant to be an abstraction to placement that is no surprise to the user. When you take awesome wm for example, placement there is sometimes a mystery /annoyane to me. When you start an app, it might appear on the current 'virtual desktop' or somewhere else.

Technically your suggestion is quite possible, but I need to add random new tags for that e.g. based on the view name or add a tag automatically when you add a new view. Reusing existing tags that the view already has might have some nasty side-effects, e.g. when subtle uses a tag that forces fullscreen. Another problem is that there's a technical limit (32 in total) of the number of tags.

I will consider it.

2) Stacking was a goal here, tiling is nice but when you have e.g. more than four windows it becomes pointless. Writing tiling algorithms is quite easy, see the layout sublet for example.

Dividing the screen into equal squares is easy:

Number of columns: cols =: ceil(sqrt(n))
Number of rows   : rows =: ceil(n / cols)

So it should be (untested) like:

 1 on :tile do |v|
 2   n     = v.clients
 3   cols  = Math.sqrt(n).ceil
 4   rows  = (n / cols).ceil
 6   # Calculate slot size
 7   geom  = Subtlext::Screen.current.geometry
 8   slotw = (geom.width / cols).ceil
 9   sloth = (geom.height / rows).ceil
11   # Counters
12   posx = 0
13   posy = 0
15   v.clients.each do |c|
16     c.geometry = [ posx, posy, slotw, sloth ]
18     # Adjust position
19     if posx + slotw >= geom.width
20       posx  = 0
21       posy += sloth
22     else
23       posx += slotw
24     end
25   end 
26 end

3) Nope, there is no styling available yet, feel free to add a feature request for that.

4) The reason for a limit here is obvious, browser WM_TITLE can be damn long if you don't apply a limit here. There is a styling option available to control the length tho, check here.

5) Uhm what exactly is xfdesktop? When a window has no tag it gets the default tag], that's how tagging works.

6) Well,subtle is written in C after all and I have to convert regexp back and forth. I might add implicit ^ and $ to strings but that requires stupid checks and reallocating of memory or buffer modifications. Is it wrong to assume smart users?

7) Is something like that really needed? I really don't feel like having a kind of base view all other views inherit values from is a good idea. I usually just use variables, when I need a definition more than once.

8) Nope, mouse events work client-wise and it is a bit messy to handle that properly. Also I wouldn't recommend to bind a grab just on one mouse key. There is currently no check if one hook triggers another so that might lead into an infinite loop.

9) There's no technical reason, I never needed it so far and no one asked before. Add a ticket and I am going to add it. (Need tickets for that for reminder anyway)

RE: Some suggestions - Added by Sae Hirak over 4 years ago

1) I'm curious, why is there a 32-tag limit?

2) Right, that's why I use multiple views (with ~4 windows per view), and use Alt+Tab and Alt+Shift+Tab to switch between views. Obviously that may not work for everyone, but it works wonderfully for me, much better than when I used stacking window managers like metacity or xfwm4.

Thank you very much for that information! I had seen the Sublets page, but was unaware of the :tile event. That looks like it'll do what I want, which is great because I think it's best to do as much as you can in Ruby.

4) Ah, thank you! I'll test that and see if it works. I agree that a limit is nice, but I have a 1600x900 monitor, so the limit seems short to me. Being able to configure it is perfect.

5) It's the Desktop daemon program thingy for Xfce. It runs in the background, displaying the desktop wallpaper. It's not actually a normal window, so it doesn't get a border or anything like that. Its type should be "Desktop", judging by

As a test, I just used subtler to remove the "default" tag from xfdesktop and it still displays my desktop wallpaper on all views, so my suggestion is to not tag clients on the desktop stacking layer with the "default" tag, since it's presumed that they're already displaying on all views anyways (due to being desktops). That way the "default" tag can work with dynamic.

As a workaround, I can assign xfdesktop to a tag, and then simply not show that tag on any view, but it'd still be nice to have it fixed properly in subtle, without needing the workaround.

6) It's not so much about smartness than about convenience, but I understand if it's technically annoying or difficult to do. It's not a big deal, since I can just add in the ^ and $ myself.

7) Well, compare these two:

set :dynamic, true

view "foo", "bar" 
view "qux", "corge" 
view "foobar", "yes" 
view "foo" do
  match "bar" 
  dynamic true
view "qux" do
  match "corge" 
  dynamic true
view "foobar" do
  match "yes" 
  dynamic true

It doesn't add new functionality, it's just a way to remove boilerplate for options that are used in a lot of different tags/views.

Thank you very much for your helpful reply.

RE: Some suggestions - Added by Christoph Kappel over 4 years ago

1) The limit is really technical, subtle needs to do lots of tag checks and uses bit operations for that. One integer consists of 32 bits, that is the limit. Using multiple integers for more tags kind of kills the benfit.

2) You need to add a check for a certain view, otherwise that applies to all, but should be easy to adapt. And you are welcome. ;)

5) Odd, normally subtle should handle that properly or I don't understand you. Windows like that usually have the _NET_WM_WINDOW_TYPE_DESKTOP type and subtle handles that correctly. Also it is intended, that desktop type windows appear on all views.

7) Well, that is long but you might consider that:

1 { "foo" => "bar", "qux" => "corge", "foobar" => "yes" }.each do |k, v|
2   view k do
3     match v
4     dynamic true
5   end
6 end

Keep in mind that the DSL of subtle is still ruby and you can use it in loops and conditions, too.

RE: Some suggestions - Added by Sae Hirak over 4 years ago

7) Doh! That's perfectly acceptable, thank you!

RE: Some suggestions - Added by Christoph Kappel over 4 years ago

5) What is the problem with the default tag then?

RE: Some suggestions - Added by Sae Hirak over 4 years ago

5) Well, here's what's happening. I have a view (let's just call it "foo") that is set up to show the default tag:

view "foo" do
  match "default" 
  dynamic true

As you can see, it's also set up as dynamic. Okay, so let's say I have a bunch of untagged clients, which of course means they get tagged with "default", and thus show up on the "foo" view. Great, works fine, no problem.

But now let's suppose I kill all those clients, so there aren't any more normal clients with the "default" tag. The problem is, dynamic never triggers for the view "foo" because xfdesktop is tagged with "default", so subtle thinks that there are still active clients on the "default" tag even though there aren't.

If I use subtler -c xfdesktop -U default then it works properly. I tried setting up a tag like this:

tag "hidden" do
  match "xfdesktop" 

But it didn't work: now xfdesktop is tagged with both "hidden" and "default" (is that intentional, by the way? I thought "default" was only given for untagged clients...) Basically, this problem would be completely solved if desktop clients weren't tagged with "default".

By the way, I'm using version 0.10.3008, so I don't know if it's actually a problem in the latest version... I'll be compiling the latest version later to see if it's still an issue or not.

RE: Some suggestions - Added by Sae Hirak over 4 years ago

Okay, I built 0.10.3203 and tried it out, but...

2) You said to do this:

on :tile do |v|

Judging by your example, it seemed that you expected the v argument to be the gravity that needs tiling. That would be great, except it doesn't work because the :tile event isn't passed any arguments, so the argument v is nil.

In addition to that, although you can set the tiling method of gravities, it appears you cannot get it:

<WARNING> NoMethodError: undefined method `tiling' for foo:Subtlext::Gravity

This is necessary so I can seamlessly integrate it with the existing gravities system like this:

gravity :foo, [ 0, 0, 100, 100 ], :grid
on :tile do |g|
  if g.tiling == :grid

Should I file issues for those two problems?

4) Setting the width of :clients works, thanks! I would personally move the property to :title and call it max_char but that's just nitpicking...

5) This is still a problem even with the latest version. See above post for more details.

On the plus side, using the latest version, the :tile event is triggered when closing a client (it didn't before), and some other bugs I had were also fixed, hurray!

RE: Some suggestions - Added by Christoph Kappel over 4 years ago

2) Oh, that is really a bug. I expected that the tile hook gets a view object, looks I have forgotten that tiling works gravity-wise. ;)

Going to fix that later.

As you can see in the rdoc there is no #tiling method for Subtlext::Gravity and since you cannot set arbitrary values to #tiling= there was never a need to carry that information within the object. One problem here is that the length of string atoms is limited and that there is no more room to add another string.

4) I am aware of that, there's even a fixme in the code but I cannot move it easily into the other style, because the title style uses all values and the clients style doesn't.

5) That is no bug, desktop type windows are meant to be visible on all virtual desktops, I don't see a reason to break ICCCM compliance here?

RE: Some suggestions - Added by Sae Hirak over 4 years ago

5) Regardless of whether xfdesktop has the "default" tag or not, it appears on all views, as it should. This means that the "default" tag is at best redundant, and at worst it actually interferes with the dynamic mode.

In addition, you might have missed it, but I already tried giving xfdesktop a hidden tag:

tag "hidden" do
  match "xfdesktop" 

But now xfdesktop is tagged with both "default" and "hidden". That definitely seems to be a bug to me, since "default" should only be applied to untagged clients. My point is that desktop clients should appear on all views, and should not be tagged with "default".

RE: Some suggestions - Added by Christoph Kappel over 4 years ago

5) Nope sorry, still not a bug. subtle assigns the default tags, when a client has a tag that is used for actual placement and your hidden tag is never visible, obviously.

Never thought of this, desktop type clients are sticky anyway so I can safely remove the default tag. Please add a ticket for this.

RE: Some suggestions - Added by Christoph Kappel over 4 years ago

5) I fixed that in r3206.

7) I added tag procs in r3209, maybe they are useful for you, too. See the latest news for information about it.

9) I cannot reproduce your problems with #[] and expression, that works properly here.

1 >> Subtlext::View[2-2]                                                                                                
2 => terms

RE: Some suggestions - Added by Sae Hirak over 4 years ago

5) I just updated and it works! Thank you very much! (By the way, you probably already know, but subtle --version still shows 0.10.3203)

7) Excellent! I can definitely make use of this!

9) Yeah, I just tried it and it works. I guess it was just an issue with the stable version, so upgrading to latest fixed it.

RE: Some suggestions - Added by Christoph Kappel over 4 years ago

5) When you build subtle from the repo you have to run @rake clobber@ once to reset the cached data including the fetched revision number.

7) and 9) Great. :)