s-victor / TinyPedal

Free and Open Source telemetry overlay application for racing simulation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Windows - Config at wrong position after restart

DanRZ opened this issue · comments

When restarting TinyPedal the config UI don't go to the last position.
In dual screen, before Quit :
BeforeQuit
And after restart :
Restart
The Config seems to be stuck on limits of Display 1.

The app.py load_window_position function is probably limiting the position loaded.

Discussion on S397 Forum :
https://forum.studio-397.com/index.php?threads/tinypedal-open-source-overlay-app-for-rf2-radar-pedal-ffb-deltabest-relative-fuel-calculator.71557/page-28#post-1138583

Hi, I have just added a new verify_window_position function in this commit e69c194 .

The idea is that the screen() returns the screen where the main window is located. So we just call this function after load_window_position function is executed and window is moved to last saved position, so it should be able to identify the correct screen number and get correct screen size (using geometry() function) & position related to the screen, and correct position only if any off screen happens.

Please test and let me know if it works, thanks!

Ok, i will try.
I have made some search and i think you should use virtualSize or other functions linked to virtual screen.
It looks like you want the Config UI to never get out of the screen 1 but i may want it on any other screen or even between two screens.
The virtual size gives you width and size of the largest "virtual screen" that would embed all of the screen.
I joined an image.
Under linux it's probably identical.
multimon-1.png

Thanks for the reply.

There was some misunderstanding, the v2.5.3 fix was never intended to limit main window on screen 1, but it just happened to end up that way, because screen() function only sees where the main window is currently located on.

With the latest commit, I think the issue should be solved. As we call screen() function only after move() function was done, and then calling both x() y() function will get the moved position and verify with screen().geometry() value.

I will try this version properly with my dual screen tomorrow.
But i think i will still have the same limitation to Monitor 1 after restart.

I don't understand the need of function :

verify_window_position(self):
         """Verify window position"""
         # Get screen size from the screen where app window located
         screen_geo = self.screen().geometry()
         # Limiting position value if out of screen range
         app_pos_x = min(
             max(self.x(), screen_geo.left()),
             screen_geo.right() - self.sizeHint().width())
         app_pos_y = min(
             max(self.y(), screen_geo.top()),
             screen_geo.bottom() - self.sizeHint().height())
         # Re-adjust position only if mismatched
         if self.x() != app_pos_x or self.y() != app_pos_y:
             self.move(app_pos_x, app_pos_y)
             logger.info("GUI: auto corrected window position")
# Limiting position value if out of screen range

With the code next to this quote you will always restrain the Config Window in Monitor 1.

On my dual screen one next to other in line, two screens of 1600 pixel wide, i think my Config was at 2400 on position_x.
With the max check, you will always save position_x less than 1600 and lose my position_x in Monitor 3.

I just think you don't need to check borders at all.
Moved by the mouse, you will always be in a real screen inside "virtual screen".
See virtual screen image, if monitor 1 is 1600 pixel wide, a position_x higher than 1600 will be in monitor 3.
Monitor 2 will be at position_x negatives.

screen_geo seems to be always Monitor 1 and never 2 or 3 because its the one which defines 0,0 coordinates.

I think there is no need at all to use verify_window_position.

The only use of that would be for a user editing json values and setting them manually outside virtual screen by error.
The verify_window_position will get it back automatically on Monitor 1.
Also when Monitor 2 or 3 may be disconnected.

And in my first screenshots i noticed an error of 20 pixels (Overlap)
image
that is probably linked to code in config.py.

self.setMinimumWidth(self.sizeHint().width() + 20)

