Bug Summary

File:core/edge-resistance.c
Warning:line 204, column 3
Value stored to 'compare' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name edge-resistance.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -D HAVE_CONFIG_H -I . -I .. -I ./include -D CROMA_LIBEXECDIR="/usr/local/libexec" -D HOST_ALIAS="" -D CROMA_LOCALEDIR="/usr/local/share/locale" -D CROMA_PKGDATADIR="/usr/local/share/croma" -D CROMA_DATADIR="/usr/local/share" -D G_LOG_DOMAIN="croma" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D _REENTRANT -D _REENTRANT -I /usr/include/startup-notification-1.0 -I /usr/include/libgtop-2.0 -D PIC -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2023-07-15-183419-30242-1 -x c core/edge-resistance.c
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Edge resistance for move/resize operations */
4
5/*
6 * Copyright (C) 2005, 2006 Elijah Newren
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#include <config.h>
25#include "edge-resistance.h"
26#include "boxes.h"
27#include "display-private.h"
28#include "workspace.h"
29
30/* A simple macro for whether a given window's edges are potentially
31 * relevant for resistance/snapping during a move/resize operation
32 */
33#define WINDOW_EDGES_RELEVANT(window, display)meta_window_should_be_showing (window) && window->
screen == display->grab_screen && window != display
->grab_window && window->type != META_WINDOW_DESKTOP
&& window->type != META_WINDOW_MENU && window
->type != META_WINDOW_SPLASHSCREEN
\
34 meta_window_should_be_showing (window) && \
35 window->screen == display->grab_screen && \
36 window != display->grab_window && \
37 window->type != META_WINDOW_DESKTOP && \
38 window->type != META_WINDOW_MENU && \
39 window->type != META_WINDOW_SPLASHSCREEN
40
41struct ResistanceDataForAnEdge
42{
43 gboolean timeout_setup;
44 guint timeout_id;
45 int timeout_edge_pos;
46 gboolean timeout_over;
47 GSourceFunc timeout_func;
48 MetaWindow *window;
49 int keyboard_buildup;
50};
51typedef struct ResistanceDataForAnEdge ResistanceDataForAnEdge;
52
53struct MetaEdgeResistanceData
54{
55 GArray *left_edges;
56 GArray *right_edges;
57 GArray *top_edges;
58 GArray *bottom_edges;
59
60 ResistanceDataForAnEdge left_data;
61 ResistanceDataForAnEdge right_data;
62 ResistanceDataForAnEdge top_data;
63 ResistanceDataForAnEdge bottom_data;
64};
65
66static void compute_resistance_and_snapping_edges (MetaDisplay *display);
67
68/* !WARNING!: this function can return invalid indices (namely, either -1 or
69 * edges->len); this is by design, but you need to remember this.
70 */
71static int
72find_index_of_edge_near_position (const GArray *edges,
73 int position,
74 gboolean want_interval_min,
75 gboolean horizontal)
76{
77 /* This is basically like a binary search, except that we're trying to
78 * find a range instead of an exact value. So, if we have in our array
79 * Value: 3 27 316 316 316 505 522 800 1213
80 * Index: 0 1 2 3 4 5 6 7 8
81 * and we call this function with position=500 & want_interval_min=TRUE
82 * then we should get 5 (because 505 is the first value bigger than 500).
83 * If we call this function with position=805 and want_interval_min=FALSE
84 * then we should get 7 (because 800 is the last value smaller than 800).
85 * A couple more, to make things clear:
86 * position want_interval_min correct_answer
87 * 316 TRUE 2
88 * 316 FALSE 4
89 * 2 FALSE -1
90 * 2000 TRUE 9
91 */
92 int low, high, mid;
93 int compare;
94 MetaEdge *edge;
95
96 /* Initialize mid, edge, & compare in the off change that the array only
97 * has one element.
98 */
99 mid = 0;
100 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
101 compare = horizontal ? edge->rect.x : edge->rect.y;
102
103 /* Begin the search... */
104 low = 0;
105 high = edges->len - 1;
106 while (low < high)
107 {
108 mid = low + (high - low)/2;
109 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
110 compare = horizontal ? edge->rect.x : edge->rect.y;
111
112 if (compare == position)
113 break;
114
115 if (compare > position)
116 high = mid - 1;
117 else
118 low = mid + 1;
119 }
120
121 /* mid should now be _really_ close to the index we want, so we start
122 * linearly searching. However, note that we don't know if mid is less
123 * than or greater than what we need and it's possible that there are
124 * several equal values equal to what we were searching for and we ended
125 * up in the middle of them instead of at the end. So we may need to
126 * move mid multiple locations over.
127 */
128 if (want_interval_min)
129 {
130 while (compare >= position && mid > 0)
131 {
132 mid--;
133 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
134 compare = horizontal ? edge->rect.x : edge->rect.y;
135 }
136 while (compare < position && mid < (int)edges->len - 1)
137 {
138 mid++;
139 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
140 compare = horizontal ? edge->rect.x : edge->rect.y;
141 }
142
143 /* Special case for no values in array big enough */
144 if (compare < position)
145 return edges->len;
146
147 /* Return the found value */
148 return mid;
149 }
150 else
151 {
152 while (compare <= position && mid < (int)edges->len - 1)
153 {
154 mid++;
155 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
156 compare = horizontal ? edge->rect.x : edge->rect.y;
157 }
158 while (compare > position && mid > 0)
159 {
160 mid--;
161 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
162 compare = horizontal ? edge->rect.x : edge->rect.y;
163 }
164
165 /* Special case for no values in array small enough */
166 if (compare > position)
167 return -1;
168
169 /* Return the found value */
170 return mid;
171 }
172}
173
174static gboolean
175points_on_same_side (int ref, int pt1, int pt2)
176{
177 return (pt1 - ref) * (pt2 - ref) > 0;
178}
179
180static int
181find_nearest_position (const GArray *edges,
182 int position,
183 int old_position,
184 const MetaRectangle *new_rect,
185 gboolean horizontal,
186 gboolean only_forward)
187{
188 /* This is basically just a binary search except that we're looking
189 * for the value closest to position, rather than finding that
190 * actual value. Also, we ignore any edges that aren't relevant
191 * given the horizontal/vertical position of new_rect.
192 */
193 int low, high, mid;
194 int compare;
195 MetaEdge *edge;
196 int best, best_dist, i;
197 gboolean edges_align;
198
199 /* Initialize mid, edge, & compare in the off change that the array only
200 * has one element.
201 */
202 mid = 0;
203 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
204 compare = horizontal ? edge->rect.x : edge->rect.y;
Value stored to 'compare' is never read
205
206 /* Begin the search... */
207 low = 0;
208 high = edges->len - 1;
209 while (low < high)
210 {
211 mid = low + (high - low)/2;
212 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
213 compare = horizontal ? edge->rect.x : edge->rect.y;
214
215 if (compare == position)
216 break;
217
218 if (compare > position)
219 high = mid - 1;
220 else
221 low = mid + 1;
222 }
223
224 /* mid should now be _really_ close to the index we want, so we
225 * start searching nearby for something that overlaps and is closer
226 * than the original position.
227 */
228 best = old_position;
229 best_dist = INT_MAX2147483647;
230
231 /* Start the search at mid */
232 edge = g_array_index (edges, MetaEdge*, mid)(((MetaEdge**) (void *) (edges)->data) [(mid)]);
233 compare = horizontal ? edge->rect.x : edge->rect.y;
234 edges_align = meta_rectangle_edge_aligns (new_rect, edge);
235 if (edges_align &&
236 (!only_forward || !points_on_same_side (position, compare, old_position)))
237 {
238 int dist = ABS (compare - position)(((compare - position) < 0) ? -(compare - position) : (compare
- position))
;
239 if (dist < best_dist)
240 {
241 best = compare;
242 best_dist = dist;
243 }
244 }
245
246 /* Now start searching higher than mid */
247 for (i = mid + 1; i < (int)edges->len; i++)
248 {
249 edge = g_array_index (edges, MetaEdge*, i)(((MetaEdge**) (void *) (edges)->data) [(i)]);
250 compare = horizontal ? edge->rect.x : edge->rect.y;
251
252 edges_align = horizontal ?
253 meta_rectangle_vert_overlap (&edge->rect, new_rect) :
254 meta_rectangle_horiz_overlap (&edge->rect, new_rect);
255
256 if (edges_align &&
257 (!only_forward ||
258 !points_on_same_side (position, compare, old_position)))
259 {
260 int dist = ABS (compare - position)(((compare - position) < 0) ? -(compare - position) : (compare
- position))
;
261 if (dist < best_dist)
262 {
263 best = compare;
264 best_dist = dist;
265 }
266 break;
267 }
268 }
269
270 /* Now start searching lower than mid */
271 for (i = mid-1; i >= 0; i--)
272 {
273 edge = g_array_index (edges, MetaEdge*, i)(((MetaEdge**) (void *) (edges)->data) [(i)]);
274 compare = horizontal ? edge->rect.x : edge->rect.y;
275
276 edges_align = horizontal ?
277 meta_rectangle_vert_overlap (&edge->rect, new_rect) :
278 meta_rectangle_horiz_overlap (&edge->rect, new_rect);
279
280 if (edges_align &&
281 (!only_forward ||
282 !points_on_same_side (position, compare, old_position)))
283 {
284 int dist = ABS (compare - position)(((compare - position) < 0) ? -(compare - position) : (compare
- position))
;
285 if (dist < best_dist)
286 {
287 best = compare;
288 }
289 break;
290 }
291 }
292
293 /* Return the best one found */
294 return best;
295}
296
297static gboolean
298movement_towards_edge (MetaSide side, int increment)
299{
300 switch (side)
301 {
302 case META_SIDE_LEFT:
303 case META_SIDE_TOP:
304 return increment < 0;
305 case META_SIDE_RIGHT:
306 case META_SIDE_BOTTOM:
307 return increment > 0;
308 default:
309 g_assert_not_reached ()do { g_assertion_message_expr ("croma", "core/edge-resistance.c"
, 309, ((const char*) (__func__)), ((void*)0)); } while (0)
;
310 }
311}
312
313static gboolean
314edge_resistance_timeout (gpointer data)
315{
316 ResistanceDataForAnEdge *resistance_data = data;
317
318 resistance_data->timeout_over = TRUE(!(0));
319 resistance_data->timeout_id = 0;
320 (*resistance_data->timeout_func)(resistance_data->window);
321
322 return FALSE(0);
323}
324
325static int
326apply_edge_resistance (MetaWindow *window,
327 int old_pos,
328 int new_pos,
329 const MetaRectangle *old_rect,
330 const MetaRectangle *new_rect,
331 GArray *edges,
332 ResistanceDataForAnEdge *resistance_data,
333 GSourceFunc timeout_func,
334 gboolean xdir,
335 gboolean keyboard_op)
336{
337 int i, begin, end;
338 int last_edge;
339 gboolean increasing = new_pos > old_pos;
340 int increment = increasing ? 1 : -1;
341
342 const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_WINDOW = 16;
343 const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_WINDOW = 0;
344 const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_XINERAMA = 32;
345 const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_XINERAMA = 0;
346 const int PIXEL_DISTANCE_THRESHOLD_TOWARDS_SCREEN = 32;
347 const int PIXEL_DISTANCE_THRESHOLD_AWAYFROM_SCREEN = 0;
348 const int TIMEOUT_RESISTANCE_LENGTH_MS_WINDOW = 0;
349 const int TIMEOUT_RESISTANCE_LENGTH_MS_XINERAMA = 0;
350 const int TIMEOUT_RESISTANCE_LENGTH_MS_SCREEN = 0;
351
352 /* Quit if no movement was specified */
353 if (old_pos == new_pos)
354 return new_pos;
355
356 /* Remove the old timeout if it's no longer relevant */
357 if (resistance_data->timeout_setup &&
358 ((resistance_data->timeout_edge_pos > old_pos &&
359 resistance_data->timeout_edge_pos > new_pos) ||
360 (resistance_data->timeout_edge_pos < old_pos &&
361 resistance_data->timeout_edge_pos < new_pos)))
362 {
363 resistance_data->timeout_setup = FALSE(0);
364 if (resistance_data->timeout_id != 0)
365 {
366 g_source_remove (resistance_data->timeout_id);
367 resistance_data->timeout_id = 0;
368 }
369 }
370
371 /* Get the range of indices in the edge array that we move past/to. */
372 begin = find_index_of_edge_near_position (edges, old_pos, increasing, xdir);
373 end = find_index_of_edge_near_position (edges, new_pos, !increasing, xdir);
374
375 /* begin and end can be outside the array index, if the window is partially
376 * off the screen
377 */
378 last_edge = edges->len - 1;
379 begin = CLAMP (begin, 0, last_edge)(((begin) > (last_edge)) ? (last_edge) : (((begin) < (0
)) ? (0) : (begin)))
;
380 end = CLAMP (end, 0, last_edge)(((end) > (last_edge)) ? (last_edge) : (((end) < (0)) ?
(0) : (end)))
;
381
382 /* Loop over all these edges we're moving past/to. */
383 i = begin;
384 while ((increasing && i <= end) ||
385 (!increasing && i >= end))
386 {
387 gboolean edges_align;
388 MetaEdge *edge = g_array_index (edges, MetaEdge*, i)(((MetaEdge**) (void *) (edges)->data) [(i)]);
389 int compare = xdir ? edge->rect.x : edge->rect.y;
390
391 /* Find out if this edge is relevant */
392 edges_align = meta_rectangle_edge_aligns (new_rect, edge) ||
393 meta_rectangle_edge_aligns (old_rect, edge);
394
395 /* Nothing to do unless the edges align */
396 if (!edges_align)
397 {
398 /* Go to the next edge in the range */
399 i += increment;
400 continue;
401 }
402
403 /* Rest is easier to read if we split on keyboard vs. mouse op */
404 if (keyboard_op)
405 {
406 if ((old_pos < compare && compare < new_pos) ||
407 (old_pos > compare && compare > new_pos))
408 return compare;
409 }
410 else /* mouse op */
411 {
412 int threshold;
413
414 /* TIMEOUT RESISTANCE: If the edge is relevant and we're moving
415 * towards it, then we may want to have some kind of time delay
416 * before the user can move past this edge.
417 */
418 if (movement_towards_edge (edge->side_type, increment))
419 {
420 /* First, determine the length of time for the resistance */
421 int timeout_length_ms = 0;
422 switch (edge->edge_type)
423 {
424 case META_EDGE_WINDOW:
425 timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_WINDOW;
426 break;
427 case META_EDGE_XINERAMA:
428 timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_XINERAMA;
429 break;
430 case META_EDGE_SCREEN:
431 timeout_length_ms = TIMEOUT_RESISTANCE_LENGTH_MS_SCREEN;
432 break;
433 }
434
435 if (!resistance_data->timeout_setup &&
436 timeout_length_ms != 0)
437 {
438 resistance_data->timeout_id =
439 g_timeout_add (timeout_length_ms,
440 edge_resistance_timeout,
441 resistance_data);
442 resistance_data->timeout_setup = TRUE(!(0));
443 resistance_data->timeout_edge_pos = compare;
444 resistance_data->timeout_over = FALSE(0);
445 resistance_data->timeout_func = timeout_func;
446 resistance_data->window = window;
447 }
448 if (!resistance_data->timeout_over &&
449 timeout_length_ms != 0)
450 return compare;
451 }
452
453 /* PIXEL DISTANCE MOUSE RESISTANCE: If the edge matters and the
454 * user hasn't moved at least threshold pixels past this edge,
455 * stop movement at this edge. (Note that this is different from
456 * keyboard resistance precisely because keyboard move ops are
457 * relative to previous positions, whereas mouse move ops are
458 * relative to differences in mouse position and mouse position
459 * is an absolute quantity rather than a relative quantity)
460 */
461
462 /* First, determine the threshold */
463 switch (edge->edge_type)
464 {
465 case META_EDGE_WINDOW:
466 if (movement_towards_edge (edge->side_type, increment))
467 threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_WINDOW;
468 else
469 threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_WINDOW;
470 break;
471 case META_EDGE_XINERAMA:
472 if (movement_towards_edge (edge->side_type, increment))
473 threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_XINERAMA;
474 else
475 threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_XINERAMA;
476 break;
477 case META_EDGE_SCREEN:
478 if (movement_towards_edge (edge->side_type, increment))
479 threshold = PIXEL_DISTANCE_THRESHOLD_TOWARDS_SCREEN;
480 else
481 threshold = PIXEL_DISTANCE_THRESHOLD_AWAYFROM_SCREEN;
482 break;
483 default:
484 threshold = 0;
485 }
486
487 if (ABS (compare - new_pos)(((compare - new_pos) < 0) ? -(compare - new_pos) : (compare
- new_pos))
< threshold)
488 return compare;
489 }
490
491 /* Go to the next edge in the range */
492 i += increment;
493 }
494
495 return new_pos;
496}
497
498static int
499apply_edge_snapping (int old_pos,
500 int new_pos,
501 const MetaRectangle *new_rect,
502 GArray *edges,
503 gboolean xdir,
504 gboolean keyboard_op)
505{
506 int snap_to;
507
508 if (old_pos == new_pos)
509 return new_pos;
510
511 snap_to = find_nearest_position (edges,
512 new_pos,
513 old_pos,
514 new_rect,
515 xdir,
516 keyboard_op);
517
518 /* If mouse snap-moving, the user could easily accidentally move just a
519 * couple pixels in a direction they didn't mean to move; so ignore snap
520 * movement in those cases unless it's only a small number of pixels
521 * anyway.
522 */
523 if (!keyboard_op &&
524 ABS (snap_to - old_pos)(((snap_to - old_pos) < 0) ? -(snap_to - old_pos) : (snap_to
- old_pos))
>= 8 &&
525 ABS (new_pos - old_pos)(((new_pos - old_pos) < 0) ? -(new_pos - old_pos) : (new_pos
- old_pos))
< 8)
526 return old_pos;
527 else
528 /* Otherwise, return the snapping position found */
529 return snap_to;
530}
531
532/* This function takes the position (including any frame) of the window and
533 * a proposed new position (ignoring edge resistance/snapping), and then
534 * applies edge resistance to EACH edge (separately) updating new_outer.
535 * It returns true if new_outer is modified, false otherwise.
536 *
537 * display->grab_edge_resistance_data MUST already be setup or calling this
538 * function will cause a crash.
539 */
540static gboolean
541apply_edge_resistance_to_each_side (MetaDisplay *display,
542 MetaWindow *window,
543 const MetaRectangle *old_outer,
544 MetaRectangle *new_outer,
545 GSourceFunc timeout_func,
546 gboolean auto_snap,
547 gboolean keyboard_op,
548 gboolean is_resize)
549{
550 MetaEdgeResistanceData *edge_data;
551 MetaRectangle modified_rect;
552 gboolean modified;
553 int new_left, new_right, new_top, new_bottom;
554
555 if (display->grab_edge_resistance_data == NULL((void*)0))
556 compute_resistance_and_snapping_edges (display);
557
558 edge_data = display->grab_edge_resistance_data;
559
560 if (auto_snap)
561 {
562 /* Do the auto snapping instead of normal edge resistance; in all
563 * cases, we allow snapping to opposite kinds of edges (e.g. left
564 * sides of windows to both left and right edges.
565 */
566
567 new_left = apply_edge_snapping (BOX_LEFT (*old_outer)((*old_outer).x),
568 BOX_LEFT (*new_outer)((*new_outer).x),
569 new_outer,
570 edge_data->left_edges,
571 TRUE(!(0)),
572 keyboard_op);
573
574 new_right = apply_edge_snapping (BOX_RIGHT (*old_outer)((*old_outer).x + (*old_outer).width),
575 BOX_RIGHT (*new_outer)((*new_outer).x + (*new_outer).width),
576 new_outer,
577 edge_data->right_edges,
578 TRUE(!(0)),
579 keyboard_op);
580
581 new_top = apply_edge_snapping (BOX_TOP (*old_outer)((*old_outer).y),
582 BOX_TOP (*new_outer)((*new_outer).y),
583 new_outer,
584 edge_data->top_edges,
585 FALSE(0),
586 keyboard_op);
587
588 new_bottom = apply_edge_snapping (BOX_BOTTOM (*old_outer)((*old_outer).y + (*old_outer).height),
589 BOX_BOTTOM (*new_outer)((*new_outer).y + (*new_outer).height),
590 new_outer,
591 edge_data->bottom_edges,
592 FALSE(0),
593 keyboard_op);
594 }
595 else
596 {
597 /* Disable edge resistance for resizes when windows have size
598 * increment hints; see #346782. For all other cases, apply
599 * them.
600 */
601 if (!is_resize || window->size_hints.width_inc == 1)
602 {
603 /* Now, apply the normal horizontal edge resistance */
604 new_left = apply_edge_resistance (window,
605 BOX_LEFT (*old_outer)((*old_outer).x),
606 BOX_LEFT (*new_outer)((*new_outer).x),
607 old_outer,
608 new_outer,
609 edge_data->left_edges,
610 &edge_data->left_data,
611 timeout_func,
612 TRUE(!(0)),
613 keyboard_op);
614 new_right = apply_edge_resistance (window,
615 BOX_RIGHT (*old_outer)((*old_outer).x + (*old_outer).width),
616 BOX_RIGHT (*new_outer)((*new_outer).x + (*new_outer).width),
617 old_outer,
618 new_outer,
619 edge_data->right_edges,
620 &edge_data->right_data,
621 timeout_func,
622 TRUE(!(0)),
623 keyboard_op);
624 }
625 else
626 {
627 new_left = new_outer->x;
628 new_right = new_outer->x + new_outer->width;
629 }
630 /* Same for vertical resizes... */
631 if (!is_resize || window->size_hints.height_inc == 1)
632 {
633 new_top = apply_edge_resistance (window,
634 BOX_TOP (*old_outer)((*old_outer).y),
635 BOX_TOP (*new_outer)((*new_outer).y),
636 old_outer,
637 new_outer,
638 edge_data->top_edges,
639 &edge_data->top_data,
640 timeout_func,
641 FALSE(0),
642 keyboard_op);
643 new_bottom = apply_edge_resistance (window,
644 BOX_BOTTOM (*old_outer)((*old_outer).y + (*old_outer).height),
645 BOX_BOTTOM (*new_outer)((*new_outer).y + (*new_outer).height),
646 old_outer,
647 new_outer,
648 edge_data->bottom_edges,
649 &edge_data->bottom_data,
650 timeout_func,
651 FALSE(0),
652 keyboard_op);
653 }
654 else
655 {
656 new_top = new_outer->y;
657 new_bottom = new_outer->y + new_outer->height;
658 }
659 }
660
661 /* Determine whether anything changed, and save the changes */
662 modified_rect = meta_rect (new_left,
663 new_top,
664 new_right - new_left,
665 new_bottom - new_top);
666 modified = !meta_rectangle_equal (new_outer, &modified_rect);
667 *new_outer = modified_rect;
668 return modified;
669}
670
671void
672meta_display_cleanup_edges (MetaDisplay *display)
673{
674 guint i,j;
675 MetaEdgeResistanceData *edge_data = display->grab_edge_resistance_data;
676 GHashTable *edges_to_be_freed;
677
678 if (edge_data == NULL((void*)0)) /* Not currently cached */
679 return;
680
681 /* We first need to clean out any window edges */
682 edges_to_be_freed = g_hash_table_new_full (g_direct_hash, g_direct_equal,
683 g_free, NULL((void*)0));
684 for (i = 0; i < 4; i++)
685 {
686 GArray *tmp = NULL((void*)0);
687 MetaSide side;
688 switch (i)
689 {
690 case 0:
691 tmp = edge_data->left_edges;
692 side = META_SIDE_LEFT;
693 break;
694 case 1:
695 tmp = edge_data->right_edges;
696 side = META_SIDE_RIGHT;
697 break;
698 case 2:
699 tmp = edge_data->top_edges;
700 side = META_SIDE_TOP;
701 break;
702 case 3:
703 tmp = edge_data->bottom_edges;
704 side = META_SIDE_BOTTOM;
705 break;
706 default:
707 g_assert_not_reached ()do { g_assertion_message_expr ("croma", "core/edge-resistance.c"
, 707, ((const char*) (__func__)), ((void*)0)); } while (0)
;
708 }
709
710 for (j = 0; j < tmp->len; j++)
711 {
712 MetaEdge *edge = g_array_index (tmp, MetaEdge*, j)(((MetaEdge**) (void *) (tmp)->data) [(j)]);
713 if (edge->edge_type == META_EDGE_WINDOW &&
714 edge->side_type == side)
715 {
716 /* The same edge will appear in two arrays, and we can't free
717 * it yet we still need to compare edge->side_type for the other
718 * array that it is in. So store it in a hash table for later
719 * freeing. Could also do this in a simple linked list.
720 */
721 g_hash_table_insert (edges_to_be_freed, edge, edge);
722 }
723 }
724 }
725
726 /* Now free all the window edges (the key destroy function is g_free) */
727 g_hash_table_destroy (edges_to_be_freed);
728
729 /* Now free the arrays and data */
730 g_array_free (edge_data->left_edges, TRUE(!(0)));
731 g_array_free (edge_data->right_edges, TRUE(!(0)));
732 g_array_free (edge_data->top_edges, TRUE(!(0)));
733 g_array_free (edge_data->bottom_edges, TRUE(!(0)));
734 edge_data->left_edges = NULL((void*)0);
735 edge_data->right_edges = NULL((void*)0);
736 edge_data->top_edges = NULL((void*)0);
737 edge_data->bottom_edges = NULL((void*)0);
738
739 /* Cleanup the timeouts */
740 if (edge_data->left_data.timeout_setup &&
741 edge_data->left_data.timeout_id != 0)
742 g_source_remove (edge_data->left_data.timeout_id);
743 if (edge_data->right_data.timeout_setup &&
744 edge_data->right_data.timeout_id != 0)
745 g_source_remove (edge_data->right_data.timeout_id);
746 if (edge_data->top_data.timeout_setup &&
747 edge_data->top_data.timeout_id != 0)
748 g_source_remove (edge_data->top_data.timeout_id);
749 if (edge_data->bottom_data.timeout_setup &&
750 edge_data->bottom_data.timeout_id != 0)
751 g_source_remove (edge_data->bottom_data.timeout_id);
752
753 g_free (display->grab_edge_resistance_data);
754 display->grab_edge_resistance_data = NULL((void*)0);
755}
756
757static int
758stupid_sort_requiring_extra_pointer_dereference (gconstpointer a,
759 gconstpointer b)
760{
761 const MetaEdge * const *a_edge = a;
762 const MetaEdge * const *b_edge = b;
763 return meta_rectangle_edge_cmp_ignore_type (*a_edge, *b_edge);
764}
765
766static void
767cache_edges (MetaDisplay *display,
768 GList *window_edges,
769 GList *xinerama_edges,
770 GList *screen_edges)
771{
772 MetaEdgeResistanceData *edge_data;
773 GList *tmp;
774 int num_left, num_right, num_top, num_bottom;
775 int i;
776
777 /*
778 * 0th: Print debugging information to the log about the edges
779 */
780#ifdef WITH_VERBOSE_MODE1
781 if (meta_is_verbose())
782 {
783 int max_edges = MAX (MAX( g_list_length (window_edges),((((((g_list_length (window_edges)) > (g_list_length (xinerama_edges
))) ? (g_list_length (window_edges)) : (g_list_length (xinerama_edges
)))) > (g_list_length (screen_edges))) ? ((((g_list_length
(window_edges)) > (g_list_length (xinerama_edges))) ? (g_list_length
(window_edges)) : (g_list_length (xinerama_edges)))) : (g_list_length
(screen_edges)))
784 g_list_length (xinerama_edges)),((((((g_list_length (window_edges)) > (g_list_length (xinerama_edges
))) ? (g_list_length (window_edges)) : (g_list_length (xinerama_edges
)))) > (g_list_length (screen_edges))) ? ((((g_list_length
(window_edges)) > (g_list_length (xinerama_edges))) ? (g_list_length
(window_edges)) : (g_list_length (xinerama_edges)))) : (g_list_length
(screen_edges)))
785 g_list_length (screen_edges))((((((g_list_length (window_edges)) > (g_list_length (xinerama_edges
))) ? (g_list_length (window_edges)) : (g_list_length (xinerama_edges
)))) > (g_list_length (screen_edges))) ? ((((g_list_length
(window_edges)) > (g_list_length (xinerama_edges))) ? (g_list_length
(window_edges)) : (g_list_length (xinerama_edges)))) : (g_list_length
(screen_edges)))
;
786 char big_buffer[(EDGE_LENGTH37+2)*max_edges];
787
788 meta_rectangle_edge_list_to_string (window_edges, ", ", big_buffer);
789 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
790 "Window edges for resistance : %s\n", big_buffer);
791
792 meta_rectangle_edge_list_to_string (xinerama_edges, ", ", big_buffer);
793 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
794 "Xinerama edges for resistance: %s\n", big_buffer);
795
796 meta_rectangle_edge_list_to_string (screen_edges, ", ", big_buffer);
797 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
798 "Screen edges for resistance : %s\n", big_buffer);
799 }
800#endif
801
802 /*
803 * 1st: Get the total number of each kind of edge
804 */
805 num_left = num_right = num_top = num_bottom = 0;
806 for (i = 0; i < 3; i++)
807 {
808 tmp = NULL((void*)0);
809 switch (i)
810 {
811 case 0:
812 tmp = window_edges;
813 break;
814 case 1:
815 tmp = xinerama_edges;
816 break;
817 case 2:
818 tmp = screen_edges;
819 break;
820 default:
821 g_assert_not_reached ()do { g_assertion_message_expr ("croma", "core/edge-resistance.c"
, 821, ((const char*) (__func__)), ((void*)0)); } while (0)
;
822 }
823
824 while (tmp)
825 {
826 MetaEdge *edge = tmp->data;
827 switch (edge->side_type)
828 {
829 case META_SIDE_LEFT:
830 num_left++;
831 break;
832 case META_SIDE_RIGHT:
833 num_right++;
834 break;
835 case META_SIDE_TOP:
836 num_top++;
837 break;
838 case META_SIDE_BOTTOM:
839 num_bottom++;
840 break;
841 default:
842 g_assert_not_reached ()do { g_assertion_message_expr ("croma", "core/edge-resistance.c"
, 842, ((const char*) (__func__)), ((void*)0)); } while (0)
;
843 }
844 tmp = tmp->next;
845 }
846 }
847
848 /*
849 * 2nd: Allocate the edges
850 */
851 g_assert (display->grab_edge_resistance_data == NULL)do { if (display->grab_edge_resistance_data == ((void*)0))
; else g_assertion_message_expr ("croma", "core/edge-resistance.c"
, 851, ((const char*) (__func__)), "display->grab_edge_resistance_data == NULL"
); } while (0)
;
852 display->grab_edge_resistance_data = g_new (MetaEdgeResistanceData, 1)((MetaEdgeResistanceData *) g_malloc_n ((1), sizeof (MetaEdgeResistanceData
)))
;
853 edge_data = display->grab_edge_resistance_data;
854 edge_data->left_edges = g_array_sized_new (FALSE(0),
855 FALSE(0),
856 sizeof(MetaEdge*),
857 num_left + num_right);
858 edge_data->right_edges = g_array_sized_new (FALSE(0),
859 FALSE(0),
860 sizeof(MetaEdge*),
861 num_left + num_right);
862 edge_data->top_edges = g_array_sized_new (FALSE(0),
863 FALSE(0),
864 sizeof(MetaEdge*),
865 num_top + num_bottom);
866 edge_data->bottom_edges = g_array_sized_new (FALSE(0),
867 FALSE(0),
868 sizeof(MetaEdge*),
869 num_top + num_bottom);
870
871 /*
872 * 3rd: Add the edges to the arrays
873 */
874 for (i = 0; i < 3; i++)
875 {
876 tmp = NULL((void*)0);
877 switch (i)
878 {
879 case 0:
880 tmp = window_edges;
881 break;
882 case 1:
883 tmp = xinerama_edges;
884 break;
885 case 2:
886 tmp = screen_edges;
887 break;
888 default:
889 g_assert_not_reached ()do { g_assertion_message_expr ("croma", "core/edge-resistance.c"
, 889, ((const char*) (__func__)), ((void*)0)); } while (0)
;
890 }
891
892 while (tmp)
893 {
894 MetaEdge *edge = tmp->data;
895 switch (edge->side_type)
896 {
897 case META_SIDE_LEFT:
898 case META_SIDE_RIGHT:
899 g_array_append_val (edge_data->left_edges, edge)g_array_append_vals (edge_data->left_edges, &(edge), 1
)
;
900 g_array_append_val (edge_data->right_edges, edge)g_array_append_vals (edge_data->right_edges, &(edge), 1
)
;
901 break;
902 case META_SIDE_TOP:
903 case META_SIDE_BOTTOM:
904 g_array_append_val (edge_data->top_edges, edge)g_array_append_vals (edge_data->top_edges, &(edge), 1);
905 g_array_append_val (edge_data->bottom_edges, edge)g_array_append_vals (edge_data->bottom_edges, &(edge),
1)
;
906 break;
907 default:
908 g_assert_not_reached ()do { g_assertion_message_expr ("croma", "core/edge-resistance.c"
, 908, ((const char*) (__func__)), ((void*)0)); } while (0)
;
909 }
910 tmp = tmp->next;
911 }
912 }
913
914 /*
915 * 4th: Sort the arrays (FIXME: This is kinda dumb since the arrays were
916 * individually sorted earlier and we could have done this faster and
917 * avoided this sort by sticking them into the array with some simple
918 * merging of the lists).
919 */
920 g_array_sort (display->grab_edge_resistance_data->left_edges,
921 stupid_sort_requiring_extra_pointer_dereference);
922 g_array_sort (display->grab_edge_resistance_data->right_edges,
923 stupid_sort_requiring_extra_pointer_dereference);
924 g_array_sort (display->grab_edge_resistance_data->top_edges,
925 stupid_sort_requiring_extra_pointer_dereference);
926 g_array_sort (display->grab_edge_resistance_data->bottom_edges,
927 stupid_sort_requiring_extra_pointer_dereference);
928}
929
930static void
931initialize_grab_edge_resistance_data (MetaDisplay *display)
932{
933 MetaEdgeResistanceData *edge_data = display->grab_edge_resistance_data;
934
935 edge_data->left_data.timeout_setup = FALSE(0);
936 edge_data->right_data.timeout_setup = FALSE(0);
937 edge_data->top_data.timeout_setup = FALSE(0);
938 edge_data->bottom_data.timeout_setup = FALSE(0);
939
940 edge_data->left_data.keyboard_buildup = 0;
941 edge_data->right_data.keyboard_buildup = 0;
942 edge_data->top_data.keyboard_buildup = 0;
943 edge_data->bottom_data.keyboard_buildup = 0;
944}
945
946static void
947compute_resistance_and_snapping_edges (MetaDisplay *display)
948{
949 GList *stacked_windows;
950 GList *cur_window_iter;
951 GList *edges;
952 /* Lists of window positions (rects) and their relative stacking positions */
953 int stack_position;
954 GSList *obscuring_windows, *window_stacking;
955 /* The portions of the above lists that still remain at the stacking position
956 * in the layer that we are working on
957 */
958 GSList *rem_windows, *rem_win_stacking;
959
960 g_assert (display->grab_window != NULL)do { if (display->grab_window != ((void*)0)) ; else g_assertion_message_expr
("croma", "core/edge-resistance.c", 960, ((const char*) (__func__
)), "display->grab_window != NULL"); } while (0)
;
961 meta_topicmeta_topic_real (META_DEBUG_WINDOW_OPS,
962 "Computing edges to resist-movement or snap-to for %s.\n",
963 display->grab_window->desc);
964
965 /*
966 * 1st: Get the list of relevant windows, from bottom to top
967 */
968 stacked_windows =
969 meta_stack_list_windows (display->grab_screen->stack,
970 display->grab_screen->active_workspace);
971
972 /*
973 * 2nd: we need to separate that stacked list into a list of windows that
974 * can obscure other edges. To make sure we only have windows obscuring
975 * those below it instead of going both ways, we also need to keep a
976 * counter list. Messy, I know.
977 */
978 obscuring_windows = window_stacking = NULL((void*)0);
979 cur_window_iter = stacked_windows;
980 stack_position = 0;
981 while (cur_window_iter != NULL((void*)0))
982 {
983 MetaWindow *cur_window = cur_window_iter->data;
984 if (WINDOW_EDGES_RELEVANT (cur_window, display)meta_window_should_be_showing (cur_window) && cur_window
->screen == display->grab_screen && cur_window !=
display->grab_window && cur_window->type != META_WINDOW_DESKTOP
&& cur_window->type != META_WINDOW_MENU &&
cur_window->type != META_WINDOW_SPLASHSCREEN
)
985 {
986 MetaRectangle *new_rect;
987 new_rect = g_new (MetaRectangle, 1)((MetaRectangle *) g_malloc_n ((1), sizeof (MetaRectangle)));
988 meta_window_get_outer_rect (cur_window, new_rect);
989 obscuring_windows = g_slist_prepend (obscuring_windows, new_rect);
990 window_stacking =
991 g_slist_prepend (window_stacking, GINT_TO_POINTER (stack_position)((gpointer) (glong) (stack_position)));
992 }
993
994 stack_position++;
995 cur_window_iter = cur_window_iter->next;
996 }
997 /* Put 'em in bottom to top order */
998 rem_windows = obscuring_windows = g_slist_reverse (obscuring_windows);
999 rem_win_stacking = window_stacking = g_slist_reverse (window_stacking);
1000
1001 /*
1002 * 3rd: loop over the windows again, this time getting the edges from
1003 * them and removing intersections with the relevant obscuring_windows &
1004 * obscuring_docks.
1005 */
1006 edges = NULL((void*)0);
1007 stack_position = 0;
1008 cur_window_iter = stacked_windows;
1009 while (cur_window_iter != NULL((void*)0))
1010 {
1011 MetaRectangle cur_rect;
1012 MetaWindow *cur_window = cur_window_iter->data;
1013 meta_window_get_outer_rect (cur_window, &cur_rect);
1014
1015 /* Check if we want to use this window's edges for edge
1016 * resistance (note that dock edges are considered screen edges
1017 * which are handled separately
1018 */
1019 if (WINDOW_EDGES_RELEVANT (cur_window, display)meta_window_should_be_showing (cur_window) && cur_window
->screen == display->grab_screen && cur_window !=
display->grab_window && cur_window->type != META_WINDOW_DESKTOP
&& cur_window->type != META_WINDOW_MENU &&
cur_window->type != META_WINDOW_SPLASHSCREEN
&&
1020 cur_window->type != META_WINDOW_DOCK)
1021 {
1022 GList *new_edges;
1023 MetaEdge *new_edge;
1024 MetaRectangle reduced;
1025
1026 /* We don't care about snapping to any portion of the window that
1027 * is offscreen (we also don't care about parts of edges covered
1028 * by other windows or DOCKS, but that's handled below).
1029 */
1030 meta_rectangle_intersect (&cur_rect,
1031 &display->grab_screen->rect,
1032 &reduced);
1033
1034 new_edges = NULL((void*)0);
1035
1036 /* Left side of this window is resistance for the right edge of
1037 * the window being moved.
1038 */
1039 new_edge = g_new (MetaEdge, 1)((MetaEdge *) g_malloc_n ((1), sizeof (MetaEdge)));
1040 new_edge->rect = reduced;
1041 new_edge->rect.width = 0;
1042 new_edge->side_type = META_SIDE_RIGHT;
1043 new_edge->edge_type = META_EDGE_WINDOW;
1044 new_edges = g_list_prepend (new_edges, new_edge);
1045
1046 /* Right side of this window is resistance for the left edge of
1047 * the window being moved.
1048 */
1049 new_edge = g_new (MetaEdge, 1)((MetaEdge *) g_malloc_n ((1), sizeof (MetaEdge)));
1050 new_edge->rect = reduced;
1051 new_edge->rect.x += new_edge->rect.width;
1052 new_edge->rect.width = 0;
1053 new_edge->side_type = META_SIDE_LEFT;
1054 new_edge->edge_type = META_EDGE_WINDOW;
1055 new_edges = g_list_prepend (new_edges, new_edge);
1056
1057 /* Top side of this window is resistance for the bottom edge of
1058 * the window being moved.
1059 */
1060 new_edge = g_new (MetaEdge, 1)((MetaEdge *) g_malloc_n ((1), sizeof (MetaEdge)));
1061 new_edge->rect = reduced;
1062 new_edge->rect.height = 0;
1063 new_edge->side_type = META_SIDE_BOTTOM;
1064 new_edge->edge_type = META_EDGE_WINDOW;
1065 new_edges = g_list_prepend (new_edges, new_edge);
1066
1067 /* Top side of this window is resistance for the bottom edge of
1068 * the window being moved.
1069 */
1070 new_edge = g_new (MetaEdge, 1)((MetaEdge *) g_malloc_n ((1), sizeof (MetaEdge)));
1071 new_edge->rect = reduced;
1072 new_edge->rect.y += new_edge->rect.height;
1073 new_edge->rect.height = 0;
1074 new_edge->side_type = META_SIDE_TOP;
1075 new_edge->edge_type = META_EDGE_WINDOW;
1076 new_edges = g_list_prepend (new_edges, new_edge);
1077
1078 /* Update the remaining windows to only those at a higher
1079 * stacking position than this one.
1080 */
1081 while (rem_win_stacking &&
1082 stack_position >= GPOINTER_TO_INT (rem_win_stacking->data)((gint) (glong) (rem_win_stacking->data)))
1083 {
1084 rem_windows = rem_windows->next;
1085 rem_win_stacking = rem_win_stacking->next;
1086 }
1087
1088 /* Remove edge portions overlapped by rem_windows and rem_docks */
1089 new_edges =
1090 meta_rectangle_remove_intersections_with_boxes_from_edges (
1091 new_edges,
1092 rem_windows);
1093
1094 /* Save the new edges */
1095 edges = g_list_concat (new_edges, edges);
1096 }
1097
1098 stack_position++;
1099 cur_window_iter = cur_window_iter->next;
1100 }
1101
1102 /*
1103 * 4th: Free the extra memory not needed and sort the list
1104 */
1105 g_list_free (stacked_windows);
1106 /* Free the memory used by the obscuring windows/docks lists */
1107 g_slist_free (window_stacking);
1108 g_slist_free_full (obscuring_windows, g_free);
1109
1110 /* Sort the list. FIXME: Should I bother with this sorting? I just
1111 * sort again later in cache_edges() anyway...
1112 */
1113 edges = g_list_sort (edges, meta_rectangle_edge_cmp);
1114
1115 /*
1116 * 5th: Cache the combination of these edges with the onscreen and
1117 * xinerama edges in an array for quick access. Free the edges since
1118 * they've been cached elsewhere.
1119 */
1120 cache_edges (display,
1121 edges,
1122 display->grab_screen->active_workspace->xinerama_edges,
1123 display->grab_screen->active_workspace->screen_edges);
1124 g_list_free (edges);
1125
1126 /*
1127 * 6th: Initialize the resistance timeouts and buildups
1128 */
1129 initialize_grab_edge_resistance_data (display);
1130}
1131
1132/* Note that old_[xy] and new_[xy] are with respect to inner positions of
1133 * the window.
1134 */
1135void
1136meta_window_edge_resistance_for_move (MetaWindow *window,
1137 int old_x,
1138 int old_y,
1139 int *new_x,
1140 int *new_y,
1141 GSourceFunc timeout_func,
1142 gboolean snap,
1143 gboolean is_keyboard_op)
1144{
1145 MetaRectangle old_outer, proposed_outer, new_outer;
1146 gboolean is_resize;
1147
1148 if (window == window->display->grab_window &&
1149 window->display->grab_wireframe_active)
1150 {
1151 meta_window_get_xor_rect (window,
1152 &window->display->grab_wireframe_rect,
1153 &old_outer);
1154 }
1155 else
1156 {
1157 meta_window_get_outer_rect (window, &old_outer);
1158 }
1159 proposed_outer = old_outer;
1160 proposed_outer.x += (*new_x - old_x);
1161 proposed_outer.y += (*new_y - old_y);
1162 new_outer = proposed_outer;
1163
1164 window->display->grab_last_user_action_was_snap = snap;
1165 is_resize = FALSE(0);
1166 if (apply_edge_resistance_to_each_side (window->display,
1167 window,
1168 &old_outer,
1169 &new_outer,
1170 timeout_func,
1171 snap,
1172 is_keyboard_op,
1173 is_resize))
1174 {
1175 /* apply_edge_resistance_to_each_side independently applies
1176 * resistance to both the right and left edges of new_outer as both
1177 * could meet areas of resistance. But we don't want a resize, so we
1178 * just have both edges move according to the stricter of the
1179 * resistances. Same thing goes for top & bottom edges.
1180 */
1181 MetaRectangle *reference;
1182 int left_change, right_change, smaller_x_change;
1183 int top_change, bottom_change, smaller_y_change;
1184
1185 if (snap && !is_keyboard_op)
1186 reference = &proposed_outer;
1187 else
1188 reference = &old_outer;
1189
1190 left_change = BOX_LEFT (new_outer)((new_outer).x) - BOX_LEFT (*reference)((*reference).x);
1191 right_change = BOX_RIGHT (new_outer)((new_outer).x + (new_outer).width) - BOX_RIGHT (*reference)((*reference).x + (*reference).width);
1192 if ( snap && is_keyboard_op && left_change == 0)
1193 smaller_x_change = right_change;
1194 else if (snap && is_keyboard_op && right_change == 0)
1195 smaller_x_change = left_change;
1196 else if (ABS (left_change)(((left_change) < 0) ? -(left_change) : (left_change)) < ABS (right_change)(((right_change) < 0) ? -(right_change) : (right_change)))
1197 smaller_x_change = left_change;
1198 else
1199 smaller_x_change = right_change;
1200
1201 top_change = BOX_TOP (new_outer)((new_outer).y) - BOX_TOP (*reference)((*reference).y);
1202 bottom_change = BOX_BOTTOM (new_outer)((new_outer).y + (new_outer).height) - BOX_BOTTOM (*reference)((*reference).y + (*reference).height);
1203 if ( snap && is_keyboard_op && top_change == 0)
1204 smaller_y_change = bottom_change;
1205 else if (snap && is_keyboard_op && bottom_change == 0)
1206 smaller_y_change = top_change;
1207 else if (ABS (top_change)(((top_change) < 0) ? -(top_change) : (top_change)) < ABS (bottom_change)(((bottom_change) < 0) ? -(bottom_change) : (bottom_change
))
)
1208 smaller_y_change = top_change;
1209 else
1210 smaller_y_change = bottom_change;
1211
1212 *new_x = old_x + smaller_x_change +
1213 (BOX_LEFT (*reference)((*reference).x) - BOX_LEFT (old_outer)((old_outer).x));
1214 *new_y = old_y + smaller_y_change +
1215 (BOX_TOP (*reference)((*reference).y) - BOX_TOP (old_outer)((old_outer).y));
1216
1217 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
1218 "outer x & y move-to coordinate changed from %d,%d to %d,%d\n",
1219 proposed_outer.x, proposed_outer.y,
1220 old_outer.x + (*new_x - old_x),
1221 old_outer.y + (*new_y - old_y));
1222 }
1223}
1224
1225/* Note that old_(width|height) and new_(width|height) are with respect to
1226 * sizes of the inner window.
1227 */
1228void
1229meta_window_edge_resistance_for_resize (MetaWindow *window,
1230 int old_width,
1231 int old_height,
1232 int *new_width,
1233 int *new_height,
1234 int gravity,
1235 GSourceFunc timeout_func,
1236 gboolean snap,
1237 gboolean is_keyboard_op)
1238{
1239 MetaRectangle old_outer, new_outer;
1240 int proposed_outer_width, proposed_outer_height;
1241 gboolean is_resize;
1242
1243 if (window == window->display->grab_window &&
1244 window->display->grab_wireframe_active)
1245 {
1246 meta_window_get_xor_rect (window,
1247 &window->display->grab_wireframe_rect,
1248 &old_outer);
1249 }
1250 else
1251 {
1252 meta_window_get_outer_rect (window, &old_outer);
1253 }
1254 proposed_outer_width = old_outer.width + (*new_width - old_width);
1255 proposed_outer_height = old_outer.height + (*new_height - old_height);
1256 meta_rectangle_resize_with_gravity (&old_outer,
1257 &new_outer,
1258 gravity,
1259 proposed_outer_width,
1260 proposed_outer_height);
1261
1262 window->display->grab_last_user_action_was_snap = snap;
1263 is_resize = TRUE(!(0));
1264 if (apply_edge_resistance_to_each_side (window->display,
1265 window,
1266 &old_outer,
1267 &new_outer,
1268 timeout_func,
1269 snap,
1270 is_keyboard_op,
1271 is_resize))
1272 {
1273 *new_width = old_width + (new_outer.width - old_outer.width);
1274 *new_height = old_height + (new_outer.height - old_outer.height);
1275
1276 meta_topicmeta_topic_real (META_DEBUG_EDGE_RESISTANCE,
1277 "outer width & height got changed from %d,%d to %d,%d\n",
1278 proposed_outer_width, proposed_outer_height,
1279 new_outer.width, new_outer.height);
1280 }
1281}