Skip to content

Tray explicit sorting, forward and reverse#470

Open
alaricljs wants to merge 7 commits into
LBCrion:mainfrom
alaricljs:feat-tray_explicit_sort
Open

Tray explicit sorting, forward and reverse#470
alaricljs wants to merge 7 commits into
LBCrion:mainfrom
alaricljs:feat-tray_explicit_sort

Conversation

@alaricljs

Copy link
Copy Markdown
Contributor

This implements explicit sorting of tray items. The user can assign a value to use in place of the standard sort keys:

TrayOrder {
"KeePassXC" = "a_keepass";
"nm-applet" = "b_network";
"blueman" = "c_bluetooth";
}

Unassigned apps keep their original sort value.

In addition, it implements forward/reverse sorting allowing right-aligned trays to fill from right to left.


Why -

I have a fixed set of applications that have tray icons. I like having them in a particular order and was doing that by disabling sort and starting them in that order. They don't all behave perfectly so sometimes I need to restart one and that breaks the ordering.

@LBCrion

LBCrion commented May 13, 2026

Copy link
Copy Markdown
Owner

First, big thank you for doing this. Tray sorting has been on the back burner for about 5 years, but I never got to it, as no one explicitly asked for the feature until now.

One thing I wonder is whether we need to assign a string sort key to tray items or if we can just sort them explicitly, i.e.:

tray {
  ...
  order = "KeePassXC", "nm-applet", "blueman";
  ...
}

On one hand using sort keys allows comparing sorted items with unsorted, on the other hand, if somebody specifies an explicit order, they probably don't want a rogue tray icon popping up between sorted items because it happens to have a name that slots between sort keys.

The only other question I have is do we need to reverse sort in tray_item_compare, since flow_grid_update already g_list_reverse's the sort order?

@alaricljs

Copy link
Copy Markdown
Contributor Author

It was so much worse than you noticed, that's on me. I panic PR'd after seeing you change flow_grid_update() because I didn't want to deal with more merge conflicts :) All cleaned up now.

I'm open to explicit sorting, a set of numeric tags does the same.

@alaricljs

Copy link
Copy Markdown
Contributor Author

And by open, I mean I'll write it that way if you'd rather.

@LBCrion

LBCrion commented May 18, 2026

Copy link
Copy Markdown
Owner

I think using an order string array in the tray section would be neater from the configuration point of view, since it avoids another {} section somewhere away from the main train config. It should also be easier to implement.
You can define a GPtrArray *order in TrayPrivate and add a string array property to populate it using something like:

  g_object_class_install_property(G_OBJECT_CLASS(kclass), TRAY_ORDER,
      g_param_spec_boxed("order", "order", "sfwbar_config", G_TYPE_PTR_ARRAY,
        G_PARAM_READWRITE));

And then in tray_item_compare, you can get an index for each using something like:

guint i1, i2;
GPtrArray *order;
...
g_object_get(flow_item_get_parent(a), "order", &order, NULL);
if(!order || !g_ptr_array_find_with_equal_function(order, p1->sni->string[SNI_PROP_TITLE], g_strcmp0, &i1))
  i1 = G_MAXUINT;

This way you don't need any changes in the config parser at all.

@alaricljs

Copy link
Copy Markdown
Contributor Author

g_strcmp0 can't be used as a GEqualFunc, so it's a bit different than your example.

@LBCrion

LBCrion commented May 18, 2026 via email

Copy link
Copy Markdown
Owner

@alaricljs

Copy link
Copy Markdown
Contributor Author

There you go, doing this means 2 runs through the array. I don't think glib is doing any optimization there, but it's small.

@LBCrion

LBCrion commented May 19, 2026

Copy link
Copy Markdown
Owner

g_ptr_array is indeed unoptimized. I guess we could convert to/from a hash table in the prop set/get functions, but I'm not sure it's worth it given the size of these arrays.

I think we no longer need flow_grid_is_sort_reverse, since the property is only used in flow_grid_update now. Also, I think we need to copy sort_reverse property documentation for taskbar and switcher as well, since these are also derived from the flow grid.

Finally, I'm trying to get my head around the changes to child packing in the flowgrid. What is it doing differently from the old implementation?
Currently flowgrid packs children into an array with either a number of columns or rows specified, sorting them along a primary axis first. I.e. a 5 item grid with rows = 2 and columns as a primary axis will get:
1 3 5
2 4
The same grid with primary axis set to rows will get:
1 2 3
4 5

I'm trying to mentally step through the new implementation for the first scenario, rows=2 (cols=0), primary=cols:
span = 5 / 2 + !!(5%2) = 2+1 = 3
base = 5/3 = 1
extra = 5%3 = 2
first count = 1 + !!2 = 2

this translates into coordinates of:
1 (i=0) : 0, 0 (i<first_count: 0,i)
2 (i=1): 0, 1 (i<first count: 0,i)
3 (i=2): 1, 0 (pri = 1 + (2-2)/2, sec = (2-2)%1)
4 (i=3): 2, 0 (pri = 1 + (3-2)/1, sec = (3-2)%1)
5 (i=4): 3, 0 (pri = 1+ (4-2)/1, sec = (4-2)%1)

So we have
1 3 4 5
2

I suspect I'm missing something or calculating something wrong here.

@alaricljs

Copy link
Copy Markdown
Contributor Author

Sorry that took so long. You're right, the math was off in certain cases, it's been corrected.
The goal is that primary_axis is used to determine how the items are laid out. So for 2 rows and primary_axis=rows:
A B C D
E F G

and 2 rows with primary_axis=cols:
A C E G
B D F

=cols was broken when the division was uneven.

@LBCrion

LBCrion commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Ok, I think I understand what new layout code is trying to do. Am I right that it handles the allocation of the remainder to align the primary axis with the main layout direction. I.e. addressing the case of 7 items in 3 rows (with rows being the primary axis):

A B C
D E F
G

vs

A B C
D E
F G

Am I correct in my understanding?

@alaricljs

Copy link
Copy Markdown
Contributor Author

yes, that's it

@LBCrion

LBCrion commented Jun 3, 2026

Copy link
Copy Markdown
Owner

How about just adjusting i to skip populating the relevant cells? I.e. change i++ after flow_grid_child_position to:
i+=1+(i%dim==dim-2 && (i+1)/dim>=count%dim && axis_cols^(rows>0));

@LBCrion

LBCrion commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Actually, can simplify it a bit further, since (i+1)/dim == i/dim when i%dim==dim-2, so:
i += 1 + (i%dim==dim-2 && i/dim>=count%dim && axis_cols^(rows>0));

It's probably worth renaming dim to span though. It describes the purpose of the variable much better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants