bugGNU Octave - Bugs: bug #56110, Setting figure position is ignored...

 
 

bug #56110: Setting figure position is ignored when set before the figure is drawn

Submitted by:  Lars Kindermann <larskindermann>
Submitted on:  Tue 09 Apr 2019 01:18:06 PM UTC  
 
Category:  Plotting with OpenGL Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Incorrect Result
Status:  Works For Me Assigned to:  None
Originator Name:  Open/Closed:  Open
Release:  dev Operating System:  GNU/Linux

Add a New Comment (Rich Markup)
   

You are not logged in

Please log in, so followups can be emailed to you.

 

( Jump to the original submission)

Sat 13 Apr 2019 10:04:04 PM UTC, comment #17:

I think the system/window-manager dependant behavior may well be explained by a race condition: the creation of Figure objects is synchronous, but not its updates.

When the "position" is changed from the interpreter using "set", the Figure object changes geometry and posts back the actual size it managed to reach. Since that happens asynchronously in the GUI thread, the new graphics event may or may not have already been posted at the time "drawnow" is called from the interpreter thread. IOW sometimes "drawnow" will only find one event in the queue, the one posted during "figure" call, sometimes it will also  find the event posted after "set".

Pantxo Diribarne <pantxo>
Project Member
Fri 12 Apr 2019 03:57:21 PM UTC, comment #16:

I agree that someone needs to test Pantxo's patch from comment #15.  Clearly something is different between our mental model of how the threads are interacting, and the actual behavior.

Rik <rik5>
Project Administrator
Thu 11 Apr 2019 07:08:10 PM UTC, comment #15:

>> Maybe the problem is more that figure() returns control to the interpreter too quickly (on some computers) while the GUI thread is still active preparing the figure.

This should not happen since we enforce synchronous execution using a Qt::BlockingQueuedConnection. For testing, the following diff (also attached as sync_test.diff) should always print: "step 1, 2, 3" after a figure is created

diff -r 34267e66915a libgui/graphics/Backend.cc
--- a/libgui/graphics/Backend.cc        Fri Nov 16 17:57:00 2018 +0100
+++ b/libgui/graphics/Backend.cc        Thu Apr 11 20:57:34 2019 +0200
@@ -111,8 +111,14 @@
         OCTAVE_PTR_TYPE tmp (reinterpret_cast<OCTAVE_INTPTR_TYPE> (proxy));
         gObj.get_properties ().set (toolkitObjectProperty (go), tmp);

+        if (go.isa ("figure"))
+          printf ("step 1, ");
+
         emit createObject (go.get_handle ().value ());

+        if (go.isa ("figure"))
+          printf ("3\n");
+
         return true;
       }

diff -r 34267e66915a libgui/graphics/Figure.cc
--- a/libgui/graphics/Figure.cc Fri Nov 16 17:57:00 2018 +0100
+++ b/libgui/graphics/Figure.cc Thu Apr 11 20:57:34 2019 +0200
@@ -149,6 +149,8 @@

     win->addReceiver (this);
     m_container->addReceiver (this);
+
+    printf ("2, ");
   }

   Figure::~Figure (void)

>> This would be consistent with the fact that pasting the code in to an Octave window works

No, I think that executing the code in the command window is equivalent to calling "gh_manager::process_events" after each line of code.

>> Could someone who can reproduce this try the following code which uses a pause() statement after figure creation to let the graphics system settle out.

Yes, this works since pause is equivalent to "gh_manager::process_events" and thus equivalent to the diff in comment #12