so the code in app.py must be :

         app_pos_x = min(
            max(self.x(), screen_geo.left()),
            screen_geo.right() - ( self.sizeHint().width() + 20 )

and you will get Config just right on the right border and not overlapping screen 2 on the right.

Hi, it seems that you are misunderstanding the issue from beginning.

I'll try rephrase the problem:
Before v2.5.3, there was not any restriction to X, Y position (as you mentioned that you think verify_window_position function is not needed), which those older version(without position restriction) prior to v2.5.3 was working fine on your system as well as to 99.9% user.

Then, about 2 weeks ago, user Capeta reported to me that he could not see main window (again, that was before v2.5.3). So I helped him to try to identify the cause of the issue. And later on, he mentioned to me that he has been running a new 2nd monitor recently, which at the same time main window starting to disappearing. So immediately I told him to check if either position_x or position_y shows negative value in JSON. And it turned out that position_x value did became something like -9000. So on next launch, the main window was moved to -9000 position, hence he cannot see it.

As you would notice now, this negative position issue is a special case, as it never happened to you or anyone else. Hence I have made some assumption about what could be the cause of this issue. Since I do not have 2nd screen, all I could do at the time was to add a hard restrict to x,y values in v2.5.3 update, to make sure they stay within whatever the screen was first detected. And restricting on screen 1 issue is a side effect of this new fix.

With above mentioned reasons, all those new fix attempts since v2.5.3 update are meant for fixing the negative position issue that only happens in certain condition(currently unknown and only reproduced by Capeta). Hence you may probably think those code would seem pointless, as they are only for user that have the negative position issue.

But if I do not add those code, then main window will be disappearing for some multi-screen user like Capeta due to unknown reasons (and they will not be able to use the APP).

So what's really need to fix:

  1. Fix the -9000 issue that user Capeta was having, by restricting on screen method or other means. However it probably be difficult to reproduce, and without way to reproduce, we can only guess what will happen or work.
  2. Fix restricting on screen 1 issue which is caused by fixing -9000 issue if using restricting on screen method.

Lemme know if you have more questions about this negative position issue (or may be contacting Capeta for clarifying what was happening).


Lastly, I think your suggestion with screen().virtualSize() function could be worth trying on your side. Thanks.

ps: there are also two things we could do to solve both negative position issue and its side effect restricting on screen 1:

  1. Only make sure x, y vale is positive, so it will not forcing window on first screen. However I do not know whether if multi-screen size(or virtualSize) can go negative or not.
  2. Add a "confined_main_window_on_screen" in Compatibility dialog, which user can disable the forced position check (at user's own decision).

Sorry, i know why we misunderstand each other.
You are trying to solve a user mistake.

Negatives values are not errors.
It may be a user having 3 monitors like in the image i posted on "virtual screen" and having set the Config UI in monitor 3. And then he removes the Monitor3.

In this case TinyPedal can't do much to solve the hardware modification of the PC.

Maybe use a new function like "Reset Config position" and use your new code only in this case when user ask it because he lost the Config UI.

Thanks, it's a good suggestion.

Before we try to add a "reset position" entry in tray menu, can you test & print self.screen().virtualSize() function to see if it really outputs the entire desktop area size of all connected monitors?

Since I'm on single monitor, geometry() gives me PySide2.QtCore.QRect(0, 0, 1920, 1080), and
virtualSize() gives me PySide2.QtCore.QSize(1920, 1080) reading.

If virtualSize() does output entire desktop area size of all monitors, then may be we can save this virtualSize value in JSON, and then verify this value on next launch. If the saved value matches virtualSize() reading, we can be sure that there is no changes to number of connected monitors, and no need to reset position. Otherwise, we can trigger reset position function.

Lemme know your opinion, thanks.


edit: there is also a screens() function from QGuiApplication class that lists all connected monitors, which may also be used for checking whether there are changes to monitor setup.

I will try the virtual size with a few configurations of my 2 screens, like Left/Right Up/Down, etc. and mixed orders. And we can also put them in diagonal ... There is a lot of possibilities.

I already added some logger.info to better see what is happening.

VirtualSize will help finding the total size but won't help on checking coordinates.

You surely need a different test to find when Config is out of screens and react automatically with the verify function.

How can i activate logs in the executable version ?
I only can see logs when i use run.py. And not the tinypedal.exe.

To activate log in executable, you need to edit tinypedal/__init__.py file, remove sys.stdout argument from StreamHandler().
(ps: I've thought about adding argument support to toggle or change logging output for executable, but haven't yet done and is not priority.)


Also I just did some search, and one source seems described a similar situation of negative X position.

What happens:

  1. 2 monitors: monitor A and monitor B.
  2. Monitor A is the primary monitor and is physically placed on the right side of monitor B.
  3. Monitor B is the extended monitor from Monitor A, and placed on the left side of monitor B.
  4. The 0,0 position is referenced from primary monitor (A in this case).

And since monitor B is on the left side of A, calling x() function when window is on monitor B will return negative value because monitor B is on the left side of 0,0 position of primary monitor A. So this probably explained why negative position value happens to the other user. Though it still doesn't explain why next launch will put the window off screen (unless like you said that monitors may be disconnected or has their order swapped).

Here are the tests i have made ( using sys.stderr ... Modifying init didn't work ).

I used the last commit : 4f251f4
And i only modified ui/app.py ( Diff : app.py.diff.txt
You can "git apply app.py.diff.txt" in the ui folder to get the code i used ...

tinypedal_tests_dual_screen.zip

You have screenshots of the display, and tinypedal.log.

Each time i resetted tinipedal to a center position in Monitor 1 before first start
then moved to center of Monitor 2, and quit, and restart.

Good news is the code works properly and i always got my Config where i left it !!!

You have some logs of coordinates, and results of "virtual size".

My Monitor 1 is 1920 x 1080 and my Monitor 2 is 1680 x 1050 (Slightly less pixels).

In horizontal mode :
Virtual size : width = 1920 + 1680 = 3600
Virtual size : height = max of 1080 and 1050 > 1080

In vertical mode :
Virtual size : width = max of 1920 and 1050 > 1920
Virtual size : height = 1080 + 1050 = 2130

You can see negatives coordinates when Monitor 2 is "up" or "left" Monitor 1.
Monitor 1 is always the one having the 0, 0 in the left up corner.
Thats what you get in the sreen_geo, and will always get that Monitor 1, i think.

I definitely think the verify function is useless, but you need to offer a "Reset config position"
in order to make sure user having issues, or who made some modification and don't remember it, like 3 months before,
able to get back the Config UI in Monitor 1 by one click.

Monitor 1 is always available. It would be too complex to save all config and monitors, to "verify" if Config is not visible anymore.
Using only Monitor 1 is not a good solution to "verify".

As i said earlier, good new is the code is working and i don't lose my config anymore using this commit version.

Maybe i didn't understand well the code.
I still have a doubt with screen_geo, which for me is always Monitor 1 "alone".
But your code works and there is something i probably didn't understand well.

Anyway, Nice work ;)

Hi, thanks for the file & fix.

And sorry I made a mistake about the logging to file thing. I have just rewritten the logging & handler code, and added supports for setting log level using command line. You can find changes in this commit 878bc17 .

Example of the new optional command line argument usage(I haven't tested with executable, but it should work too):
python .\run.py --log-level=1 this will output log to console only.
python .\run.py --log-level=2 this will output log to both console & tinypedal.log file in tinypedal folder.
And --log-level=0 will output nothing. Of course there are still stuff can be improved later.

Meanwhile, I'll be testing your new files and get back to you.

Thanks again for your detailed testing feedback which helps greatly. Here is some feedback:

I have read your logs & pictures and comments, and it seems the verification does work as you have described as well as shown in logs.

Also I think screen_geo (the screen().geometry() function) is working correctly for reasons below:

As according to this document , screen() returns the screen that APP window is current shown on.

And in your tests, when APP initially launched, main window was first moved to the last saved position, which was moved from primary Monitor 1 to Monitor 2.

And then screen().geometry() function was executed in verify_window_position(), which I believe screen_geo did output screen value from Monitor 2 (but its not added in logging so I have to guess).

The reason for this assumption is based on your 2_Left_1_Right.png & 1_Down_2_Up.png tests, which both tests have window located at negative position. Since primary monitor(Monitor 1) coordinates always starts at 0,0 position, if screen().geometry() reads Monitor 1's value (which is QRect at 0, 0, 1920, 1080), then it will surely force any negative value back to positive, but it was not the case. As the test results show that negative value is not changed back to positive, so screen_geo must be outputting value from Monitor 2. I would assume if you print screen_geo value, it would show QRect at -1680, 0, 1680, 1050. (QRect value is x, y, width, height)

And I agree that it is still worthwhile to add an option in tray menu to reset main window just in case if verification fails. I'll try add one tomorrow.

I will add some logs to show the coordinates of screen_geo and we will be fixed on the ID of Monitor, which as you said is the one where the Config UI is ... But what if the Config UI is out ?
I will also try with coordinates totally outside of the virtual screen and see what happens.

So as you said if there is a situation that main window is placed outside of either monitor 1 or 2 (totally outside of virtual screen), then the main window will definitely be auto-moved back to screen area on either monitor 1 or 2 (this is exactly verify_window_position function made for). And it really doesn't matter which monitor QRect coordinates value would screen_geo return, because neither monitors is going to show the window in the first place, so whether main window will be moved back to screen 1 or screen 2 will not matter.

I have made some tests, and i can confirm that screen_geo is the Monitor where the Config UI is or Monitor 1 if outside all of Monitors, as you said earlier. I was wrong.

When "verify" see an error it will always get back to Monitor 1.

I only see a sort of error, when the Config UI is send back to Monitor 1.
There is an error of 20 pixel on the x and the y is to low i think.
It looks like you want all the Config UI to be seen in Monitor 1
but it is not the case ... Not a big issue, by the way.

Here is an example :
Capture
Monitor 1 is where the Windows bar is slightly lower on the left part.
And we can see a bit of the Monitor 2 on right.

The cross in top right is "half" outside Monitor 1, and the height should be higher.
We can't see the bottom of the Config UI.

Thanks for the testing & feedback.

The partially off screen after correction should be expected behavior. Since window size is changeable depends on user, and it also gives some extra small room for user to place window & still be able to see the window.

ok, I added 2 new constants to completely restrict window inside screen area after auto-correction is done, in commit 33c25db

This should sort out the issue you have mentioned. Although the down side is that main window will never be able to stay in the middle area in-between 2 monitors (as expected) after re-launching.

edit: just added a new Show log option in Help menu, log can now be viewed from this new dialog.

Ok. Now you can probably add these parameters in the settings, and maybe some kind of boolean to allow overlapping on screens or not.

Nice addon about the logs.

I realize it can be useful to keep that overlap.
Don't be too influenced by my needs.
Your last version was already good and correct the issue i created.
I think i can close this issue.

To be honest i am an old developper, with more than 20 years of experience, but not in GUI or "applications" and i can tell the quality of what you've done.

Bravo, well done ;)

Awesome, thank you again for the help, and for sharing ideas and knowledge. I'm far less experienced with programming (and still learning), and it is great to have you and other experienced developer helping make the APP better.

And good suggestion with the toggle-able overlapping feature, I'll probably add it to Compatibility dialog later, will need to see how it works first. There are also a few new widgets ideas that I'm planning to do next.