This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Tinwview, resolution changes, and window placement

Tags: None
(comma "," separated)
Hyper_Eye
Registered Member
Posts
4
Karma
0
I posted this thread on both the Phoronix and Gentoo forums. I haven't gotten much assistance from either. I would really like to solve this.

I have been using Nvidia's twinview with KDE for a long long time. In that time I have always been frustrated by the effect resolution changes have on my window placement. I place my windows in a particular configuration between my two monitors. When I start a game that uses RandR resolution mode changes the placement of my windows ends up changed. In particular the windows get moved to the left monitor if the game switches to a mode that turns the right monitor off. When I'm done playing I have to reposition all my windows. Sometimes the resolution change will also cause my taskbar size to change from around 80% of the width of one monitor to 100%. I have been getting around this issue by using XVidMode resolution mode switching whenever possible. This involves setting registry options for games that use Wine. I also sometimes use GameTreeLinux/Cedega and it uses XVidMode by default. When it comes to native games the chances seem to be about 50/50 that it will use one or the other. libSDL based games will use XVidMode if built against the last few releases or, in the case of games dynamically linked against libSDL, your system libraries are up-to-date. SDL can also be forced to use XVidMode with an environment variable.

As of the 302.XX Nvidia drivers switching resolutions with XVidMode is resulting in the same issue I have when switching with X/Randr. So my "work-around" is no longer working. At this point I am ready to try something else and I am hoping that someone here knows a better solution. I would like for my windows to either return to their original position or for KDE to totally ignore resolution changes. I don't know if the solution might lie in KDE settings, X settings, or Nvidia settings. Thanks for any ideas you might have.
karthikp
Registered Member
Posts
109
Karma
0
OS
Three comments.

1. I would have normally suggested that you stick with the nouveau drivers as they are much more well-behaved with the rest of the packages than nvidia (which the last I remember would simply replace a third of xorg with its hacks). However, this is not an option if you use your box for gaming. As awesome as nouveau is to work with, its 3-D performance is far behind the proprietary nvidia driver's.

2. kwin is rather (in)famous for having a billion configuration options in the window settings that you can use to do all kinds of things. You can access these settings by doing alt+f3 from a window or left/right clicking on the icon in the titlebar of the window. Note that you can force window sizes and positions, among other things. That might come in handy.

3. There were multiple blogposts some time back about progress on kwin scripting. (I seem to remember the dev even got the windows to play pong with each other!) If you could write a script that would "return" the windows back to the original positions and sizes, that would be a pretty neat solution. So, I'd suggest looking into how to write kwin scripts (assuming it's now part of the current release and not still in development).


karthikp, proud to be a member of KDE forums since 2008.
Image
whatthefunk
Registered Member
Posts
61
Karma
0
I have the same problem. It drives me crazy. When I run any program (usually a game or Wine) that uses a resolution change and exit that program, all my desktop widgets and open windows end up in weird places on the left screen. My panel configuration also changes, so much so that having the panel the way I want is too much of a headache. Because of this, Ive completely given up on KDE desktop widgets and use conky instead.
Hyper_Eye
Registered Member
Posts
4
Karma
0
karthikp wrote:3. There were multiple blogposts some time back about progress on kwin scripting. (I seem to remember the dev even got the windows to play pong with each other!) If you could write a script that would "return" the windows back to the original positions and sizes, that would be a pretty neat solution. So, I'd suggest looking into how to write kwin scripts (assuming it's now part of the current release and not still in development).


I have started writing a kwin script that implements the desired behavior. The idea is to store all the window geometry for unique desktop resolutions as the resolution changes. While any particular resolution is used the stored geometry is updated when a window changes.

This is what I have so far: https://github.com/mwoodj/kwinscripts/b ... restore.js

Code: Select all
// reschangedesktoprestore - Restore windows when resolution changes
// Copyright (C) 2012  Michael J. Wood
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

var clientMap = new Object();

