siefkenj / gnome-shell-windowlist

Displays a list of open windows in gnome-shell
GNU General Public License v2.0
34 stars 18 forks source link

Suggestion - minimize, maximize, close, restore, etc #15

Closed mathematicalcoffee closed 11 years ago

mathematicalcoffee commented 12 years ago

Hi,

I wrote an extension 'window-options' that adds a drop down menu to the Main.panel._appMenu with options like close (window), minimize, maximize, restore, always on this workspace, ... (https://extensions.gnome.org/extension/353/window-options/).

I had a user ask about making my extension compatible with yours. Now I'm pretty sure that's not possible because mine can only patch _appMenu (I could patch every button in Main.panel._leftBox but then buttons that aren't meant to will get the menus).

However I reckon I could patch your extension to add these options in/happy for you to look at my code if you wanted to implement it (lives at bitbucket with mercurial: https://bitbucket.org/mathematicalcoffee/window-options-gnome-shell-extension).

What are your feelings towards this? Also, I'm on GNOME 3.2 at the moment and I've managed to modify the specialMenu.js to have unmaximize, maximize, minimize, close (window, not app), move, resize. I haven't seen your extension in action on GNOME 3.4 yet (but will try tonight), so I don't know how feasible adding these items in will be.

Always on top/always on visible workspace are a bit hacky as the Mutter/Meta interface is not fully exposed at the moment - you have to use Wnck which requires wnck-devel. These options could be left off if you didn't want to add another dependency to the project.

Anyhow, let me know what you think about this. I'm happy to do the work. In case you're interested:

Maximize:

metaWindow.maximize(Meta.MaximizeFlags.HORIZONTAL | Meta.MaximizeFlags.VERTICAL);

Minimize:

metaWindow.minimize(global.get_current_time());

Unmaximize

metaWindow.maximize(Meta.MaximizeFlags.HORIZONTAL | Meta.MaximizeFlags.VERTICAL);

Close (window)

metaWindow.delete(global.get_current_time());

Move (really global.display.begin_grab_op is all that is needed in the Mainloop.idle_add; the Gdk stuff just moves your cursor to the appropriate part of the window):

Mainloop.idle_add(function () {                                 
                    let pointer = Gdk.Display.get_default().get_device_manager().get_client_pointer(),
                        [scr,,] = pointer.get_position(),                       
                        rect    = current_window.get_input_rect(),              http://github.github.com/github-flavored-markdown/
                        x       = rect.x + rect.width/2,                        
                        y       = rect.y + rect.height/2;                       
                    pointer.warp(scr, x, y);                                    
                    global.display.begin_grab_op(global.screen, metaWindow, 
                        Meta.GrabOp.MOVING, false, true, 1, 0, global.get_current_time(),
                        x, y);                                                  
                    return false;                                               
                });

Resize:

Mainloop.idle_add(function () {                                 
                    let pointer = Gdk.Display.get_default().get_device_manager().get_client_pointer(),
                        [scr,,] = pointer.get_position(),                       
                        rect    = current_window.get_input_rect(),              
                        x       = rect.x + rect.width,                          
                        y       = rect.y + rect.height;                         
                    pointer.warp(scr, x, y);                                    
                    global.display.begin_grab_op(global.screen, metaWindow, 
                        Meta.GrabOp.RESIZING_SE, false, true, 1, 0, global.get_current_time(),
                        x, y);                                                  
                    return false;                                               
                });

For always on top, you have to get metaWindow as a Wnck.Window instead (at the moment I do this by doing Wnck.Screen.get_default().get_active_window(), because comparing the window titles isn't good enough). Then:

wnckWindow.make_above() // or unmake_above();
wnckWindow.pin(); // or unpin()
mathematicalcoffee commented 12 years ago

I can send you the patched specialMenu.js for the GNOME 3.2 verison if you like (metadata.json v3)

siefkenj commented 12 years ago

This sounds great. I am embarrassed to admit that I am also still on 3.2 (The 3.4 support were patches I accepted). Is there a way to use Wnck if it's there and gracefully disable the option if it is not?

If you get things all integrated, send me a pull request and I'll check it out :-).

mathematicalcoffee commented 12 years ago

Will do! but which commit do I make my changes onto (i.e. do you know which changeset corresponds to the latest GNOME 3.2 one)? (Sorry I am very rusty with git).

siefkenj commented 12 years ago

You can do it off master. I hope to be on 3.4 in the next few weeks :-).

mathematicalcoffee commented 12 years ago

I can't do the 3.2 changes off master, that's compatible with 3.4 only. Do you have a tag or branch marking the latest one that's compatible with 3.2?

mathematicalcoffee commented 12 years ago

OK, I think I worked it out:

Commit 7ede91868efd5d75ce98065416acedf029041e33 is the most recent that was compatible with 3.2. The most recent 3.2 version on extensions.gnome.org is 1f7e5bf1a0b277e1840e314b6b817412f7bcdf9d which is the one I patched. This one has individual buttons for each window.

In the most recent 3.2 & 3.4 extensions though there's just one menu per app group so I'm not entirely sure how to add the min/max options there - I can add them onto the per-group menu but which window should they affect? Or do we do per-window menus?

siefkenj commented 12 years ago

I did a lot of restructuring and cleanup for 7ede91868efd5d75ce98065416acedf029041e33 . It would be most helpful if the patch were against that commit. The menu options should affect the window that currently has focus in the group, which should be stored in the group for you.

mathematicalcoffee commented 12 years ago

OK, this is what I've done:

These commits were at first made off the latest GNOME 3.2 version (7ede918 as you requested) and work with GNOME 3.2, I've tested. They're in a branch called '3.2_window_options'.

Then in commit 9de189224f7e7e895a0112f668325ec9369e6fbd I merged this branch into the HEAD of master which ports these changes to 3.4 and they work there too.

Have a look and if you like, tell me what you'd like me to put in the pull request.

For example you might want the window buttons in the hover menu but not the menu buttons in the right click menu (that's why I kept these in separate commits so that it might be easier to cherry pick the commits corresponding to what you want).

Further details: Window Buttons in hover menu:

These are just St.Buttons with unicode characters as their labels (that's why some of them look odd, I couldn't always find the unicode character that matched the action). They should probably be styled with images instead in the stylesheet.css, but as-is they demonstrate proof of concept.

The 'up' arrow is 'always on top', the 'anchor' is 'pin' i.e. 'always on visible workspace', the + is move (I couldn't find the plus with the arrows move symbol), the arrow is resize, the _ is minimize, square is maximize (and it switches to restore when you maximize a window), X is close.

The always on top/visible workspace are Wnck only, and if we cannot find the Wnck window that corresponds with the meta.Window we fail gracefully by excluding these options from the menu. If the user doesn't have Wnck installed the same is supposed to happen (I can't test as it is installed on all of my computers).

Menu Items These are like the window buttons but affect this.appGroup.lastFocused. Also, a few modifications to AppGroup in extension.js to try and locate the Wnck window that corresponds to the Meta window this.appGroup.lastFocused, and if we can't then the items just do nothing (alternatively, we could hide them from the menu or setSensitive(false), but this could be confusing as sometimes the Wnck window can be found and sometimes it can't).

With all of the above, whenever the menu is opened the items update themselves to reflect the always on top/always on visible workspace properties of the windows in case they got changed not from the window (for example, always on top is toggled 'off' and then the user right-clicks the window's system title bar and sets it to true -- then the toggle should also read 'on' to reflect this).

And a word on locating the Wnck.Window that matches a particular Meta.Window: there is no way to directly convert between these. So, I currently get a list of all Wnck windows for the default screen. I then loop through them all until I hit one that has the same title and app as the target Meta.Window.

This is not enough to uniquely identify it though; for example if you open a couple of terminals and leave them at the home directory say, they'll have the same title and app.

So what I then do is compare the target Meta.Window's get_outer_rect() with the Wnck.Window's get_geometry(), which are supposed to be the same (x, y, width, height of the window plus decorations).

If these are equal for a given Wnck window then we assume that that is the same as the Meta.Window.

This still isn't foolproof in that if two windows have the same title, app, and are in the exact same position and have the exact same size, the extension will only pick the 'first' one as the corresponding wnck window instead of the second. But given the unlikeliness of this happening I think that's good enough.

Let me know what you think.

mathematicalcoffee commented 12 years ago

https://github.com/mathematicalcoffee/gnome-shell-windowlist/commits/master

siefkenj commented 12 years ago

I tested your patches out. They are quite neat!

Couple of comments:

Wnck, seems to rarely be able to find the correct metaWindow...When it can't, the thumbnail options are suppressed as they should be, but the right-click menu still shows them. . ..

All my testing was done against the right_click_window_options tagged commit. Unfortunately I still don't have 3.4 to test out master...

mathematicalcoffee commented 12 years ago

It's the same code for 3.4.

I'd love tooltips over the buttons but didn't put them in since GNOME 3.4 doesn't have them. I think replacing the app title text with what the button does on hover is a good idea here.

Clutter factor - I can try make them fade to visible. How would I make them not cause a resize? (I'm sure they can be styled to look less eye-bleeding too, but I have no nack for that sort of thing).

Application groups - I agree it would be nice to affect the window that the mouse is over. Perhaps if the button-release event were tied to the WindowButton instead of the AppButton if the group is expanded? Other than that all I can think of is to get the coordinates of the button event and try use Clutter.Stage.get_actor_at_pos, or perhaps the width/position of each WindowButton to work out which was clicked. I can try this.

However I'd argue that:

In summary, this is what I reckon would be ideal:

What do you reckon? I'm a bit busy at the moment but will come back to play with this soon I hope.

siefkenj commented 12 years ago

I like it. I forget all the details at the moment, but one of the containers you set the size request functions yourself. This allows you to lie about your size, which would prevent the hover menu getting taller. I think some of the clutter actors I stuck in the menu already do this, so maybe it's just a matter of choosing the right parent...

mathematicalcoffee commented 12 years ago

I finally got round to doing this! Haven't submitted a pull request yet - have a play around first.

https://github.com/mathematicalcoffee/gnome-shell-windowlist

The 3.2_window_options branch is for GNOME 3.2 and works. The 'master' branch is for GNOME 3.4 -- I've merged the changes in (from the 3.2 branch) but have not tested them yet.

I'm pretty happy with it!

mathematicalcoffee commented 12 years ago

OK - am happy with the latest versions (3.2_window_options for gnome 3.2, and master for gnome 3.4), EXCEPT don't use this with the Maximus gnome shell extension yet, because I'm getting this bug (on 3.2 anyway) whereby I use the hover menu to maximize the window, it maximizes and undecorates, but fires an extra 'window-added' signal that screws Maximus over. (And I only get this extra window-added signal when I run Maximus with this extension - why would that be??)

siefkenj commented 12 years ago

Looking good. The icons and captions are very nice :-). Since neither of us have 3.4, we can keep a 3.2 branch around for easier testing. There are a few things we could do to polish a bit more:

I like the new right-click behavior for expanded groups. When everything gets squared away, I will ask people on extensions.gnome.org to test on 3.4.

mathematicalcoffee commented 12 years ago

OK - done! (branch 3.2_window_options).

I do have 3.4 on a different computer, but just don't get much time on it. I will incorporate these changes into gnome 3.4 eventually though (the only extra work will be to add the settings to prefs.js). But the 3.2 version is ready now for trying out.

Also, I noticed that the 3.2_window_options version of the extension lags a little behind the master version - for example, in extension.js for 3.2_window_options all the Frippery Move Clock stuff in enable()/disable() is enabled. In your master branch for 3.4, the Frippery Move Clock stuff is disabled. Should I merge new changes from your master 3.4 branch into the 3.2 branch so that they both remain in sync?

siefkenj commented 12 years ago

I think we're almost ready to merge. Just a couple more things:

Truth be told, I don't want the frippery stuff removed, but I accepted the working 3.4 patch as is since I didn't have a testing environment. When I eventually get one (which will hopefully be before 3.6 is released!), I will look for a more permanent solution.

mathematicalcoffee commented 12 years ago

OK.

I fixed the first two.

With the last, I was able to replicate a few times and determine that when this occurs the chrome window's 'appears_focused' property is ALWAYS stuck to 'false' which prevents the window from being unfocused - this is why it won't minimize again.

However, I tried a few more times (to try narrow down what it was), and I can no longer replicate the bug?? All I did earlier was have chrome open, restart gnome shell, focus it via clicking on the AppButton, and then try to click on the AppButton again to unfocus it (which did not work as window.appears_focused was false). Now when I try that again, it works fine. Bringing other windows to focus after focusing chromium does not reproduce the problem.

What could this be ??? I can't test any further since I can't reproduce the bug any more! However, it is something to do with the chrome window somehow getting stuck with .appears_focused being false, and even though one calls .activate() on the window (and it comes to focus), its .appears_focused property remains false. I don't know what can cause that.

siefkenj commented 12 years ago

It appears the issue is everyones favourite library: Wnck. After a call to Wnck.Screen.get_default() chromium always reports false to appears_focused. Before this call, it reports the correct focus. Not sure of why or a workaround, but if Wnck is disabled, things function normally.

Perhaps the easiest thing to do is to add Wnck/always on top functionality as a option with a warning that activating it may cause frameless windows to malfunction with respect to windowlist.

What are your thoughts?

mathematicalcoffee commented 12 years ago

Wow, good work for working that one out, I was completely stumped. Do you have a bug report link for it (I'd like to watch it)?

I'd agree - a warning (or perhaps remove that functionality all together). I'll put it as an option with the rest of the options in the top of extension.js?

On 1 September 2012 11:25, siefkenj notifications@github.com wrote:

It appears the issue is everyones favourite library: Wnck. After a call to Wnck.Screen.get_default() chromium always reports false to appears_focused. Before this call, it reports the correct focus. Not sure of why or a workaround, but if Wnck is disabled, things function normally.

Perhaps the easiest thing to do is to add Wnck/always on top functionality as a option with a warning that activating it may cause frameless windows to malfunction with respect to windowlist.

What are your thoughts?

— Reply to this email directly or view it on GitHubhttps://github.com/siefkenj/gnome-shell-windowlist/issues/15#issuecomment-8208920.

siefkenj commented 12 years ago

I haven't filed a bug report yet. If you want to, it would be greatly appreciated :-). I've been hacking away, polishing things up (including adding Wnck as an option). Hopefully I'll have stuff pushed later today. I finally upgraded to 3.4 (thought it might fix the wnck bug...), so I'll be making a branch for that and pushing all your changes as a single commit.