Merge lp://qastaging/~vanvugt/compiz/fix-980663-1041066 into lp://qastaging/compiz/0.9.8

Proposed by Daniel van Vugt
Status: Superseded
Proposed branch: lp://qastaging/~vanvugt/compiz/fix-980663-1041066
Merge into: lp://qastaging/compiz/0.9.8
Diff against target: 331 lines (+234/-17)
6 files modified
plugins/opengl/CMakeLists.txt (+1/-0)
plugins/opengl/src/fsregion.cpp (+54/-0)
plugins/opengl/src/fsregion.h (+49/-0)
plugins/opengl/src/paint.cpp (+10/-17)
plugins/opengl/src/tests/CMakeLists.txt (+7/-0)
plugins/opengl/src/tests/test-fsregion.cpp (+113/-0)
To merge this branch: bzr merge lp://qastaging/~vanvugt/compiz/fix-980663-1041066
Reviewer Review Type Date Requested Status
Sam Spilsbury Pending
Review via email: mp+122205@code.qastaging.launchpad.net

This proposal supersedes a proposal from 2012-08-29.

This proposal has been superseded by a proposal from 2012-09-04.

Description of the change

Make "Unredirect Fullscreen Windows" more reliable. This fixes the problem
with unredirection failing to engage at all (LP: #1041066) when
gtk-window-decorator creates offscreen windows that are stacked on top.
This also fixes the problem with unredirect hiding all windows,
because it thinks the desktop window should be stacked on top (LP: #980663).

Unfortunately, both issues are so tightly coupled that they can only really
be fixed and tested together.

To post a comment you must log in.
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Seems to work perfectly. But on hold until I figure out if automated testing is possible for this right now, without making the code totally unmaintainable...

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal
Download full text (4.7 KiB)

115 +/*
116 + * Why mock locally? Because...
117 + * 1. Code is cleaner without typecasts, so we need to ensure that
118 + * Output::Window is-a CompWindow when not mocking.
119 + * 2. No polymorphism is required = fewer classes, less code, easier to follow.
120 + */
121 +#ifdef OUTPUTWINDOW
122 +class MockCompWindow
123 +{
124 +public:
125 + MockCompWindow (unsigned int type, int x, int y, int width, int height) :
126 + flags (type), reg (x, y, width, height) {}
127 + unsigned int type () const { return flags; }
128 + const CompRegion &region () const { return reg; }
129 +
130 +private:
131 + unsigned int flags;
132 + CompRegion reg;
133 +};
134 +#else
135 +#define OUTPUTWINDOW CompWindow
136 +#endif

Yeah, I disagree with this :)

1. It relies on a define for the code to compile the right way
   a. (Unity has code that does this and its not nice to work with)
2. Ifdefs make the code harder to follow in general. The code is doing two different things depending on how it was compiled. This could introduce subtle gotchas.
3. This code is relying on an implicit interface (eg, what the caller is doing with CompWindow). This means that
   when it breaks, it will be non-obvious as to why (eg, instead of being told that MockCompWindow does not
   implement the interface, you get a normal compile error saying that certain functions don't exist on this object
   that #defines itself into existence at compile time).
4. The Window definition conflicts with the Xlib one.

If you don't want to use an interface class (this is a point I agree on), here are some alternatives:

 a. Output::occlude is only really interested in three things from CompWindow, firstly whether or not it can take focus (I will deal with this later), and secondly a means to get a CompositeWindow and thirdly its covering region. You can do something like this:

 typedef enum _FocusableState
 {
     CanTakeFocus = 0,
     NoFocusAllowed = 1
 } FocusableState;

 //
 Output::occlude (FocusableState focusState,
                  CompRegion const & reg,
                  Window win) // Using Window in terms of its XLib meaning here ...
 {
57 +
58 + if (!fullscreen &&
              focusState == CanTakeFocus && // Skip desktop etc
60 + reg == untouched)
61 + {
62 + fullscreen = win;
63 + }
64 + untouched -= reg;
 }

Window
Output::fullscreenWindow ()
{
    return Window;
}

// not under test
FocusableState
compiz::opengl::WindowTypeToFocusableState (CompWindow *window)
{
    if (window->type () & NO_FOCUS_MASK)
        return NoFocusAllowed;

    return CanTakeFocus;
}

Use the code like this:

FocusableState focusState = WindowTypeToFocusableState (window);
output.occlude (focusState, window->id (), window->region ());

Window fullscreenWindow = output.fullscreenWindow ();
CompWindow *fullscreenCompWindow = screen->findWindow (fullscreenWindow);
CompositeWindow *compositeFullscreenWindow = CompositeWindow::get (fullscreenCompWindow);

compositeFullscreenWindow->unredirect ();

I personally don't like using the Xlib Window handle as a means to identify windows within compiz, and would personally prefer that compiz::opengl::Output used an interface like RedirectedWindow (with metho...

Read more...

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Actually, I thought of all of that already and disagree with almost all of it :)

I'll try to find a nicer way to hide and clean up the mocking. However changing a class' public interface is usually a mistake. Test cases can change how you do your implementation, but should never change the interfaces.

I'm not using compiz_discover_tests because I hate the fact that it necessitates excessively deep directories (plugins/NAME/src/LIBNAME/src/stuff.cpp). Also, what does compiz_discover_tests give me if I need to create more files, directories and complexity to use it?

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Also, test-output is in a namespace already by virtue of its directory:
build/plugins/opengl/src/tests/test-output

However I will rename it internally at least so you can tell what and where it is just from the CTest output.

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Clean-ups all round.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal
Download full text (3.2 KiB)

"Actually, I thought of all of that already and disagree with almost all of it :)"

Could you elaborate? I didn't say that you needed to change any public interfaces.

This is still very confusing:

380 +#ifdef MOCK_COMPWINDOW
381 + typedef Stackable Window;
382 +#else
383 + typedef CompWindow Window;
384 +#endif

The code is compiled twice, and you have an abstract base class in one version and a concrete class in another. What this essentially is, is a template implemented in terms of #define.

If you're going to create an abstract base class, why not just go all the way and make PrivateGLWindow inherit Stackable, put a redirect method in Stackable and make it call through to PrivateGLWindow? That way you don't need to rely on a define, and you only need to compile this code once.

96 +include_directories(${GTEST_INCLUDE_DIRS} ..)
97 +add_definitions(-DMOCK_COMPWINDOW)
98 +set(exe "compiz_opengl_test_windowstack")
99 +add_executable(${exe} test-windowstack.cpp ../windowstack.cpp)
100 +target_link_libraries(${exe} compiz_core ${GTEST_BOTH_LIBRARIES})
101 +add_test(OpenGLWindowStackTests ${exe})

"I'm not using compiz_discover_tests because I hate the fact that it necessitates excessively deep directories (plugins/NAME/src/LIBNAME/src/stuff.cpp). Also, what does compiz_discover_tests give me if I need to create more files, directories and complexity to use it?"

It doesn't necessitate that at all. The tests are only organized that way because this is the way I happened to organize them. (Also, when in doubt, its a good idea to be consistent rather than go against the grain - I'm happy to change the organization if we can agree on a better way).