(file #46752)

Pantxo Diribarne <pantxo>
Project Member
Thu 11 Apr 2019 06:45:23 PM UTC, comment #14:

Yes, tst_figpos2 fixes the problem shown with tst_figpos for me.

Mike Miller <mtmiller>
Project Administrator
Thu 11 Apr 2019 04:58:18 PM UTC, comment #13:

I see what you're saying.  Annotated code

f1 = figure();
## When created in the GUI, there may be graphics events that are put in
## to the queue after creation by the GUI thread
pos1 = get(f1,"position")
pos1(1) = pos1(1) + 50;
pos1(2) = pos1(2) - 50;
pos1(3) = pos1(4) * 2
set(f1,"position",pos1) #before drawn
## get/set operations don't cause a queue flush
## So, "position" is now updated pos1, but drawnow is about to fire and
## run the queued event that returns position back to its starting value
drawnow
get(f1,"position")

Maybe the problem is more that figure() returns control to the interpreter too quickly (on some computers) while the GUI thread is still active preparing the figure.  In this scenario, the queued event would actually be flushed, but there simply hasn't been enough time for the GUI to grab a mutex, post the event, etc.  This would be consistent with the fact that pasting the code in to an Octave window works (because there are extra delays with parsing each command), but fails when the same code is in a script (parsed once, and then run as fast as possible).

Could someone who can reproduce this try the following code which uses a pause() statement after figure creation to let the graphics system settle out.

f1 = figure();
pause (0.1);
pos1 = get(f1,"position")
pos1(1) = pos1(1) + 50;
pos1(2) = pos1(2) - 50;
pos1(3) = pos1(4) * 2
set(f1,"position",pos1) #before drawn
drawnow
pos1_after = get(f1,"position")
if (! isequal (pos1, pos1_after))
  warning ("position1 after drawnow is different");
endif

The script is attached as tst_figpos2.m as well.

(file #46749)

Rik <rik5>
Project Administrator
Thu 11 Apr 2019 08:50:22 AM UTC, comment #12:

I am able to reproduce and the root cause is that the Qt Figure object (which lives in the GUI thread) uses the graphics event queue to communicate position changes to the interpreter thread. This means, after the figure is constructed, there is a new event in the queue that will tell the interpreter to fix the position to an eventually new value.

The following simple diff fixes the issue for me

diff -r ca0230d3efbf libgui/graphics/Backend.cc
--- a/libgui/graphics/Backend.cc        Mon Apr 08 09:22:39 2019 -0700
+++ b/libgui/graphics/Backend.cc        Thu Apr 11 10:42:30 2019 +0200
@@ -113,6 +113,10 @@

         emit createObject (go.get_handle ().value ());

+        // We need to process graphics events that have been pushed while
+        // initializing the GUI objects
+        gh_manager::process_events ();
+
         return true;
       }

What I don't understand is why this behavior is not deterministic. IOW I don't see how the graphics event can be executed before drawnow on some systems.

Pantxo Diribarne <pantxo>
Project Member
Tue 09 Apr 2019 11:17:49 PM UTC, comment #11:

I tried gnome/xorg, gnome/wayland/ kde/xorg(?) -- no problem.
This is on Fedora 30, qt5.12.1

Dmitri.

Dmitri A. Sergatskov <dasergatskov>
Tue 09 Apr 2019 10:47:48 PM UTC, comment #10:

Yuck.  This looks hard to debug.  Is there a way to separate whether Octave is calling Qt incorrectly versus whether there is something wrong within Qt?

I checked the positions of figure 1 and 2 after running tst_figpos and they are correctly the same as printing within the script.

I am not using Wayland.  Am using X.Org Xserver with nouveau driver.

Rik <rik5>
Project Administrator
Tue 09 Apr 2019 09:41:40 PM UTC, comment #9:

For my part, I can reproduce Lars' behavior with Octave 5.1 or with the default branch, using Qt 5.11 or 5.12, and running in GNOME 3.30 on Wayland, Qt is using XWayland.

If I force Qt to use Wayland with QT_QPA_PLATFORM=wayland-egl, then the position is reported the same before and after drawnow inside Rik's script, but the actual figure sizes are not correct after the script returns to the prompt.

>> tst_figpos
pos1 =

   300   200   560   420

pos1 =

   350   150   840   420

pos1_after =

   350   150   840   420

pos2 =

   300   200   560   420

pos2 =

   350   150   840   420

pos2_after =

   350   150   840   420

>> get (f1, "position")
ans =

   350   150   560   420

>> get (f2, "position")
ans =

   350   150   560   420

Mike Miller <mtmiller>
Project Administrator
Tue 09 Apr 2019 07:31:28 PM UTC, comment #8:

I'm using Kubuntu 18.04 so KDE as the window manager and Qt-5.9.5 for the libraries.

Could be something that has been fixed since 4/2016 in Lars' case.

Rik <rik5>
Project Administrator
Tue 09 Apr 2019 06:31:13 PM UTC, comment #7:

I'm also using GNOME (version 3.30) with default window placement rules.

Mike Miller <mtmiller>
Project Administrator
Tue 09 Apr 2019 05:47:50 PM UTC, comment #6:

I wonder if this is windows manager trying to do some kind of
"smart window placement"...
In any case I do not get this problem on Fedora 30 / gnome desktop.

Dmitri.
--

Dmitri A. Sergatskov <dasergatskov>
Tue 09 Apr 2019 05:11:56 PM UTC, comment #5:

I get the same results as Lars.

Mike Miller <mtmiller>
Project Administrator
Tue 09 Apr 2019 04:40:59 PM UTC, comment #4:

It only happens with "graphics_toolkit qt". fltk works fine, gnuplot has no warning but different windows, but I think that's expected. I'm building against Qt 5.5.1.

Lars Kindermann <larskindermann>
Tue 09 Apr 2019 04:24:28 PM UTC, comment #3:

Running your script on my system (Xubuntu 16.04) both with "run-octave -f" and "run-octave -f --gui" still yields

>> tst_figpos

pos1 =

   300   200   560   420

pos1 =

   350   150   840   420

pos1_after =

   300   200   560   418

warning: position1 after drawnow is different
warning: called from
    tst_figpos at line 10 column 3
pos2 =

   300   200   560   420

pos2 =

   350   150   840   420

pos2_after =

   350   150   840   420

>>

Lars Kindermann <larskindermann>
Tue 09 Apr 2019 04:00:21 PM UTC, comment #2:

Works for me.  I'm attaching your commands as a script for others to try.  I added a check that the positions are the same so that tester's don't have to manually scan the results.

I used

run-octave -f --gui

as well as

run-octave -f

to test GUI and CLI versions and both worked.

(file #46740)

Rik <rik5>
Project Administrator
Tue 09 Apr 2019 02:20:19 PM UTC, comment #1:

The code below works fine if you paste it into the command window, the problem appears only if run as a script.

Lars Kindermann <larskindermann>
Tue 09 Apr 2019 01:18:06 PM UTC, original submission:

These two figures should have the same size and position, regardless when they are drawn:

f1 = figure();
pos1 = get(f1,"position")
pos1(1) = pos1(1) + 50;
pos1(2) = pos1(2) - 50;
pos1(3) = pos1(4) * 2
set(f1,"position",pos1) #before drawn
drawnow
get(f1,"position")

f2 = figure();
pos2 = get(f2,"position")
pos2(1) = pos2(1) + 50;
pos2(2) = pos2(2) - 50;
pos2(3) = pos2(4) * 2
drawnow
set(f2,"position",pos2) #after drawn
get(f2,"position")

but the position of the first figure is changed back by drawnow (and even not exactly to the initial settings):

pos1 = 300   200   560   420
pos1 = 350   150   840   420
ans  = 300   200   560   418

pos2 = 300   200   560   420
pos2 = 350   150   840   420
ans  = 350   150   840   420

As far as I remember, Matlab always behaves like the second example. Maybe somebody could check this...

Lars Kindermann <larskindermann>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #46752:  sync_test.diff added by pantxo (1KiB - text/x-patch)
file #46749:  tst_figpos2.m added by rik5 (294B - text/x-matlab)
file #46740:  tst_figpos.m added by rik5 (562B - text/x-matlab)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by pantxo (Posted a comment)
  • -email is unavailable- added by dasergatskov (Posted a comment)
  • -email is unavailable- added by rik5 (Updated the item)
  • -email is unavailable- added by larskindermann (Submitted the item)
  •  

    Do you think this task is very important?
    If so, you can add your encouragement to it.
    This task has 0 encouragements so far.

    Only project members can vote.

     

     

     

    Follow 5 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2019-04-11 pantxo Attached File- => Added sync_test.diff, #46752
    2019-04-11 rik5 Attached File- => Added tst_figpos2.m, #46749
    2019-04-09 mtmiller CategoryPlotting => Plotting with OpenGL
    2019-04-09 rik5 Attached File- => Added tst_figpos.m, #46740
        StatusNone => Works For Me

    Back to the top


    Powered by Savane 3.4