function initialize() {
  var clients = workspace.clientList();

  for(var i in clients) {
    addClient(clients[i]);
  }
}

function addClient(client) {
  print("Adding new client: ", client.caption);
  updateClientMap(client);
  client.clientFinishUserMovedResized.connect(updateClientMap);
}

function removeClient(client) {
  var clientId = client.windowId;
   
  if(clientMap[clientId]) {
    print("Deleting client: ", client.caption);
    delete clientMap[clientId];
  }
}

function screenResizedHandler(screen) {
  print("Screen resized (", workspace.displayWidth, ", ", workspace.displayHeight, ")");
 
  var clients = workspace.clientList();
 
  for(var i in clients) {
    var ret = restoreClientGeometry(clients[i]);
   
    if(!ret) {
      updateClientMap(clients[i]);
    }
  }
}

function numScreensChangedHandler(count) {
  print("Number of screens changed ", count);
 
  //var json = JSON.stringify(clientMap, null, 4);
  //print("client Map: ", json);
 
  var clients = workspace.clientList();
 
  for(var i in clients) {   
    var ret = restoreClientGeometry(clients[i]);
   
    if(!ret) {
      updateClientMap(clients[i]);
    }
  }
}

function updateClientMap(client) {
  var clientId   = client.windowId;
  var rectMapKey = new String();

  for(i = 0; i < workspace.numScreens; ++i) {
    var clArea = workspace.clientArea(KWin.FullScreenArea, i, 0);
    rectMapKey += clArea['width'].toString() + clArea['height'].toString();
  }
 
  if(!clientMap[clientId]) {
    clientMap[clientId] = new Object();
  }

  if(clientMap[clientId][rectMapKey]) {
    delete clientMap[clientId][rectMapKey];
  }
 
  print("Storing geometry for client ", client.caption, "[", client.windowId, "] with key ", rectMapKey);
 
  clientMap[clientId][rectMapKey] = new Object();
 
  // Store each geometry parameter
  for(var attr in client.geometry) {
    clientMap[clientId][rectMapKey][attr] = client.geometry[attr];
  }

  // For easier debugging
  clientMap[clientId]['caption'] = client.caption;
}

function restoreClientGeometry(client) {
  var clientId   = client.windowId;
  var rectMapKey = new String();
 
  for(i = 0; i < workspace.numScreens; ++i) {
    var clArea = workspace.clientArea(KWin.FullScreenArea, i, 0);
    rectMapKey += clArea['width'].toString() + clArea['height'].toString();
  }
 
  if(clientMap[clientId][rectMapKey]) {
    client.geometry = clientMap[clientId][rectMapKey];

    print("Moved client ", client.caption, " to ", client.geometry['x'], ", Intended: ", clientMap[clientId][rectMapKey]['x']);
   
    return true;
  }
 
  return false;
}

initialize();

workspace.screenResized.connect(screenResizedHandler);
workspace.numberScreensChanged.connect(numScreensChangedHandler);
workspace.clientAdded.connect(addClient);
workspace.clientRemoved.connect(removeClient);


It is early and this does have some issues. This does not yet do anything to restore panels. It does not yet handle certain types of windows that don't trigger the needed event when moved. On my desktop gkrellm is one of these. Also it records changes in windows by users as well as the position of any new window but a window that is moved without the intervention of the user is not updated in the geometry list. In my case if I use the "Restore Previous Session" in Firefox the window is moved to the location it was in before being closed but the stored geometry for that window is for the position before it got moved. If the user picks the window up and puts it down the new position gets stored.

Another issue is that if I move a window in my desktop resolution and then move it in my gaming resolution the window doesn't make it to exactly where it should be returned to when I switch back to the desktop resolution even though the values I'm applying look correct. If I don't move the window while in the gaming resolution it works fine. This one has me scratching my head a little.