Here's the syntax for compiz_discover_tests.

compiz_discover_tests (test_executable COVERAGE library_that_the_test_uses_1 library_2 ...)

The coverage argument is optional, but does require that the tested code goes into a separate library (which you should do anyways because currently the code is compiled twice, which is the exact problem that unity has which I am trying to avoid).

I strongly recommend using this function. It has the following purposes:

1. It adds every individual test to the CTest manifest, meaning that you always have a perfectly clean environment on setup and teardown (defend against subtle bugs where tests are stateful and rely on each other when they shouldn't).
2. You have per-test resolution when something fails from "make test"
3. Its the best way to get your code added to the coverage report, so that you can see if your tests are actually excersizing the code all round. (You can add to the coverage report yourself, however that's several hundred lines of CMake code).

Another good reason:
4. If someone else adds a test using compiz_discover_tests there is a race in CMake where the CTestFile for this test will be clobbered.

"WindowStack" also feels weird. Its not a window stack - its a class that accumulates uncovered screen regions to determine which windows are not occluded. Also "stackable" in the namespace compiz::opengl feels weird too. Its not a "stackable", in compiz terms "stackable" means something more like a window that sits in a stack and can be re-arranged. I...

Read more...

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

I apologize if I seem ... opinionated, I'm just trying to distill what the intention is and the best way of effecting that intention

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

Looking much better without the #define.

I think that Output can take the X11 definition of a "Window" (eg, typedef unsigned int Window) rather than using void *, it means the same thing in both instances and makes the code slightly more clear as to what is being used to identify the window. There's no need to link to xlib for this, all there is a header dependency on <X11/Xlib.h>

Now that Output is taking references to the data that it needs to use to identify which window is on top, there's not much need for MockCompWindow anymore. The boolean parameter in Output can be changed to an enum, eg

typedef enum _FocusAllowedState
{
    NoFocusAllowed,
    FocusAllowed
}

Output::occlude (FocusAllowed, region, window) is more expressive than Output::occlude (true, region, window).

Finally, it would be good if output.cpp was a static library that was linked into opengl. I've tried to avoid setting the trend of compiling any source file more than once in the tree (like Unity does), and would like to keep the source tree this way.

compiz_discover_tests(${exe})

If you are using another static library, you can create coverage targets as so

compiz_discover_tests(${exe} COVERAGE compiz_opengl_output_occlusion_detection)

That will ensure that you can get coverage reports from "make coverage"

The preferred method of addressing source files in a cmake tree is this:

${CMAKE_CURRENT_SOURCE_DIR}/../file.cpp not ../file.cpp

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

If possible by the way, see if you can find a better name for "Output". I still think there's some confusion between "Output" and "CompOutput" - the responsibility of this class seems to be finding a fullscreen window to unredirect based on which windows are not occluded.

I did mention it before, but I find that difficulty in finding a name for a class might indicate that its doing too many unrelated things. In this case, the class is checking for a window to unredirect and then offering a way to get the result. Perhaps it would be better if it stored an interface by which the window could be unredirected and then provided a method to call into the class to unredirect the saved fullscreen window. That way the class could be called "UnoccludedWindowUnredirector". Yes I know you don't like -er, but this is still a noun.

3338. By Daniel van Vugt

Merge latest lp:compiz

3339. By Daniel van Vugt

Remove headers no longer required.

3340. By Daniel van Vugt

Another attempt at renaming. Today it's called "FullscreenRegion".

3341. By Daniel van Vugt

Simplified. Merged addToBottom() and fullscreenWindow() into occlude()

3342. By Daniel van Vugt

Rename occlude() to a more descriptive "isCoveredBy()".

3343. By Daniel van Vugt

Add more tests and fix some search/replace mistakes in test-fsregion.cpp

3344. By Daniel van Vugt

Less bool, more enum. At Sam's request.

3345. By Daniel van Vugt

Massage into a form that survey suggests 9 out of 10 smspillaz' prefer.

3346. By Daniel van Vugt

Building of tests is conditional, apparently. This fixes a Jenkins failure.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
The diff is not available at this time. You can reload the page or download it.

Subscribers

People subscribed via source and target branches