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
355bd1d9
Verified
Commit
355bd1d9
authored
Jun 15, 2026
by
Kirill Unitsaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
displays: add monitor config include prompt
parent
18cf5dd4
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
420 additions
and
42 deletions
+420
-42
displays-view.blp
data/ui/displays-view.blp
+13
-0
ru.po
po/ru.po
+51
-21
tuner-displays.pot
po/tuner-displays.pot
+51
-21
display-backend.vala
src/backends/display-backend.vala
+104
-0
hyprland-backend.vala
src/backends/hyprland-backend.vala
+62
-0
niri-backend.vala
src/backends/niri-backend.vala
+57
-0
meson.build
src/meson.build
+1
-0
config-include-validator.vala
src/ui/config-include-validator.vala
+59
-0
displays-view.vala
src/ui/displays-view.vala
+22
-0
No files found.
data/ui/displays-view.blp
View file @
355bd1d9
...
...
@@ -7,6 +7,19 @@ template $TunerDisplaysDisplaysView : Adw.PreferencesPage {
title: _("Displays");
icon-name: "video-display-symbolic";
Adw.PreferencesGroup config_include_group {
Adw.ActionRow config_include_row {
visible: false;
title: _("Monitor configuration is not connected");
[suffix]
Button config_include_button {
valign: center;
label: _("Connect");
}
}
}
Adw.PreferencesGroup status_group {}
Adw.PreferencesGroup layout_group {}
...
...
po/ru.po
View file @
355bd1d9
...
...
@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: tuner-displays\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-0
5-31 21:4
8+0300\n"
"POT-Creation-Date: 2026-0
6-15 11:5
8+0300\n"
"PO-Revision-Date: 2026-05-28 00:00+0000\n"
"Last-Translator: Automatically generated\n"
"Language-Team: Russian\n"
...
...
@@ -15,7 +15,17 @@ msgstr ""
msgid "Displays"
msgstr "Мониторы"
#: data/ui/displays-view.blp:15
#: data/ui/displays-view.blp:13 src/backends/hyprland-backend.vala:40
#: src/backends/hyprland-backend.vala:55 src/backends/niri-backend.vala:46
#: src/backends/niri-backend.vala:61
msgid "Monitor configuration is not connected"
msgstr "Конфигурация мониторов не подключена"
#: data/ui/displays-view.blp:18
msgid "Connect"
msgstr "Подключить"
#: data/ui/displays-view.blp:28
msgid "Details"
msgstr "Параметры"
...
...
@@ -55,11 +65,27 @@ msgstr "Нет включённых мониторов для зеркалиро
msgid "No common mirror mode is available"
msgstr "Нет общего режима для зеркалирования"
#: src/backends/hyprland-backend.vala:39
#: src/backends/hyprland-backend.vala:41
msgid "Hyprland configuration file was not found."
msgstr "Файл конфигурации Hyprland не найден."
#: src/backends/hyprland-backend.vala:56
msgid "Add monitors.conf to the Hyprland configuration."
msgstr "Добавьте monitors.conf в конфигурацию Hyprland."
#: src/backends/hyprland-backend.vala:80
msgid "hyprctl monitors all returned non-array JSON"
msgstr "hyprctl monitors all вернул JSON не в виде массива"
#: src/backends/niri-backend.vala:44
#: src/backends/niri-backend.vala:47
msgid "niri configuration file was not found."
msgstr "Файл конфигурации niri не найден."
#: src/backends/niri-backend.vala:62
msgid "Add monitor.kdl to the niri configuration."
msgstr "Добавьте monitor.kdl в конфигурацию niri."
#: src/backends/niri-backend.vala:85
msgid "niri msg outputs returned non-object JSON"
msgstr "niri msg outputs вернул JSON не в виде объекта"
...
...
@@ -67,73 +93,77 @@ msgstr "niri msg outputs вернул JSON не в виде объекта"
msgid "Built-in Display"
msgstr "Встроенный дисплей"
#: src/ui/displays-view.vala:
68
#: src/ui/displays-view.vala:
72
msgid "Failed to load monitors"
msgstr "Не удалось загрузить мониторы"
#: src/ui/displays-view.vala:
77
#: src/ui/displays-view.vala:
81
msgid "Monitor settings applied"
msgstr "Настройки мониторов применены"
#: src/ui/displays-view.vala:16
0
#: src/ui/displays-view.vala:16
5
msgid "Read-only backend"
msgstr "Режим только для чтения"
#: src/ui/displays-view.vala:16
1
#: src/ui/displays-view.vala:16
6
msgid "Applying monitor layouts is not supported by this backend."
msgstr "Применение раскладок мониторов не поддерживается этим бэкендом."
#: src/ui/displays-view.vala:171
#: src/ui/displays-view.vala:189
msgid "Monitor configuration connected"
msgstr "Конфигурация мониторов подключена"
#: src/ui/displays-view.vala:201
msgid "Mirror Displays"
msgstr "Зеркалировать мониторы"
#: src/ui/displays-view.vala:2
3
1 src/ui/monitor-settings-content.vala:88
#: src/ui/displays-view.vala:2
6
1 src/ui/monitor-settings-content.vala:88
#: src/ui/monitor-settings-content.vala:127
msgid "Resolution"
msgstr "Разрешение"
#: src/ui/displays-view.vala:
27
7 src/ui/monitor-settings-content.vala:265
#: src/ui/displays-view.vala:
30
7 src/ui/monitor-settings-content.vala:265
#: src/ui/monitor-settings-content.vala:291
msgid "Scale"
msgstr "Масштаб"
#: src/ui/displays-view.vala:
29
5 src/ui/monitor-settings-content.vala:308
#: src/ui/displays-view.vala:
32
5 src/ui/monitor-settings-content.vala:308
msgid "Normal"
msgstr "Обычный"
#: src/ui/displays-view.vala:
29
5 src/ui/monitor-settings-content.vala:308
#: src/ui/displays-view.vala:
32
5 src/ui/monitor-settings-content.vala:308
msgid "90 degrees"
msgstr "90 градусов"
#: src/ui/displays-view.vala:
29
5 src/ui/monitor-settings-content.vala:308
#: src/ui/displays-view.vala:
32
5 src/ui/monitor-settings-content.vala:308
msgid "180 degrees"
msgstr "180 градусов"
#: src/ui/displays-view.vala:
29
5 src/ui/monitor-settings-content.vala:308
#: src/ui/displays-view.vala:
32
5 src/ui/monitor-settings-content.vala:308
msgid "270 degrees"
msgstr "270 градусов"
#: src/ui/displays-view.vala:
29
6 src/ui/monitor-settings-content.vala:309
#: src/ui/displays-view.vala:
32
6 src/ui/monitor-settings-content.vala:309
msgid "Flipped"
msgstr "Отражённый"
#: src/ui/displays-view.vala:
29
6 src/ui/monitor-settings-content.vala:309
#: src/ui/displays-view.vala:
32
6 src/ui/monitor-settings-content.vala:309
msgid "Flipped 90 degrees"
msgstr "Отражённый 90 градусов"
#: src/ui/displays-view.vala:
29
6 src/ui/monitor-settings-content.vala:309
#: src/ui/displays-view.vala:
32
6 src/ui/monitor-settings-content.vala:309
msgid "Flipped 180 degrees"
msgstr "Отражённый 180 градусов"
#: src/ui/displays-view.vala:
29
6 src/ui/monitor-settings-content.vala:309
#: src/ui/displays-view.vala:
32
6 src/ui/monitor-settings-content.vala:309
msgid "Flipped 270 degrees"
msgstr "Отражённый 270 градусов"
#: src/ui/displays-view.vala:3
0
2 src/ui/monitor-settings-content.vala:315
#: src/ui/displays-view.vala:3
3
2 src/ui/monitor-settings-content.vala:315
msgid "Rotation"
msgstr "Поворот"
#: src/ui/displays-view.vala:3
3
5
#: src/ui/displays-view.vala:3
6
5
msgid "Primary Display"
msgstr "Основной дисплей"
...
...
po/tuner-displays.pot
View file @
355bd1d9
...
...
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: tuner-displays\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-0
5-31 21:4
8+0300\n"
"POT-Creation-Date: 2026-0
6-15 11:5
8+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
...
...
@@ -21,7 +21,17 @@ msgstr ""
msgid "Displays"
msgstr ""
#: data/ui/displays-view.blp:15
#: data/ui/displays-view.blp:13 src/backends/hyprland-backend.vala:40
#: src/backends/hyprland-backend.vala:55 src/backends/niri-backend.vala:46
#: src/backends/niri-backend.vala:61
msgid "Monitor configuration is not connected"
msgstr ""
#: data/ui/displays-view.blp:18
msgid "Connect"
msgstr ""
#: data/ui/displays-view.blp:28
msgid "Details"
msgstr ""
...
...
@@ -61,11 +71,27 @@ msgstr ""
msgid "No common mirror mode is available"
msgstr ""
#: src/backends/hyprland-backend.vala:39
#: src/backends/hyprland-backend.vala:41
msgid "Hyprland configuration file was not found."
msgstr ""
#: src/backends/hyprland-backend.vala:56
msgid "Add monitors.conf to the Hyprland configuration."
msgstr ""
#: src/backends/hyprland-backend.vala:80
msgid "hyprctl monitors all returned non-array JSON"
msgstr ""
#: src/backends/niri-backend.vala:44
#: src/backends/niri-backend.vala:47
msgid "niri configuration file was not found."
msgstr ""
#: src/backends/niri-backend.vala:62
msgid "Add monitor.kdl to the niri configuration."
msgstr ""
#: src/backends/niri-backend.vala:85
msgid "niri msg outputs returned non-object JSON"
msgstr ""
...
...
@@ -73,73 +99,77 @@ msgstr ""
msgid "Built-in Display"
msgstr ""
#: src/ui/displays-view.vala:
68
#: src/ui/displays-view.vala:
72
msgid "Failed to load monitors"
msgstr ""
#: src/ui/displays-view.vala:
77
#: src/ui/displays-view.vala:
81
msgid "Monitor settings applied"
msgstr ""
#: src/ui/displays-view.vala:16
0
#: src/ui/displays-view.vala:16
5
msgid "Read-only backend"
msgstr ""
#: src/ui/displays-view.vala:16
1
#: src/ui/displays-view.vala:16
6
msgid "Applying monitor layouts is not supported by this backend."
msgstr ""
#: src/ui/displays-view.vala:171
#: src/ui/displays-view.vala:189
msgid "Monitor configuration connected"
msgstr ""
#: src/ui/displays-view.vala:201
msgid "Mirror Displays"
msgstr ""
#: src/ui/displays-view.vala:2
3
1 src/ui/monitor-settings-content.vala:88
#: src/ui/displays-view.vala:2
6
1 src/ui/monitor-settings-content.vala:88
#: src/ui/monitor-settings-content.vala:127
msgid "Resolution"
msgstr ""
#: src/ui/displays-view.vala:
27
7 src/ui/monitor-settings-content.vala:265
#: src/ui/displays-view.vala:
30
7 src/ui/monitor-settings-content.vala:265
#: src/ui/monitor-settings-content.vala:291
msgid "Scale"
msgstr ""
#: src/ui/displays-view.vala:
29
5 src/ui/monitor-settings-content.vala:308
#: src/ui/displays-view.vala:
32
5 src/ui/monitor-settings-content.vala:308
msgid "Normal"
msgstr ""
#: src/ui/displays-view.vala:
29
5 src/ui/monitor-settings-content.vala:308
#: src/ui/displays-view.vala:
32
5 src/ui/monitor-settings-content.vala:308
msgid "90 degrees"
msgstr ""
#: src/ui/displays-view.vala:
29
5 src/ui/monitor-settings-content.vala:308
#: src/ui/displays-view.vala:
32
5 src/ui/monitor-settings-content.vala:308
msgid "180 degrees"
msgstr ""
#: src/ui/displays-view.vala:
29
5 src/ui/monitor-settings-content.vala:308
#: src/ui/displays-view.vala:
32
5 src/ui/monitor-settings-content.vala:308
msgid "270 degrees"
msgstr ""
#: src/ui/displays-view.vala:
29
6 src/ui/monitor-settings-content.vala:309
#: src/ui/displays-view.vala:
32
6 src/ui/monitor-settings-content.vala:309
msgid "Flipped"
msgstr ""
#: src/ui/displays-view.vala:
29
6 src/ui/monitor-settings-content.vala:309
#: src/ui/displays-view.vala:
32
6 src/ui/monitor-settings-content.vala:309
msgid "Flipped 90 degrees"
msgstr ""
#: src/ui/displays-view.vala:
29
6 src/ui/monitor-settings-content.vala:309
#: src/ui/displays-view.vala:
32
6 src/ui/monitor-settings-content.vala:309
msgid "Flipped 180 degrees"
msgstr ""
#: src/ui/displays-view.vala:
29
6 src/ui/monitor-settings-content.vala:309
#: src/ui/displays-view.vala:
32
6 src/ui/monitor-settings-content.vala:309
msgid "Flipped 270 degrees"
msgstr ""
#: src/ui/displays-view.vala:3
0
2 src/ui/monitor-settings-content.vala:315
#: src/ui/displays-view.vala:3
3
2 src/ui/monitor-settings-content.vala:315
msgid "Rotation"
msgstr ""
#: src/ui/displays-view.vala:3
3
5
#: src/ui/displays-view.vala:3
6
5
msgid "Primary Display"
msgstr ""
...
...
src/backends/display-backend.vala
View file @
355bd1d9
...
...
@@ -7,7 +7,23 @@ namespace TunerDisplays {
APPLY_FAILED
}
public
enum
ConfigIncludeState
{
NOT_NEEDED
,
INCLUDED
,
NOT_INCLUDED
,
MISSING_MAIN_CONFIG
,
UNSUPPORTED
}
public
class
ConfigIncludeInfo
:
Object
{
public
ConfigIncludeState
state
{
get
;
set
;
default
=
ConfigIncludeState
.
NOT_NEEDED
;
}
public
string
title
{
get
;
set
;
default
=
""
;
}
public
string
subtitle
{
get
;
set
;
default
=
""
;
}
}
public
abstract
class
DisplayBackend
:
Object
{
protected
delegate
bool
ConfigIncludeMatcher
(
string
content
);
public
abstract
string
id
{
get
;
}
public
abstract
string
title
{
owned
get
;
}
public
abstract
bool
can_apply
{
get
;
}
...
...
@@ -33,6 +49,14 @@ namespace TunerDisplays {
public
abstract
Gee
.
ArrayList
<
MonitorConfig
>
load
()
throws
Error
;
public
abstract
void
apply
(
Gee
.
ArrayList
<
MonitorConfig
>
monitors
)
throws
Error
;
public
virtual
ConfigIncludeInfo
config_include_info
()
{
return
new
ConfigIncludeInfo
();
}
public
virtual
void
include_monitor_config
()
throws
Error
{
throw
new
BackendError
.
UNSUPPORTED
(
"Including monitor config is not supported by this backend"
);
}
protected
static
Json
.
Node
backend_parse_json
(
string
text
)
throws
Error
{
var
parser
=
new
Json
.
Parser
();
parser
.
load_from_data
(
text
);
...
...
@@ -78,6 +102,86 @@ namespace TunerDisplays {
return
value
.
replace
(
"\\"
,
"\\\\"
).
replace
(
"\""
,
"\\\""
);
}
protected
static
void
backend_include_config_file
(
string
main_path
,
string
included_path
,
string
include_line
,
string
comment_prefix
,
ConfigIncludeMatcher
matcher
)
throws
Error
{
backend_ensure_config_file
(
included_path
);
string
content
=
""
;
if
(
FileUtils
.
test
(
main_path
,
FileTest
.
EXISTS
))
FileUtils
.
get_contents
(
main_path
,
out
content
);
if
(
matcher
(
content
))
return
;
string
updated
;
if
(
backend_uncomment_config_include
(
content
,
comment_prefix
,
matcher
,
out
updated
))
{
FileUtils
.
set_contents
(
main_path
,
updated
);
return
;
}
var
separator
=
content
==
""
||
content
.
has_suffix
(
"\n"
)
?
""
:
"\n"
;
FileUtils
.
set_contents
(
main_path
,
content
+
separator
+
include_line
);
}
private
static
void
backend_ensure_config_file
(
string
path
)
throws
Error
{
DirUtils
.
create_with_parents
(
Path
.
get_dirname
(
path
),
0755
);
if
(!
FileUtils
.
test
(
path
,
FileTest
.
EXISTS
))
FileUtils
.
set_contents
(
path
,
""
);
}
private
static
bool
backend_uncomment_config_include
(
string
content
,
string
comment_prefix
,
ConfigIncludeMatcher
matcher
,
out
string
updated
)
{
var
builder
=
new
StringBuilder
();
var
lines
=
content
.
split
(
"\n"
);
var
changed
=
false
;
for
(
var
i
=
0
;
i
<
lines
.
length
;
i
++)
{
var
line
=
lines
[
i
];
if
(!
changed
&&
backend_uncomment_config_line
(
line
,
comment_prefix
,
matcher
,
out
line
))
changed
=
true
;
if
(
i
>
0
)
builder
.
append_c
(
'\n'
);
builder
.
append
(
line
);
}
updated
=
builder
.
str
;
return
changed
;
}
private
static
bool
backend_uncomment_config_line
(
string
line
,
string
comment_prefix
,
ConfigIncludeMatcher
matcher
,
out
string
uncommented
)
{
uncommented
=
line
;
var
comment
=
line
.
index_of
(
comment_prefix
);
if
(
comment
<
0
||
line
.
substring
(
0
,
comment
).
strip
()
!=
""
)
return
false
;
var
prefix
=
line
.
substring
(
0
,
comment
);
var
candidate
=
line
.
substring
(
comment
+
comment_prefix
.
length
);
if
(
candidate
.
has_prefix
(
" "
))
candidate
=
candidate
.
substring
(
1
);
if
(!
matcher
(
candidate
))
return
false
;
uncommented
=
prefix
+
candidate
;
return
true
;
}
public
static
DisplayBackend
create_for_session
()
{
var
desktop
=
(
Environment
.
get_variable
(
"XDG_CURRENT_DESKTOP"
)
??
""
).
down
();
var
session
=
(
Environment
.
get_variable
(
"XDG_SESSION_DESKTOP"
)
??
""
).
down
();
...
...
src/backends/hyprland-backend.vala
View file @
355bd1d9
...
...
@@ -29,6 +29,41 @@ namespace TunerDisplays {
public
override
bool
supports_color_management
{
get
{
return
true
;
}
}
public
override
bool
supports_hdr_metadata
{
get
{
return
true
;
}
}
public
override
ConfigIncludeInfo
config_include_info
()
{
var
main_path
=
main_config_path
();
if
(!
FileUtils
.
test
(
main_path
,
FileTest
.
EXISTS
))
{
return
new
ConfigIncludeInfo
()
{
state
=
ConfigIncludeState
.
MISSING_MAIN_CONFIG
,
title
=
_
(
"Monitor configuration is not connected"
),
subtitle
=
_
(
"Hyprland configuration file was not found."
)
};
}
try
{
string
content
;
if
(
FileUtils
.
get_contents
(
main_path
,
out
content
)
&&
hyprland_config_includes_monitor_config
(
content
))
return
new
ConfigIncludeInfo
()
{
state
=
ConfigIncludeState
.
INCLUDED
};
}
catch
(
Error
err
)
{
warning
(
"Failed to check Hyprland monitor config include: %s"
,
err
.
message
);
}
return
new
ConfigIncludeInfo
()
{
state
=
ConfigIncludeState
.
NOT_INCLUDED
,
title
=
_
(
"Monitor configuration is not connected"
),
subtitle
=
_
(
"Add monitors.conf to the Hyprland configuration."
)
};
}
public
override
void
include_monitor_config
()
throws
Error
{
backend_include_config_file
(
main_config_path
(),
monitors_path
(),
"source = ~/.config/hypr/monitors.conf\n"
,
"#"
,
hyprland_config_includes_monitor_config
);
}
public
override
Gee
.
ArrayList
<
MonitorConfig
>
load
()
throws
Error
{
var
monitors
=
new
Gee
.
ArrayList
<
MonitorConfig
>();
var
active
=
read_active_names
();
...
...
@@ -316,6 +351,33 @@ namespace TunerDisplays {
return
Path
.
build_filename
(
Environment
.
get_user_config_dir
(),
"hypr"
,
"monitors.conf"
);
}
private
static
string
main_config_path
()
{
return
Path
.
build_filename
(
Environment
.
get_user_config_dir
(),
"hypr"
,
"hyprland.conf"
);
}
private
static
bool
hyprland_config_includes_monitor_config
(
string
content
)
{
foreach
(
var
line
in
content
.
split
(
"\n"
))
{
var
trimmed
=
strip_hyprland_comment
(
line
).
strip
();
if
(!
trimmed
.
has_prefix
(
"source"
))
continue
;
var
equals
=
trimmed
.
index_of
(
"="
);
if
(
equals
<
0
)
continue
;
var
path
=
trimmed
.
substring
(
equals
+
1
).
strip
();
if
(
path
==
"~/.config/hypr/monitors.conf"
||
path
==
monitors_path
())
return
true
;
}
return
false
;
}
private
static
string
strip_hyprland_comment
(
string
line
)
{
var
index
=
line
.
index_of
(
"#"
);
return
index
>=
0
?
line
.
substring
(
0
,
index
)
:
line
;
}
private
static
DisplayMode
?
parse_mode
(
string
value
)
{
var
cleaned
=
value
.
replace
(
"Hz"
,
""
);
var
parts
=
cleaned
.
split
(
"@"
);
...
...
src/backends/niri-backend.vala
View file @
355bd1d9
...
...
@@ -35,6 +35,41 @@ namespace TunerDisplays {
public
override
bool
supports_backdrop_color
{
get
{
return
true
;
}
}
public
override
bool
supports_hot_corners
{
get
{
return
true
;
}
}
public
override
ConfigIncludeInfo
config_include_info
()
{
var
main_path
=
main_config_path
();
if
(!
FileUtils
.
test
(
main_path
,
FileTest
.
EXISTS
))
{
return
new
ConfigIncludeInfo
()
{
state
=
ConfigIncludeState
.
MISSING_MAIN_CONFIG
,
title
=
_
(
"Monitor configuration is not connected"
),
subtitle
=
_
(
"niri configuration file was not found."
)
};
}
try
{
string
content
;
if
(
FileUtils
.
get_contents
(
main_path
,
out
content
)
&&
niri_config_includes_monitor_config
(
content
))
return
new
ConfigIncludeInfo
()
{
state
=
ConfigIncludeState
.
INCLUDED
};
}
catch
(
Error
err
)
{
warning
(
"Failed to check niri monitor config include: %s"
,
err
.
message
);
}
return
new
ConfigIncludeInfo
()
{
state
=
ConfigIncludeState
.
NOT_INCLUDED
,
title
=
_
(
"Monitor configuration is not connected"
),
subtitle
=
_
(
"Add monitor.kdl to the niri configuration."
)
};
}
public
override
void
include_monitor_config
()
throws
Error
{
backend_include_config_file
(
main_config_path
(),
monitors_path
(),
"include \"monitor.kdl\"\n"
,
"//"
,
niri_config_includes_monitor_config
);
}
public
override
Gee
.
ArrayList
<
MonitorConfig
>
load
()
throws
Error
{
var
monitors
=
new
Gee
.
ArrayList
<
MonitorConfig
>();
var
saved
=
read_saved_monitors
();
...
...
@@ -273,6 +308,28 @@ namespace TunerDisplays {
return
Path
.
build_filename
(
Environment
.
get_user_config_dir
(),
"niri"
,
"monitor.kdl"
);
}
private
static
string
main_config_path
()
{
return
Path
.
build_filename
(
Environment
.
get_user_config_dir
(),
"niri"
,
"config.kdl"
);
}
private
static
bool
niri_config_includes_monitor_config
(
string
content
)
{
foreach
(
var
line
in
content
.
split
(
"\n"
))
{
var
trimmed
=
strip_comment
(
line
).
strip
();
if
(!
trimmed
.
has_prefix
(
"include "
))
continue
;
var
path
=
parse_quoted
(
trimmed
);
if
(
path
==
"monitor.kdl"
||
path
==
"./monitor.kdl"
||
path
==
"~/.config/niri/monitor.kdl"
||
path
==
monitors_path
())
{
return
true
;
}
}
return
false
;
}
private
static
void
append_hot_corners
(
StringBuilder
builder
,
string
value
)
{
if
(
value
==
""
)
return
;
...
...
src/meson.build
View file @
355bd1d9
...
...
@@ -12,6 +12,7 @@ sources = files(
'backends/niri-backend.vala',
'core/display-model.vala',
'core/shell-command.vala',
'ui/config-include-validator.vala',
'ui/displays-view.vala',
'ui/monitor-layout.vala',
'ui/monitor-row.vala',
...
...
src/ui/config-include-validator.vala
0 → 100644
View file @
355bd1d9
namespace
TunerDisplays
{
public
class
ConfigIncludeBinding
:
Tuner
.
Binding
{
private
DisplayBackend
backend
;
public
ConfigIncludeBinding
(
DisplayBackend
backend
)
{
this
.
backend
=
backend
;
}
public
ConfigIncludeInfo
info
()
{
return
backend
.
config_include_info
();
}
public
void
connect_config
()
throws
Error
{
backend
.
include_monitor_config
();
emit_changed
();
}
public
override
Type
expected_type
{
get
{
return
typeof
(
bool
);
}
}
public
override
bool
get_value
(
ref
Value
value
)
{
value
=
info
().
state
==
ConfigIncludeState
.
NOT_INCLUDED
;
return
true
;
}
public
override
void
set_value
(
Value
value
)
{
}
}
public
class
ConfigIncludeValidator
:
Tuner
.
Validator
{
public
override
void
apply
(
Tuner
.
Binding
binding
,
Gtk
.
Widget
native_widget
)
{
var
include_binding
=
binding
as
ConfigIncludeBinding
;
var
row
=
native_widget
as
Adw
.
ActionRow
;
if
(
include_binding
==
null
||
row
==
null
)
return
;
update
(
include_binding
,
row
);
include_binding
.
changed
.
connect
(()
=>
update
(
include_binding
,
row
));
}
private
static
void
update
(
ConfigIncludeBinding
binding
,
Adw
.
ActionRow
row
)
{
var
info
=
binding
.
info
();
var
visible
=
info
.
state
==
ConfigIncludeState
.
NOT_INCLUDED
||
info
.
state
==
ConfigIncludeState
.
MISSING_MAIN_CONFIG
;
row
.
visible
=
visible
;
var
group
=
row
.
get_ancestor
(
typeof
(
Adw
.
PreferencesGroup
));
if
(
group
!=
null
)
group
.
visible
=
visible
;
if
(!
visible
)
return
;
row
.
title
=
info
.
title
;
row
.
subtitle
=
info
.
subtitle
;
}
}
}
src/ui/displays-view.vala
View file @
355bd1d9
...
...
@@ -11,8 +11,11 @@ namespace TunerDisplays {
private
MonitorSettingsContent
?
single_monitor_content
;
private
MonitorLayout
layout
;
private
Adw
.
PreferencesRow
layout_row
;
private
ConfigIncludeBinding
config_include_binding
;
private
DBusConnection
?
session_bus
;
private
uint
monitors_changed_id
;
[
GtkChild
]
private
unowned
Adw
.
ActionRow
config_include_row
;
[
GtkChild
]
private
unowned
Gtk
.
Button
config_include_button
;
[
GtkChild
]
private
unowned
Adw
.
PreferencesGroup
monitors_group
;
[
GtkChild
]
private
unowned
Adw
.
PreferencesGroup
layout_group
;
[
GtkChild
]
private
unowned
Adw
.
PreferencesGroup
status_group
;
...
...
@@ -23,6 +26,7 @@ namespace TunerDisplays {
construct
{
backend
=
DisplayBackend
.
create_for_session
();
config_include_binding
=
new
ConfigIncludeBinding
(
backend
);
layout_row
=
new
Adw
.
PreferencesRow
()
{
activatable
=
false
,
...
...
@@ -40,6 +44,9 @@ namespace TunerDisplays {
layout
.
layout_changed
.
connect
(
sync_rows
);
layout_row
.
child
=
layout
;
layout_group
.
add
(
layout_row
);
config_include_button
.
clicked
.
connect
(
connect_monitor_config
);
new
ConfigIncludeValidator
().
apply
(
config_include_binding
,
config_include_row
);
config_include_binding
.
changed
.
connect
(
sync_config_include_button
);
subscribe_monitor_changes
();
reload
();
...
...
@@ -133,6 +140,7 @@ namespace TunerDisplays {
clear_status_rows
();
clear_mirror_settings_rows
();
clear_single_monitor_settings
();
config_include_binding
.
emit_changed
();
sync_layout_visibility
();
sync_group_visibility
();
...
...
@@ -163,6 +171,20 @@ namespace TunerDisplays {
}
}
private
void
sync_config_include_button
()
{
config_include_button
.
visible
=
config_include_binding
.
info
().
state
==
ConfigIncludeState
.
NOT_INCLUDED
;
}
private
void
connect_monitor_config
()
{
try
{
config_include_binding
.
connect_config
();
Tuner
.
toast
(
_
(
"Monitor configuration connected"
));
reload
();
}
catch
(
Error
err
)
{
Tuner
.
toast
(
err
.
message
);
}
}
private
void
add_gnome_mirror_row
()
{
if
(!
backend
.
supports_global_mirroring
||
monitors
.
size
<=
1
)
return
;
...
...
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