This is my first attempt at kwin scripting. I am a C/C++/Java developer but javascript is quite different from those so that is causing me to work through this a little slower than I would like but I think it is coming along. The kwin scripting has also changed a lot in recent version. I can tell you that much of the API that window pong script uses is removed and it would need some modification to work. There are very few examples, that I can find, of scripts using the new API.

I will continue working on it. In the meantime I am open to any and all suggestions.
Hyper_Eye
Registered Member
Posts
4
Karma
0
I went ahead and restarted KDE and let my script do its thing tonight. For simply switching between the desktop and games that use the full resolution of the left monitor this script is already doing what I need. It turns out gkrellm is getting handled by the script after I restarted the desktop. I'm not sure what made that difference. Obviously if I switch to a game that messes up the taskbar I am going to have to correct that but barring that this is working well. So I will start looking at how I can handle the taskbar soon. I would really like to know why setting geometry on a window doesn't work correctly if it was moved in a different resolution.
karthikp
Registered Member
Posts
109
Karma
0
OS
Awesome work. I'm going to bookmark this for future reference!


karthikp, proud to be a member of KDE forums since 2008.
Image
Hyper_Eye
Registered Member
Posts
4
Karma
0
After using this script for a few days I want to go ahead and document the bugs at this point. I am not really sure how many of these are caused by issues in kwin scripting, which is something that is changing rapidly at the moment I know, and how many are caused by the way I am handling things in the script. I would really like to see what one of the kwin devs thinks. Martin Gräßlin seems to be the guy when it comes to this subject as far as I can tell. The main reason why I am attempting to bring attention to these issues isn't to get someone to complete my script for me. There is very little code that I can find that uses the new kwin scripting API. If my script is exposing bugs or I am having issues due to a lack of pertinent information in the documentation I hope that it can be helpful in resolving them.

What works:

- Storing kwin client positions for a particular combination of screen resolutions and returning the windows to that position if the resolution is changed to something else and then back so long as the windows are not moved while the resolution is changed. This does most of what I need when playing games. When the game starts it causes the resolution to change through an XVidMode or XRandr request. During that time the game is fullscreen and I don't interact with any of the desktop windows. When I quit the game my resolution returns to normal and the windows are where I left them. Note that the script handles resolution changes regardless of the reason so if you push ctrl+alt++ or ctrl+alt+- it will do the same thing it does when you start a game.

Issues:

- If compositing is enabled when the resolution or number of screens changes GTK-based applications will most likely crash when the script attempts to move them. I am using the oxygen-molecule theme applied through the KDE control panel. I do not know yet if the issue is related to this yet. Disabling compositing (shortcut alt+shift+f12) before changing resolutions resolves this issue and I do that before playing games anyway.

- If a window is moved while in a particular resolution the window will not move to the correct position when applying any other stored resolution's geometry data. The windows will move to the correct screen though. I really don't know what is going on with this one. I left some debug prints in my commit so that anyone that wants to look at it can see what I was seeing. That would be that the geometry parameters being applied to the client contain the correct positions for the resolution. By uncommenting the two lines that print the ClientMap object you can even see the geometry for each resolution that is stored for any particular client. You will also see that printing the client's 'geometry.x' position after applying the stored geometry shows the expected value. Still the window ends up in the wrong place.

- If the taskbar changes size after a resolution change it will be returned to the original size when the resolution is changed back but the panels inside will not adjust to the new size. The result of this, in my case, is that I can't see or interact with all of the panels or maybe with only a partial panel.

- The script does not store changes in window geometry if those changes are not a result of user action. So the example I used before is when I restore a session in Firefox and the window gets moved to the position it was in during that session automatically. The position it was in before the automatic move is what is contained in the stored geometry. If I pick the window up and put it back down the new position gets stored. This is certainly due to the event that I am connecting to to detect these changes. It only picks up changes made by the user. I will need to use a different event ultimately but there may be some issues that come with that. I would prefer to leave it alone for now.


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], kde-naveen, Sogou [Bot]