Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
tuner-displays
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ximper Linux
tuner-displays
Commits
ba26fb3d
Verified
Commit
ba26fb3d
authored
Jun 15, 2026
by
Kirill Unitsaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ui: prevent monitor overlap after resize
parent
87463a2c
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
212 additions
and
0 deletions
+212
-0
ui-utils.vala
src/ui/common/ui-utils.vala
+189
-0
monitor-setting-binding.vala
src/ui/settings/monitor-setting-binding.vala
+23
-0
No files found.
src/ui/common/ui-utils.vala
View file @
ba26fb3d
...
...
@@ -43,6 +43,195 @@ namespace TunerDisplays {
monitor
.
y
=
0
;
}
private
enum
MonitorSide
{
NONE
,
LEFT
,
RIGHT
,
TOP
,
BOTTOM
}
internal
static
void
repair_layout_after_monitor_resize
(
MonitorConfig
changed
,
Gee
.
ArrayList
<
MonitorConfig
>
monitors
,
double
old_width
,
double
old_height
)
{
if
(!
changed
.
enabled
||
changed
.
mirrored
)
return
;
var
old_x
=
changed
.
x
;
var
old_y
=
changed
.
y
;
var
old_right
=
old_x
+
old_width
;
var
old_bottom
=
old_y
+
old_height
;
foreach
(
var
monitor
in
monitors
)
{
if
(
monitor
==
changed
||
!
monitor
.
enabled
)
continue
;
var
side
=
adjacent_side
(
monitor
,
old_x
,
old_y
,
old_right
,
old_bottom
);
if
(
side
!=
MonitorSide
.
NONE
)
place_next_to
(
changed
,
monitor
,
side
);
}
var
max_passes
=
monitors
.
size
*
monitors
.
size
+
4
;
for
(
int
pass
=
0
;
pass
<
max_passes
;
pass
++)
{
bool
moved
=
false
;
for
(
int
i
=
0
;
i
<
monitors
.
size
;
i
++)
{
var
a
=
monitors
[
i
];
if
(!
a
.
enabled
)
continue
;
for
(
int
j
=
i
+
1
;
j
<
monitors
.
size
;
j
++)
{
var
b
=
monitors
[
j
];
if
(!
b
.
enabled
||
!
monitors_overlap
(
a
,
b
))
continue
;
if
(
a
==
changed
)
move_away_from
(
a
,
b
);
else
if
(
b
==
changed
)
move_away_from
(
b
,
a
);
else
move_away_from
(
a
,
b
);
moved
=
true
;
}
}
if
(!
moved
)
break
;
}
normalize_enabled_positions
(
monitors
);
}
private
static
MonitorSide
adjacent_side
(
MonitorConfig
monitor
,
double
old_x
,
double
old_y
,
double
old_right
,
double
old_bottom
)
{
var
x
=
(
double
)
monitor
.
x
;
var
y
=
(
double
)
monitor
.
y
;
var
right
=
x
+
monitor
.
logical_width
;
var
bottom
=
y
+
monitor
.
logical_height
;
if
(
edges_touch
(
x
,
old_right
)
&&
ranges_overlap
(
y
,
bottom
,
old_y
,
old_bottom
))
return
MonitorSide
.
RIGHT
;
if
(
edges_touch
(
right
,
old_x
)
&&
ranges_overlap
(
y
,
bottom
,
old_y
,
old_bottom
))
return
MonitorSide
.
LEFT
;
if
(
edges_touch
(
y
,
old_bottom
)
&&
ranges_overlap
(
x
,
right
,
old_x
,
old_right
))
return
MonitorSide
.
BOTTOM
;
if
(
edges_touch
(
bottom
,
old_y
)
&&
ranges_overlap
(
x
,
right
,
old_x
,
old_right
))
return
MonitorSide
.
TOP
;
return
MonitorSide
.
NONE
;
}
private
static
bool
edges_touch
(
double
a
,
double
b
)
{
return
Math
.
fabs
(
Math
.
round
(
a
)
-
Math
.
round
(
b
))
<=
1.0
;
}
private
static
void
place_next_to
(
MonitorConfig
anchor
,
MonitorConfig
monitor
,
MonitorSide
side
)
{
switch
(
side
)
{
case
MonitorSide
.
RIGHT
:
monitor
.
x
=
(
int
)
Math
.
ceil
(
anchor
.
x
+
anchor
.
logical_width
);
break
;
case
MonitorSide
.
LEFT
:
monitor
.
x
=
(
int
)
Math
.
floor
(
anchor
.
x
-
monitor
.
logical_width
);
break
;
case
MonitorSide
.
BOTTOM
:
monitor
.
y
=
(
int
)
Math
.
ceil
(
anchor
.
y
+
anchor
.
logical_height
);
break
;
case
MonitorSide
.
TOP
:
monitor
.
y
=
(
int
)
Math
.
floor
(
anchor
.
y
-
monitor
.
logical_height
);
break
;
default
:
break
;
}
}
private
static
void
move_away_from
(
MonitorConfig
anchor
,
MonitorConfig
monitor
)
{
var
best_x
=
monitor
.
x
;
var
best_y
=
monitor
.
y
;
var
best_distance
=
double
.
MAX
;
consider_non_overlapping_position
(
anchor
,
monitor
,
(
int
)
Math
.
floor
(
anchor
.
x
-
monitor
.
logical_width
),
monitor
.
y
,
ref
best_x
,
ref
best_y
,
ref
best_distance
);
consider_non_overlapping_position
(
anchor
,
monitor
,
(
int
)
Math
.
ceil
(
anchor
.
x
+
anchor
.
logical_width
),
monitor
.
y
,
ref
best_x
,
ref
best_y
,
ref
best_distance
);
consider_non_overlapping_position
(
anchor
,
monitor
,
monitor
.
x
,
(
int
)
Math
.
floor
(
anchor
.
y
-
monitor
.
logical_height
),
ref
best_x
,
ref
best_y
,
ref
best_distance
);
consider_non_overlapping_position
(
anchor
,
monitor
,
monitor
.
x
,
(
int
)
Math
.
ceil
(
anchor
.
y
+
anchor
.
logical_height
),
ref
best_x
,
ref
best_y
,
ref
best_distance
);
monitor
.
x
=
best_x
;
monitor
.
y
=
best_y
;
}
private
static
void
consider_non_overlapping_position
(
MonitorConfig
anchor
,
MonitorConfig
monitor
,
int
x
,
int
y
,
ref
int
best_x
,
ref
int
best_y
,
ref
double
best_distance
)
{
if
(
rects_overlap
(
anchor
.
x
,
anchor
.
y
,
anchor
.
logical_width
,
anchor
.
logical_height
,
x
,
y
,
monitor
.
logical_width
,
monitor
.
logical_height
))
{
return
;
}
var
dx
=
x
-
monitor
.
x
;
var
dy
=
y
-
monitor
.
y
;
var
distance
=
Math
.
sqrt
(
dx
*
dx
+
dy
*
dy
);
if
(
distance
<
best_distance
)
{
best_distance
=
distance
;
best_x
=
x
;
best_y
=
y
;
}
}
private
static
bool
monitors_overlap
(
MonitorConfig
a
,
MonitorConfig
b
)
{
return
rects_overlap
(
a
.
x
,
a
.
y
,
a
.
logical_width
,
a
.
logical_height
,
b
.
x
,
b
.
y
,
b
.
logical_width
,
b
.
logical_height
);
}
private
static
bool
rects_overlap
(
double
ax
,
double
ay
,
double
aw
,
double
ah
,
double
bx
,
double
by
,
double
bw
,
double
bh
)
{
return
ax
<
bx
+
bw
&&
ax
+
aw
>
bx
&&
ay
<
by
+
bh
&&
ay
+
ah
>
by
;
}
private
static
bool
ranges_overlap
(
double
a1
,
double
a2
,
double
b1
,
double
b2
)
{
return
a1
<
b2
&&
b1
<
a2
;
}
private
static
void
normalize_enabled_positions
(
Gee
.
ArrayList
<
MonitorConfig
>
monitors
)
{
int
min_x
=
0
;
int
min_y
=
0
;
bool
first
=
true
;
foreach
(
var
monitor
in
monitors
)
{
if
(!
monitor
.
enabled
)
continue
;
if
(
first
)
{
min_x
=
monitor
.
x
;
min_y
=
monitor
.
y
;
first
=
false
;
}
else
{
min_x
=
int
.
min
(
min_x
,
monitor
.
x
);
min_y
=
int
.
min
(
min_y
,
monitor
.
y
);
}
}
if
(
first
||
(
min_x
==
0
&&
min_y
==
0
))
return
;
foreach
(
var
monitor
in
monitors
)
{
if
(!
monitor
.
enabled
)
continue
;
monitor
.
x
-=
min_x
;
monitor
.
y
-=
min_y
;
}
}
private
static
string
refresh_rate_label
(
DisplayMode
mode
)
{
return
_
(
"%.2f Hz"
).
printf
(
mode
.
refresh
);
}
...
...
src/ui/settings/monitor-setting-binding.vala
View file @
ba26fb3d
...
...
@@ -99,6 +99,9 @@ namespace TunerDisplays {
public
override
void
set_value
(
Value
value
)
{
var
context
=
MonitorSettingsState
.
current
;
var
monitor
=
context
.
monitor
;
var
repair_layout
=
affects_layout_size
(
field
);
var
old_width
=
monitor
.
logical_width
;
var
old_height
=
monitor
.
logical_height
;
switch
(
field
)
{
case
"enabled"
:
...
...
@@ -151,9 +154,29 @@ namespace TunerDisplays {
break
;
}
if
(
repair_layout
&&
size_changed
(
old_width
,
old_height
,
monitor
.
logical_width
,
monitor
.
logical_height
))
repair_layout_after_monitor_resize
(
monitor
,
context
.
all_monitors
,
old_width
,
old_height
);
context
.
emit_changed
();
}
private
static
bool
affects_layout_size
(
string
field
)
{
switch
(
field
)
{
case
"mode"
:
case
"resolution"
:
case
"scale-choice"
:
case
"scale-spin"
:
case
"transform"
:
return
true
;
default
:
return
false
;
}
}
private
static
bool
size_changed
(
double
old_width
,
double
old_height
,
double
width
,
double
height
)
{
return
Math
.
fabs
(
old_width
-
width
)
>
0.01
||
Math
.
fabs
(
old_height
-
height
)
>
0.01
;
}
private
static
string
get_string_value
(
string
field
)
{
var
monitor
=
MonitorSettingsState
.
current
.
monitor
;
switch
(
field
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment