Short-term (I hope...) TODO list/reminders: - Need to update the documentation; the huge comment is out of date and misleading now - Quicklist that I thought of: X Titlebar onscreen func should use CLAMP(percent*width, 10, 75) for width and 2-3 pixels for height for checking if the titlebar is partially onscreen or not X on-single-xinerama constraint should not apply if only 1 xinerama exists X use CLAMP() macro in more places of constraints.c X Two of meta_window_move_resize_internal() calling methods in huge comment are actually the same; search for "bogus" and "BEFORE" X There may be a bug with gravity an onscreen constraints--it seems that creating a tab then removing it and repeating this a lot made the window drift northwest. Very weird. - Get rid of compiling warnings for constraints.c even if they're dumb - Should we turn off fully-onscreen & on-single-xinerama constraints for decorationless windows? Otherwise, most users (those that don't know about alt-drag to move or alt+f7 to keyboard move) won't be able to move xmms off their current xinerama onscreen space. This might mean that users lose their window (dragging the top of the window too far offscreen), but that might be a required trade-off for having a stupid-app. - Brokenness left in aspect-ratio resizing: X gtk+ seems to be doing nit-picky fighting with us over which way to round the size. This means that if the user increases the width of an aspect-ratio'ed window, we increase the height of the window in a way that keeps the center fixed, gtk+ doesn't like our selected size and sends a configure request, and then we resize the window to the configure request size using NorthWestGravity instead of WestGravity--resulting in the window drifting slightly either upward or downward. Can also result in heavy flickering sometimes. sucks. *UPDATE*: It wasn't gtk+ -- it was window.c:update_resize() causing all the flickering that I saw. However, this configure request stuff doesn't appear to be the cause of the drift... - There's still a drift... X Interplay between various onscreen constraints is not very good (resizing should stop when any window edge hits the screen edge, instead of arbitrarily clipping that edge). Similar problems probably occur for overlap with other constraints (do we care about the others, though?). ! Ought to be able to find intersection to any edge of screen (could be 3 sided, not just two) and determine the relevant box size for that. Some care will be needed, e.g. for East/West/North/South gravity where some sides only get increase/2 amount of change instead of increase - Doesn't work well with fixed sides--if the aspect ratio needs to be enforced, then fixed_directsion should be set to 0. (Also, fixed_directions should probably be reset to its former nonzero value if all constraints couldn't be satisfied simultaneously...) X edge resistance need not be much different than the current code that exists for the keyboard except that (a) only non-covered edges should count (same ought to be true for keyboard moving/resizing as well), (b) it'd be nice to have timeouts (think of two windows, A and B, separated by just a little less than the width of C--it may become really hard without timeouts to place C where it may be wanted), (c) we should add edge stickiness too, (d) it'd be nice to have the pixel-resistance and timeout-resistance be much larger for the screen edges, (e) it may be difficult determining where the screen edges are - Various extra random ideas X Could make edge resistance infinite if move/resize was click-on-titlebar-area activated (or perhaps just if the grab_anchor_root_(x|y) is in the titlebar area?) - Could get rid of the big comment at the beginning of meta_rectangle_get_minimal_spanning_set_for_region() X checking for obscured edges could make use of boxes.c:split_edge() X when timeout fires, edge-resistance for _any_ edge should be disabled until the mouse moves at least pixels (from last_motion_(x|y) or edge resisted x,y?) X check if test_find_onscreen_edges() passes when struts are disjoint X change edges_overlap() to not depend on type (allow undefined type; just check thicknesses) X have a shove_onscreen item in the menu when the titlebar is offscreen too X Important edge resistance points - Both moving and resizing - Real edges, not workarea - Screen vs. xinerama vs. window edges - 0-distance magnetism + resistance - pixel-distance, timeouts (mouse only), build-up (keyboard only) - ignore unseen edges - cache edges - put all this functionality into one common location - Important documentation points - All fields of ConstraintsInfo struct - Inner vs Outer window - meta_window_move_resize_internal() and other changes - priority structure - basic function addition - spanning rects - boxes.[ch] & testboxes.c - Questions for UI experts: - should I have left edges lining up to left edges of other windows result in resistance as well, or just left edges lining up against right edges as I currently do? - should I do the extend-by-1-thing when checking for overlap? - what should the threshold be for resistance? screen-size-dependent? - timeout for offscreen stuff? - make timeout different for xinerama edges? - if window offscreen, have different threshold for offscreen edge resistance than for normal window edges? (xinerama?) - how much keyboard buildup before moving past various edges? timeout? - amount windows are allowed offscreen - should I turn off all onscreen & on-single-xinerama constraints for decorationless windows? - ??? length of timeout on mouse_resize without threshold movement before shoving window entirely onscreen (and amount of titlebar obscured before it's considered offscreen?) - Need to clean out lots of FIXMEs in the code. X Need to do the titlebar offscreen checking, partial maximization, etc. X Might be good to optimize by storing spanning rects in MetaWorkspace X Need to replace xinerama and screen structures (screen.h?) and maybe tabpopup stuff (see bug 98340, IIRC) with MetaRectangle's X It looks like I can nuke work_area_screen in ConstraintInfo X Do I need the include_frame parameter to get_size_limits() anymore? (Update: yes, do_screen_and_xinerama_relative_constraints() uses it) X Ought to rewrite adjust_for_gravity to do less and then just use meta_rectangle_resize_with_gravity() X Need to add a test_find_closest_linepoint to testboxes.c to test that function nice and thoroughly. X Ought to add a test_gravity_resize to testboxes.c, and use the new meta_rectangle_region_to_string(), and maybe move other printing stuff there. X Clicking on an XMMS window causes a failed assertion due to unfixed FIXME in meta_window_configure_request() (Problem was that we tried to call meta_window_move_resize_internal() on restack configure requests) X Once the window goes offscreen, clicking on the edge in order to resize results in all kinds of weirdness: clipping the window to the screen, sending the window totally and completely offscreen, or who knows what else. Very odd. X Holy cow, constrain_aspect_ratio is ABSOLUTELY COMPLETELY BORKEN!!! X Trying to _move_ the window offscreen results in clipping. Huh?? Other weirdness afterwards happens too (keyboard resizing to the right went up and right) X Need to nuke old #ifdef'd out code X Need to make shove_into_rect use shortest distance in addition to maximal overlap (especially for totally offscreen case) X Need to add testboxes stuff to appropriate Makefile.am thingies X Okay the on-single-xinerama/fully-onscreen/partially-onscreen constraints aren't as simple as I thought, the boxes.[ch] is still the wrong way to go about it and doesn't cover everything needed, and I need something else big. Ideas: X Get minimal set of (maximally) covering rects: - Start with relevant rect (screen/xinerama) - Foreach strut, divide each rect in the set into up to three rects (before-strut zone, overlap-strut zone, and after-strut zone) - Each new rect must not include the strut - If the strut begins where the original rect does, the before-strut zone can be ignored; similarly for ending location and after-strut zone. - For a top or bottom strut, the before and after zones are *just* horizontal shrinkages of the original rect while the overlap zone is *just* a vertical shrinkage of the original rect (do not make the mistake of horizontally shrinking the overlap zone in this case). The left and right struts are similar in nature (vertical shrinkage for before and after, horizontal shrinkage for overlap) X Be careful not to move/clip in the wrong direction - For user move, one does not want to shove a rect vertically to force it fully onscreen if the user had only been moving the window horizontally--even if moving it vertically would result in less overall displacement. - To do this, need notion of fixed sides: - Move (App or user): - Horizontal: Top and bottom are fixed - Vertical: Left and right are fixed - Diagonal: No sides are fixed - User resize: - Uni-directional: All sides but the given direction are fixed - Bi-directional: The two other sides are fixed - App resize -- acts like move as far as side fixing - Move & resize -- unsure, perhaps no sides are fixed? X Regardless of clipping or shoving; there needs to be a good way to pick the best of the (maximally) covering rects into which to clip or shove. - User resize (clip-into): - Entirely determined by greatest-area-conserved-when-clipping-unfixed-sides - User move or app move (shove-into): - Must be able to fit the rect, w/o changing fixed sides - Prefer greatest-overlap-before-shoving - Prefer short distance moves over long distance ones (this is only needed in special cases, such as a move that causes the window to be totally offscreen) - App resize or user or app move-resize: - May first need to clamp size down, then do user/app-move stuff - If clamping is needed, clamp to the size of the rectangle that preserves as much area in the rect as possible - Note: this does not mean picking the largest covering rect possible; it may be that the window is really long and skinny, there's a covering rect that's long and skinny but not-quite-long enough, and then another covering rect that is square and overall the largest but not very long. In this case, the square rect should not be picked, because neither dimension of the window size should ever be increased. Extra notes: X Write a get_elijah_region() function, returning a GList* X elijah_region is defined as minimal set of possibly overlapping rectangles for a region with the property that a window is contained in the region iff it is contained in one of the rectangles X function should take: basic_rect (screen or xinerama), struts, extend_amount (0 for fully-onscreen or on-single-xinerama, but large relative-to-window amount for partially-onscreen constraints; extra amount might be 4x1 array for each of four directions) X Need to handle minimum size constraints in all this - The elijah_region thing would make is_titlebar_partially_onscreen() fairly easy to write (get the elijah_region, find the titlebar rect, do a whole bunch of intersection operations and see if we ever get an intersection area greater than some threshold like 0) X My aspect ratio resizing may still not work because perhaps closest-in-area should trump whenever one of the two is very far away in area (Think about grabbing the SE corner with the mouse, resizing way to the right, not letting go of the left mouse button, letting constraints catch up, then moving the mouse up slightly to shrink the window: That results in a big height reduction (since mouse position and window didn't align well), and a corresponding massive width reduction since the shrinking window stuff rules out the bigger of the two aspects). Maybe closest-in-area should ust always trump--except for some extra slop for keyboard resizing?. X My attempts to do all contraints in terms of the outer window are mislead--most are actually relative to the inner window. Comparisons: constraint window --------------- ------ size_increments inner size_limits inner maximization outer fullscreen inner aspect_ratio inner onscreen outer X Change documentation in constraints.c to target future maintainers first, then explain the basic ideas behind the algorithm and how it compares to the old method and why. X Need to add the require_fully_onscreen and require_on_single_xinerama flags and get them all initialized and everything Extra window.h flags: require_fully_onscreen (136307) vert_maximized, horiz_maximized (113601) require_on_single_xinerama (unfiled) Bugs to fix: unfiled - constraints.c is overly complicated unfiled - constraints.c is not robust when all constraints cannot be met unfiled - document our treating of gravities with center as a size-increment constraint (or perhaps actually store the reference point and don't require the even-number-of-pixels in resize) unfiled - get_outermost_onscreen_positions is decoration-unaware unfiled - constraints.c documentation is difficult to understand 142016, 143784 - should try to keep windows on a single xinerama 109553 - gravity w/ simultaneous move & resize doesn't work 113601 - maximize vert and horiz should toggle & be constrained 122196 - windows show up under vertical panels 143145 - clamp to screensize 143145? - make appear on screen 136307 - don't allow app resize off screen (unless minimum size hints? No...too big windows are fully clamped) 156699 - avoid struts when placing windows, if possible 149867 - fixed aspect ratio windows are difficult to resize WARNING: nasty interaction with e.g. onscreen constraints in 2 dim's! 312007 - snap-resize moves windows with minimium size constraint 312104 - resize top causes bottom to grow 144126 - fix stupid old method of strut handling Maybe: 152898 - no way to move a window off the top of the screen (warning: requires cleverness as user can accidentally trigger alt+click moving; probably needs edge resistance and other work first) 154706 - bouncing weirdness at screen edge w/ keyboard move or resize 124582 - shift-arrow erroneously moves window multi-dimensionally 122670 - jerky/random resizing of windows via keyboard (drop extra events -- not really needed) 81704 - edge magnetism/resistance/snapping/etc. 151842 - maximize to fill feature (gripe: patch doesn't do maximal grow) 302456 - dragging offscreen too restrictive 308521 - better alt-middle-drag resizing Some ideas: - move_rectangle_into_region & clip_rectangle_into_region in boxes.[ch] are way over-engineered; only need workarea & best-window-area (via modified form of get_outermost_onscreen_positions()) - update_position_limits looks like stupidity without current crufty framework - get_mouse_deltas_for_resize() shouldn't be necessary (window.c) - adjust_for_gravity() ought to move to constraints.c, IMO - onscreen cases: - user resize: clip into valid region - user move: move window into (fully extended) valid region - user move & resize: someone lied about what's happening or who's doing it - app resize: clamp to workarea size, move into it - app move: move into valid region - app move & resize: clamp to workarea size, then move into valid region - offscreen differences: - user resize: don't allow size increase of offscreen sides - user move: N/A (valid region extended to include offscreen in both cases) - user move & resize: N/A - app resize, move, move&resize: same but with bigger region Constraints in old constraints.c: - place the window (huh?), including maximization after placement - maximization constraints (both horiz & vert; window-size == workarea size) - fullscreen constraints (window-size == xinerama size) - desktop window constraints - titlebar onscreen constraints - min & max window size constraints (restore towards previous size) - resize increment constraints (no need for restoration here; but adjust imp.) - aspect ratio (geometric average of rects defined by x & y?) - gravity - really onscreen - clamp to screen size Add a rectangle calculus packages MetaRectangle rectangle; GList* region; // list of rectangles gboolean rectangles_intersect gboolean region_contains_rectangle gboolean region_larger_than_rectangle void move_rectangle_into_region void clip_rectangle_into_region region_expand // takes screen region, add 75 -> have // partially onscreen region contraint ** NOTE: Trying to resize at left should not move bigger window onscreen ** ** NOTE: Resizing aspect ratio windows should resize to rect closest in size to the previous one ** ** NOTE: Trying to resize minimum size window should attempt to restore window to previous position, not just resize to minimum size or else it could result in the window moving ** ** NOTE: Might be good to consider gravity somehow; Havoc has test program ** ** NOTE: Would probably be good to store optimal points, largest rectangle(s) (area-wise?) that will fit, and some other stuff that only changes when docks are added or removed... ** ** NOTE: How does application specified placement interact with onscreen constraints? ** Enumeration: A simple enumeration with explicitly defined values, e.g. typedef enum { PRIORITY_MINIMUM=0, PRIORITY_ASPECT_RATIO=0, PRIORITY_CLAMP_TO_WORKAREA=1, PRIORITY_ENTIRELY_VISIBLE_ON_WORKAREA=1, PRIORITY_MEET_MINIMIMUM_SIZE_HINTS=2, PRIORITY_PARTIALLY_VISIBLE_ON_WORKAREA=3, PRIORITY_TITLEBAR_PARTIALLY_VISIBLE_ON_WORKAREA=3 PRIORITY_MAXIMUM=3 } Others: (large windows are auto-maximized, maximized windows follow struts, fullscreen windows are screensize, desktop window is screensize,...) Function form: gboolean meta_constrain_whatever (constraint_info info, int priority, gboolean check_only) { if (priority > PRIORITY_WHATEVER) return TRUE; if (check_only) { /* If constraints already satisfied return TRUE, otherwise FALSE */ } /* Enforce constraints */ return TRUE; /* Though this is ignored when check_only is FALSE */ } Extra sanity checking: It can be useful to define variables _corner_fixed (where = ne, nw, se, or sw) window_size_fixed To verify that size or aspect ratio or placement constraints affect the correct variables Advantages: - Easier to understand (can easily add/remove/reprioritize constraints) - Can handle multi-dimensional constraints such as aspect ratio - Can determine which constraints will be violated when there are too many - We can even log the fact that constraints will be violated Minor disadvantage - We don't get enforced sanity, but sanity checking is fairly easy Disadvantages: - Major code overhaul Extra rationale: - fully-onscreen vs. strictly following PPosition hints Advantages: - users are annoyed when they can't see the whole window they are interacting with (note that this is why we raise on click too) - needed to fully fix placement with vertical panels (bug 122196) - needed to fully fix placement for accessibility with docks (bug 156699) - can still benefit from PPosition by putting the window to the position as close as possible to the point specified that still satisfies the fully-onscreen constraint Disadvantages: - apps may be trying to place dialogs relative to some other UI in their main window, and it may annoy the users to have the windows not align exactly Other notes: - disable_workarounds totally ignores PPosition anyway - PPosition is already overridden for totally offscreen or titlebar offscreen cases (while keeping the window as close as possible to the specified position) - users should easily recognize why things don't align as they might expect (since the window aligns with the edge of the workarea); further, it shouldn't be too problematic as the window should be close to the specified location - users would still be allowed to manually move the window offscreen (see bug 136307 comment 16 for how this works) - keep-on-single-xinerama vs. strictly following PPosition hints Advantages: - users are annoyed when windows are split across xineramas - can still benefit from PPosition by putting the window to the position as close as possible to the point specified that still satisfies the fully-onscreen constraint - is consistent with fully-onscreen overriding strictly following PPosition Disadvantages: - apps may be trying to place dialogs relative to some other UI in their main window, and it may annoy the users to have the windows not exactly align Other notes: - disable_workarounds totally ignores PPosition anyway - PPosition is already overridden for totally offscreen or titlebar offscreen cases (while keeping the window as close as possible to the specified position) - users should easily recognize why things don't align as they might expect (since the window aligns with the edge of a monitor); further, it shouldn't be too problematic as the window should be close to the specified location - users would still be allowed to manually move windows to an area spanning multiple xineramas (see bug 136307 comment 16 for the idea of how this works; it extends to the on-single-xinerama case easily). - This constraint should probably not apply for windows with a parent that spans multiple xineramas, unless that parent is a DESKTOP or DOCK window. Question: - Should this constraint resize windows to make them fit? (I'm thinking no--but if it should for the general case, DESKTOP and DOCKS will need to be exceptions) General notes on the rewrite: Old comments on how to do the rewrite and how it used to work (wish I would have seen all these before I embarked on the project...): http://bugzilla.gnome.org/show_bug.cgi?id=106740#c62 http://bugzilla.gnome.org/show_bug.cgi?id=106740#c75 http://bugzilla.gnome.org/show_bug.cgi?id=106740#c101 http://bugzilla.gnome.org/show_bug.cgi?id=123838#c2 Havoc considers the current implementation broken: http://log.ometer.com/2004-05.html http://bugzilla.gnome.org/show_bug.cgi?id=136307#c20 http://bugzilla.gnome.org/show_bug.cgi?id=152898#c2 http://bugzilla.gnome.org/show_bug.cgi?id=152898#c7 http://bugzilla.gnome.org/show_bug.cgi?id=130834#c1 http://bugzilla.gnome.org/show_bug.cgi?id=126872#c1 http://bugzilla.gnome.org/show_bug.cgi?id=116601#c1 ...to the point that he's more or less admitted he's unwilling to review patches for it: http://bugzilla.gnome.org/show_bug.cgi?id=136307#c18 Havoc wants it rewritten: http://bugzilla.gnome.org/show_bug.cgi?id=149867#c2 Note that I'm not referring to this earlier rewrite: http://bugzilla.gnome.org/show_bug.cgi?id=107010