diff options
Diffstat (limited to 'doc/how-constraints-works.txt')
-rw-r--r-- | doc/how-constraints-works.txt | 283 |
1 files changed, 0 insertions, 283 deletions
diff --git a/doc/how-constraints-works.txt b/doc/how-constraints-works.txt deleted file mode 100644 index 327e5fe8..00000000 --- a/doc/how-constraints-works.txt +++ /dev/null @@ -1,283 +0,0 @@ -File contents: - Basic Ideas - Important points to remember - Explanation of fields in the ConstraintInfo struct - Gory details of resize_gravity vs. fixed_directions - -IMPORTANT NOTE: There's a big comment at the top of constraints.c -explaining how to add extra constraints or tweak others. Read it. I put -that information there because it may be enough information by itself for -people to hack on constraints.c. I won't duplicate that information in -this file; this file is for deeper details. - - ---------------------------------------------------------------------------- -Basic Ideas ---------------------------------------------------------------------------- -There are a couple basic ideas behind how this constraints.c code works and -why it works that way: - - 1) Split the low-level error-prone operations into a special file - 2) Add robustness by prioritizing constraints - 3) Make use of a minimal spanning set of rectangles for the - "onscreen region" (screen minus struts). - 4) Constraints can be user-action vs app-action oriented - 5) Avoid over-complification ;-) - -Some more details explaining these basic ideas: - - 1) Split tedious operations out - - boxes.[ch] have been added which contain many common, tedious, and - error-prone operations. I find that this separation helps a lot for - managing the complexity and ensuring that things work correctly. - Also, note that testboxes.c thoroughly tests all functionality in - boxes.[ch] and a testboxes program is automatically compiled. - - Note that functions have also been added to this file to handle some - of the tedium necessary for edge resistance as well. - - 2) Prioritize constraints - - In the old code, if each and every constraint could not be - simultaneously satisfied, then it would result in some - difficult-to-predict set of constraints being violated. This was - because constraints were applied in order, with the possibility for - each making changes that violated previous constraints, with no - checking done at the end. - - Now, all constraints have an associated priority, defined in the - ConstraintPriority enum near the top of constraints.c. The - constraints are all applied, and then are all checked; if not all are - satisfied then the least important constraints are dropped and the - process is repeated. This ensures that the most important constraints - are satisfied. - - A special note to make here is that if any one given constraint is - impossible to satisfy even individually (e.g. if minimum size hints - specify a larger window than the screen size, making the - fully-onscreen constraint impossible to satisfy) then we treat the - constraint as being satisfied. This sounds counter-intuitive, but the - idea is that we want to satisfy as many constraints as possible and if - we treat it as a violation then all constraints with a lesser priority - also get dropped along with the impossible to satisfy one. - - 3) Using maximal/spanning rectangles - - The constraints rely heavily on something I call spanning rectangles - (which Soeren referred to as maximal rectangles, a name which I think - I like better but I don't want to go change all the code now). These - spanning rectangles have the property that a window will fit on the - screen if and only if it fits within at least one of the rectangles. - Soeren had an alternative way of describing these rectangles, namely - that they were rectangles with the property that if you made any of - them larger in any direction, they would overlap with struts or be - offscreen (with the implicit assumption that there are enough of these - rectangles that combined they cover all relevant parts of the screen). - Note that, by necessity, these spanning/maximal rectangles will often - overlap each other. - - Such a list makes it relatively easy to define operations like - window-is-onscreen or clamp-window-to-region or - shove-window-into-region. Since we have a on-single-xinerama - constraint in addition to the onscreen constraint(s), we cache - number_xineramas + 1 of these lists in the workspace. These lists - then only need to be updated whenever the workarea is (e.g. when strut - list change or screen or xinerama size changes). - - 4) Constraints can be user-action vs app-action oriented - - Such differentiation requires special care for the constraints to be - consistent; e.g. if the user does something and one constraint - applies, then the app does something you have to be careful that the - constraint on the app action doesn't result in some jarring motion. - - In particular, the constraints currently allow offscreen movement or - resizing for user actions only. The way consistency is handled is - that at the end of the constraints, update_onscreen_requirements() - checks to see if the window is offscreen or split across xineramas and - updates window->require_fully_onscreen and - window->require_on_single_xinerama appropriately. - - 5) Avoid over-complification - - The previous code tried to reform the constraints into terms of a - single variable. This made the code rather difficult to - understand. ("This is a rather complicated fix for an obscure bug - that happened when resizing a window and encountering a constraint - such as the top edge of the screen.") It also failed, even on the - very example for which it used as justification for the complexity - (bug 312104 -- when keyboard resizing the top of the window, - Metacity extends the bottom once the titlebar hits the top panel), - though the reason why it failed is somewhat mysterious as it should - have worked. Further, it didn't really reform the constraints in - terms of a single variable -- there was both an x_move_delta and an - x_resize_delta, and the existence of both caused bug 109553 - (gravity with simultaneous move and resize doesn't work) - - ---------------------------------------------------------------------------- -Important points to remember ---------------------------------------------------------------------------- - - - Inner vs Outer window - - Note that because of how configure requests work and - meta_window_move_resize_internal() and friends are set up, that the - rectangles passed to meta_window_constrain() are with respect to inner - window positions instead of outer window positions (meaning that window - manager decorations are not included in the position/size). For the - constraints that need to be enforced with respect to outer window - positions, you'll need to make use of the extend_by_frame() and - unextend_by_frame() functions. - - - meta_window_move_resize_internal() accepts a really hairy set of - inputs. See the huge comment at the beginning of that function. - constraints gets screwed up if that function can't sanitize the input, - so be very careful about that. It used to be pretty busted. - - ---------------------------------------------------------------------------- -Explanation of fields in the ConstraintInfo strut ---------------------------------------------------------------------------- - -As of the time of this writing, ConstraintInfo had the following fields: - orig - current - fgeom - action_type - is_user_action - resize_gravity - fixed_directions - work_area_xinerama - entire_xinerama - usable_screen_region - usable_xinerama_region - -A brief description of each and/or pointers to more information are found -below: - orig - The previous position and size of the window, ignoring any window - decorations - current - The requested position and size of the window, ignoring any window - decorations. This rectangle gets modified by the various constraints - to specify the allowed position closest to the requested position. - fgeom - The geometry of the window frame (i.e. "decorations"), if it exists. - Otherwise, it's a dummy 0-size frame for convenience (i.e. this pointer - is guaranteed to be non-NULL so you don't have to do the stupid check). - action_type - Whether the action being constrained is a move, resize, or a combined - move and resize. Some constraints can run faster with this information - (e.g. constraining size increment hints or min size hints don't need to - do anything for pure move operations). This may also be used for - providing slightly different behavior (e.g. clip-to-region instead of - shove-into-region for resize vs. moving operations), but doesn't - currently have a lot of use for this. - is_user_action - Used to determine whether the action being constrained is a user - action. If so, certain parts of the constraint may be relaxed. Note - that this requires care to get right; see item 4 of the basic ideas - section for more details. - resize_gravity - The gravity used in the resize operation, used in order to make sure - windows are resized correctly if constraints specify that their size - must be modified. Explained further in the resize_gravity - vs. fixed_directions section. - fixed_directions - There may be multiple solutions to shoving a window back onscreen. - Typically, the shortest distance used is the solution picked, but if - e.g. an application only moved its window in a single direction, it's - more desirable that the window is shoved back in that direction than in - a different one. fixed_directions facilitates that. Explained further - in the resize_gravity vs. fixed_directions section. - work_area_xinerama - This region is defined in the workspace and just cached here for - convenience. It is basically the area obtained by taking the current - xinerama, treating all partial struts as full struts, and then - subtracting all struts from the current xinerama region. Useful - e.g. for enforcing maximization constraints. - entire_xinerama - Just a cache of the rectangle corresponding to the entire current - xinerama, including struts. Useful e.g. for enforcing fullscreen - constraints. - usable_screen_region - The set of maximal/spanning rectangles for the entire screen; this - region doesn't overlap with any struts and helps to enforce - e.g. onscreen constraints. - usable_xinerama_region - The set of maximal/spanning rectangles for the current xinerama; this - region doesn't overlap with any struts on the xinerama and helps to - enforce e.g. the on-single-xinerama constraint. - - ---------------------------------------------------------------------------- -Gory details of resize_gravity vs. fixed_directions ---------------------------------------------------------------------------- - -Note that although resize_gravity and fixed_directions look similar, they -are used for different purposes: - - - resize_gravity is only for resize operations and is used for - constraints unrelated to keeping a window within a certain region - - fixed_directions is for both move and resize operations and is - specifically for keeping a window within a specified region. - -Examples of where each are used: - - - If a window is simultaneously moved and resized to the southeast corner - with SouthEastGravity, but it turns out that the window was sized to - something smaller than the minimum size hint, then the size_hints - constraint should resize the window using the resize_gravity to ensure - that the southeast corner doesn't move. - - If an application resizes itself so that it grows downward only (which - I note could be using any of three different gravities, most likely - NorthWest), and happens to put the southeast part of the window under a - partial strut, then the window needs to be forced back on screen. - (Yes, shoved onscreen and not clipped; see bug 136307). It may be the - case that moving the window to the left results in less movement of the - window than moving the window up, which, in the absence of fixed - directions would cause us to chose moving to the left. But since the - user knows that only the height of the window is changing, they would - find moving to the left weird (especially if this were a dialog that - had been centered on its parent). It'd be better to shove the window - upwards so we make sure to keep the left and right sides fixed in this - case. Note that moving the window upwards (or leftwards) is probably - totally against the gravity in this case; but that's okay because - gravity typically assumes there's more than enough onscreen space for - the resize and we only override the gravity when that assumption is - wrong. - -For the paranoid, a fixed directions might give an impossible to fulfill -constraint (I don't think that's true currently in the code, but I haven't -thought it through in a while). If this ever becomes a problem, it should -be relatively simple to throw out the fixed directions when this happens -and rerun the constraint. Of course, it might be better to rethink things -to just avoid such a problem. - -The nitty gritty of what gets fixed: - User move: - in x direction - y direction fixed - in y direction - x direction fixed - in both dirs. - neither direction fixed - User resize: (note that for clipping, only 1 side ever changed) - in x direction - y direction fixed (technically opposite x side fixed too) - in y direction - x direction fixed (technically opposite y side fixed too) - in both dirs. - neither direction fixed - App move: - in x direction - y direction fixed - in y direction - x direction fixed - in both dirs. - neither direction fixed - App resize - in x direction - y direction fixed - in y direction - x direction fixed - in 2 parallel directions (center side gravity) - other dir. fixed - in 2 orthogonal directions (corner gravity) - neither dir. fixed - in 3 or 4 directions (a center-like gravity) - neither dir. fixed - Move & resize - Treat like resize case though this will usually mean all four sides - change and result in neither direction being fixed - Note that in all cases, if neither direction moves it is likely do to a - change in struts and thus neither direction should be fixed despite the - lack of movement. |