Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
ximper-shell-notification-center
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
ximper-shell-notification-center
Commits
16e371f2
Verified
Commit
16e371f2
authored
Apr 18, 2026
by
Kirill Unitsaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
notification: make URLs in body clickable
parent
b1e6beda
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
42 additions
and
31 deletions
+42
-31
notification.vala
src/notification/notification.vala
+42
-31
No files found.
src/notification/notification.vala
View file @
16e371f2
...
...
@@ -90,6 +90,7 @@ namespace XimperShellNotificationCenter {
private
static
Regex
tag_regex
;
private
static
Regex
tag_unescape_regex
;
private
static
Regex
img_tag_regex
;
private
static
Regex
url_regex
;
private
static
bool
regexes_initialized
=
false
;
public
bool
dismissed
{
get
;
private
set
;
default
=
false
;
}
...
...
@@ -147,6 +148,8 @@ namespace XimperShellNotificationCenter {
"&(?=%s)"
.
printf
(
unescaped
));
img_tag_regex
=
new
Regex
(
"<img[^>]* src=((\"([^\"]*)\")|(\'([^\']*)\'))[^>]*>"
);
url_regex
=
new
Regex
(
"(?<!href=\")(https?://[^\\s<>\"'\\)]+)"
);
regexes_initialized
=
true
;
}
catch
(
Error
e
)
{
stderr
.
printf
(
"Invalid regex: %s"
,
e
.
message
);
...
...
@@ -161,6 +164,15 @@ namespace XimperShellNotificationCenter {
BindingFlags
.
SYNC_CREATE
|
BindingFlags
.
INVERT_BOOLEAN
,
null
,
null
);
body
.
activate_link
.
connect
((
uri
)
=>
{
try
{
AppInfo
.
launch_default_for_uri
(
uri
,
null
);
}
catch
(
Error
e
)
{
warning
(
"Failed to open URL: %s"
,
e
.
message
);
}
return
true
;
});
// Build the default_action gesture
gesture
=
new
Gtk
.
GestureClick
();
default_action
.
add_controller
(
gesture
);
...
...
@@ -375,43 +387,42 @@ namespace XimperShellNotificationCenter {
}
}
// Markup
// Sanitize markup
string
markup
=
text
;
try
{
Pango
.
AttrList
?
attr
=
null
;
string
?
buf
=
null
;
Pango
.
AttrList
?
attr_check
;
string
?
buf_check
;
Pango
.
parse_markup
(
text
,
-
1
,
0
,
out
attr_check
,
out
buf_check
,
null
);
}
catch
(
Error
e
)
{
// Invalid markup - escape all, then re-enable allowed tags
try
{
// Try parsing without any hacks
Pango
.
parse_markup
(
text
,
-
1
,
0
,
out
attr
,
out
buf
,
null
);
}
catch
(
Error
e
)
{
// Default to hack if the initial markup couldn't be parsed
// Escapes all characters
string
escaped
=
Markup
.
escape_text
(
text
);
// Replace all valid tags brackets with <,</,> so that the
// markup parser only parses valid tags
// Ex: <b>BOLD</b> -> <b>BOLD</b>
escaped
=
tag_regex
.
replace
(
escaped
,
escaped
.
length
,
0
,
"<\\1>"
);
// Unescape a few characters that may have been double escaped
// Sending "<" in Discord would result in "&lt;" without this
// &lt; -> <
escaped
=
tag_unescape_regex
.
replace_literal
(
escaped
,
escaped
.
length
,
0
,
"&"
);
// Turns it back to markup, defaults to original if not valid
Pango
.
parse_markup
(
escaped
,
-
1
,
0
,
out
attr
,
out
buf
,
null
);
}
this
.
body
.
set_text
(
buf
);
if
(
attr
!=
null
)
{
this
.
body
.
set_attributes
(
attr
);
escaped
=
tag_regex
.
replace
(
escaped
,
escaped
.
length
,
0
,
"<\\1>"
);
escaped
=
tag_unescape_regex
.
replace_literal
(
escaped
,
escaped
.
length
,
0
,
"&"
);
markup
=
escaped
;
}
catch
(
Error
re
)
{
markup
=
Markup
.
escape_text
(
text
);
}
}
catch
(
Error
e
)
{
stderr
.
printf
(
"Could not parse Pango markup %s: %s\n"
,
text
,
e
.
message
);
// Sets the original text
this
.
body
.
set_text
(
text
);
}
// Wrap URLs in clickable anchor tags
try
{
markup
=
url_regex
.
replace_eval
(
markup
,
markup
.
length
,
0
,
0
,
(
mi
,
result
)
=>
{
string
url
=
mi
.
fetch
(
0
);
string
safe
=
Markup
.
escape_text
(
url
);
result
.
append_printf
(
"<a href=\"%s\">%s</a>"
,
safe
,
safe
);
return
false
;
});
}
catch
(
Error
e
)
{}
this
.
body
.
set_markup
(
markup
);
this
.
body
.
set_visible
(
this
.
body
.
get_text
().
length
>
0
);
}
...
...
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