Alberth
unread,Jul 29, 2013, 12:43:29 PM7/29/13Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to freer...@googlegroups.com
Hi,
Thanks for the improved patch that uses the Z priority.
It is not correct though, and it can also get much further simplified, after a more detailed look at the WindowManager code.
I'll first give some comments on the current patch, mostly to show how you can code it smarter.
Then I'll reflect on what the patch is doing, and alternative ways to reach its functionality in a much more integrated way.
I realize my comments are very brief and can be read as very harsh, but that's just my style of commenting.
If they are harsh in any way, they are harsh only to the patch itself, never to you as person or as developer.
I very much appreciate that you take the time and effort to get the project forward.
(I know from experience that reading these comments for the first few times can really ruin your day. If they do, stop reading, and don't react on them while you are angry. Instead, let it sink in for a few days, reread them, and try to decide objectively whether I am talking rubbish or not for each point that I make. Adopt things that you think are good, ask for clarification or explain why you think I am wrong for the other things. It is perfectly possible that I am wrong on some things, or we can agree to disagree on some points :) )
The purpose of commenting your patch is to increase the code quality as much as possible. I also found that doing this made me grow as programmer because I got explained alternative (and often better) solutions, even though I did have a some bad days after someone else burned my patch to the ground.
> /**
> + * Move window 'w' above window 'position'.
> + * @param w The window to move.
> + * @param position The window we have to put 'w' above.
> + */
> +void WindowManager::MoveWindowAbove(Window *w, Window *position)
We already have 'move window', which means moving in the (x,y) plane. To avoid confusion, a different name than 'move' is useful. Perhaps use RaiseAbove or so?
"position" makes no sense to me in this method, "below" seems better to me.
In the documentation, you can use \a (as in "\a w") to refer to arguments of the method.
Last but not least, if you generalize the method to also allow NULL for 'position' (meaning 'insert w at the bottom), the method is fully generic with very little extra work.
> +{
> + if (w == position) {
> + return;
> + }
The doxygen text implies that w and position can never be the same window (a window cannot be above itself).
Silently ignoring violations like this means the program keeps running, but with faulty data (either w or position is not what it should be). Quite likely, it creates havoc in some weird way, and eventually crashes in some totally weird way 5 minutes later. 5 minutes later is however a *LOT* of statements to search for the cause of the error.
The alternative way is to crash the program in a controlled way, eg by
assert(w != position);
This is the earliest possible point where you can detect that something is not right. The sequence of statements to this point should be much shorter than in the above case.
> + /* Remove our window. */
> + if (w->higher != NULL) {
> + w->higher->lower = w->lower;
> + }
> + if (w->lower != NULL) {
> + w->lower->higher = w->higher;
> + }
Code is fine. I'd write the 'then' statement after the 'if' and omit the curly brackets, but that's just personal style.
> + bool is_top = (position == this->top ? true : false);
Are you aware that comparisons are functions that give a boolean result?
bool is_top = (position == this->top);
does exactly the same.
> + if (position->higher != NULL) {
> + position->higher->lower = w;
> + w->higher = position->higher;
> + w->lower = position;
> + position->higher = w;
> + }
> + else {
> + position->higher = w;
> + w->lower = position;
> + }
Since this->top->higher == NULL, the "if (position->higher != NULL) {" test is actually the same as testing !is_top. You can merge the "this->top = w;" code below into the 'else'.
> +
> + if (is_top == true) {
> + this->top = w;
> + }
'if' takes a boolean value inside the parentheses, so you can just do "if (is_top) { ..."
> + if (is_bottom == true) {
> + this->bottom = w;
> + }
This is wrong.
'position' is below w, so the latter is never at the bottom in your patch.
> + /* Give the clicked window focus. */
> + if (this->current_window->higher != NULL) {
> + bool move_up = (GetWindowZPriority(this->current_window->wtype) >= GetWindowZPriority(this->current_window->higher->wtype) ? true : false);
> + if (move_up) {
Use the condition immediately in the 'if' statement, and delete the 'move_up' variable entirely?
> + /* Find new location for our window. */
> + Window *position = this->current_window;
> + while (position->higher != NULL && GetWindowZPriority(this->current_window->wtype) >= GetWindowZPriority(position->higher->wtype)) {
> + position = position->higher;
> + }
> + this->MoveWindowAbove(this->current_window, position);
It looks a bit long to me, first test whether you can move up, and if you can, move up until you cannot move further.
If you always look for the new place to insert the window, and afterwards check whether it needs moving, the code is simpler (both tests get merged).
A 'while' that fails on the first try is much like an 'if' that fails.
> + this->current_window->MarkDirty();
I was surprised about this one, and wondered whether you had forgotten something here.
In the end however, I concluded this is indeed the right solution.
> void StartWindowMove();
>
> + void MoveWindowAbove(Window *w, Window *position);
This part of the patch triggered my "Move" comment, two functions both using "move", but with a totally different meaning.
So far about your current patch. I hope you understand what I meant to say. Feel free to open a discussion about my points if you think I am unclear, or when I seem to be missing some important point.
Now about the alternative solution.
When you look in the existing code, WindowManager::DeleteWindow does the remove-window part (and a bit more), and WindowManager::AddTostack inserts a window at the right point (in a somewhat different way). An alternative is thus to split the DeleteWindow in two pieces (namely, the 'remove window' part and 'delete w'), and use those two functions to move the window to the right point in the stack.
I agree it's less efficient in terms of CPU use, the 'add' function may walk through more windows than absolutely needed. On the other hand, there are not so many windows displayed (it should also implement automatically closing of windows at the bottom if it does not do that already), and clicking at a window is a human action, so it is not executed very often and CPU time is mostly irrelevant.
(Just now I see that "AddTostack" should be "AddToStack" (with uppercase S). Amazing how many silly mistakes you make :) )