- First pass at pylint clean-up
This commit is contained in:
parent
062e8b102f
commit
17a9bc5f02
12 changed files with 587 additions and 603 deletions
4
.pylintrc
Normal file
4
.pylintrc
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
[MAIN]
|
||||||
|
max-line-length=150
|
||||||
|
max-module-lines=2000
|
||||||
|
generated-member=cairo.*
|
||||||
|
|
@ -28,7 +28,7 @@ class Autostart:
|
||||||
|
|
||||||
def __init__(self, app_name):
|
def __init__(self, app_name):
|
||||||
if not app_name.endswith(".desktop"):
|
if not app_name.endswith(".desktop"):
|
||||||
app_name = "%s.desktop" % (app_name)
|
app_name = f"{app_name}.desktop"
|
||||||
self.app_name = app_name
|
self.app_name = app_name
|
||||||
self.auto_locations = [os.path.join(
|
self.auto_locations = [os.path.join(
|
||||||
xdg_config_home, 'autostart/'), '/etc/xdg/autostart/']
|
xdg_config_home, 'autostart/'), '/etc/xdg/autostart/']
|
||||||
|
|
@ -77,7 +77,7 @@ class BazziteAutostart:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.auto = False
|
self.auto = False
|
||||||
with open("/etc/default/discover-overlay") as f:
|
with open("/etc/default/discover-overlay", encoding="utf-8") as f:
|
||||||
content = f.readlines()
|
content = f.readlines()
|
||||||
for line in content:
|
for line in content:
|
||||||
if line.startswith("AUTO_LAUNCH_DISCOVER_OVERLAY="):
|
if line.startswith("AUTO_LAUNCH_DISCOVER_OVERLAY="):
|
||||||
|
|
@ -94,14 +94,15 @@ class BazziteAutostart:
|
||||||
self.auto = enable
|
self.auto = enable
|
||||||
|
|
||||||
def change_file(self, value):
|
def change_file(self, value):
|
||||||
|
"""Alter bazzite config via pkexec and sed"""
|
||||||
root = ''
|
root = ''
|
||||||
if shutil.which('pkexec'):
|
if shutil.which('pkexec'):
|
||||||
root = 'pkexec'
|
root = 'pkexec'
|
||||||
else:
|
else:
|
||||||
log.error("No ability to request root privs. Cancel")
|
log.error("No ability to request root privs. Cancel")
|
||||||
return
|
return
|
||||||
command = " sed -i 's/AUTO_LAUNCH_DISCOVER_OVERLAY=./AUTO_LAUNCH_DISCOVER_OVERLAY=%s/g' /etc/default/discover-overlay" % (
|
command = f" sed -i 's/AUTO_LAUNCH_DISCOVER_OVERLAY=./AUTO_LAUNCH_DISCOVER_OVERLAY={
|
||||||
value)
|
value}/g' /etc/default/discover-overlay"
|
||||||
command_with_permissions = root + command
|
command_with_permissions = root + command
|
||||||
os.system(command_with_permissions)
|
os.system(command_with_permissions)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import calendar
|
||||||
import websocket
|
import websocket
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import gi
|
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
@ -94,9 +93,14 @@ class DiscordConnector:
|
||||||
"""
|
"""
|
||||||
url = "https://streamkit.discord.com/overlay/token"
|
url = "https://streamkit.discord.com/overlay/token"
|
||||||
myobj = {"code": code1}
|
myobj = {"code": code1}
|
||||||
response = requests.post(url, json=myobj)
|
response = requests.post(url, json=myobj, timeout=10)
|
||||||
try:
|
try:
|
||||||
jsonresponse = json.loads(response.text)
|
jsonresponse = json.loads(response.text)
|
||||||
|
except requests.exceptions.Timeout:
|
||||||
|
# TODO This probably needs a retry, not a quit
|
||||||
|
jsonresponse = {}
|
||||||
|
except requests.exceptions.TooManyRedirects:
|
||||||
|
jsonresponse = {}
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
jsonresponse = {}
|
jsonresponse = {}
|
||||||
if "access_token" in jsonresponse:
|
if "access_token" in jsonresponse:
|
||||||
|
|
@ -192,8 +196,7 @@ class DiscordConnector:
|
||||||
"""
|
"""
|
||||||
Update a line of text
|
Update a line of text
|
||||||
"""
|
"""
|
||||||
for idx in range(0, len(self.text)):
|
for idx, message in enumerate(self.text):
|
||||||
message = self.text[idx]
|
|
||||||
if message['id'] == message_in['id']:
|
if message['id'] == message_in['id']:
|
||||||
new_message = {'id': message['id'],
|
new_message = {'id': message['id'],
|
||||||
'content': self.get_message_from_message(message_in),
|
'content': self.get_message_from_message(message_in),
|
||||||
|
|
@ -209,8 +212,7 @@ class DiscordConnector:
|
||||||
"""
|
"""
|
||||||
Delete a line of text
|
Delete a line of text
|
||||||
"""
|
"""
|
||||||
for idx in range(0, len(self.text)):
|
for idx, message in enumerate(self.text):
|
||||||
message = self.text[idx]
|
|
||||||
if message['id'] == message_in['id']:
|
if message['id'] == message_in['id']:
|
||||||
del self.text[idx]
|
del self.text[idx]
|
||||||
self.text_altered = True
|
self.text_altered = True
|
||||||
|
|
@ -386,7 +388,8 @@ class DiscordConnector:
|
||||||
self.dump_channel_data()
|
self.dump_channel_data()
|
||||||
return
|
return
|
||||||
elif j["cmd"] == "GET_GUILD":
|
elif j["cmd"] == "GET_GUILD":
|
||||||
# We currently only get here because of a "CHANNEL_CREATE" event. Stupidly long winded way around
|
# We currently only get here because of a "CHANNEL_CREATE" event.
|
||||||
|
# Stupidly long winded way around
|
||||||
if j["data"]:
|
if j["data"]:
|
||||||
guild = j["data"]
|
guild = j["data"]
|
||||||
self.dump_channel_data()
|
self.dump_channel_data()
|
||||||
|
|
@ -417,7 +420,8 @@ class DiscordConnector:
|
||||||
self.set_channel(j['data']['id'], j['data']['guild_id'])
|
self.set_channel(j['data']['id'], j['data']['guild_id'])
|
||||||
self.discover.voice_overlay.set_channel_title(
|
self.discover.voice_overlay.set_channel_title(
|
||||||
j["data"]["name"])
|
j["data"]["name"])
|
||||||
if self.current_guild in self.guilds and 'icon_url' in self.guilds[self.current_guild]:
|
if (self.current_guild in self.guilds and
|
||||||
|
'icon_url' in self.guilds[self.current_guild]):
|
||||||
self.discover.voice_overlay.set_channel_icon(
|
self.discover.voice_overlay.set_channel_icon(
|
||||||
self.guilds[self.current_guild]['icon_url'])
|
self.guilds[self.current_guild]['icon_url'])
|
||||||
else:
|
else:
|
||||||
|
|
@ -460,7 +464,8 @@ class DiscordConnector:
|
||||||
log.warning(j)
|
log.warning(j)
|
||||||
|
|
||||||
def dump_channel_data(self):
|
def dump_channel_data(self):
|
||||||
with open(self.discover.channel_file, 'w') as f:
|
""" Write all channel data out to file"""
|
||||||
|
with open(self.discover.channel_file, 'w', encoding="utf-8") as f:
|
||||||
f.write(json.dumps(
|
f.write(json.dumps(
|
||||||
{'channels': self.channels, 'guild': self.guilds}))
|
{'channels': self.channels, 'guild': self.guilds}))
|
||||||
|
|
||||||
|
|
@ -536,7 +541,7 @@ class DiscordConnector:
|
||||||
if guild in self.guilds:
|
if guild in self.guilds:
|
||||||
self.rate_limited_channels.append(guild)
|
self.rate_limited_channels.append(guild)
|
||||||
else:
|
else:
|
||||||
log.warning(f"Didn't find guild with id {guild}")
|
log.warning("Didn't find guild with id %s", guild)
|
||||||
|
|
||||||
def req_channel_details(self, channel, nonce=None):
|
def req_channel_details(self, channel, nonce=None):
|
||||||
"""message
|
"""message
|
||||||
|
|
@ -669,6 +674,7 @@ class DiscordConnector:
|
||||||
self.websocket.send(json.dumps(cmd))
|
self.websocket.send(json.dumps(cmd))
|
||||||
|
|
||||||
def set_mute(self, muted):
|
def set_mute(self, muted):
|
||||||
|
""" Set client muted status """
|
||||||
cmd = {
|
cmd = {
|
||||||
"cmd": "SET_VOICE_SETTINGS",
|
"cmd": "SET_VOICE_SETTINGS",
|
||||||
"args": {"mute": muted},
|
"args": {"mute": muted},
|
||||||
|
|
@ -679,6 +685,7 @@ class DiscordConnector:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_deaf(self, deaf):
|
def set_deaf(self, deaf):
|
||||||
|
""" Set client deafened status """
|
||||||
cmd = {
|
cmd = {
|
||||||
"cmd": "SET_VOICE_SETTINGS",
|
"cmd": "SET_VOICE_SETTINGS",
|
||||||
"args": {"deaf": deaf},
|
"args": {"deaf": deaf},
|
||||||
|
|
@ -688,14 +695,14 @@ class DiscordConnector:
|
||||||
self.websocket.send(json.dumps(cmd))
|
self.websocket.send(json.dumps(cmd))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def change_voice_room(self, id):
|
def change_voice_room(self, room_id):
|
||||||
"""
|
"""
|
||||||
Switch to another voice room
|
Switch to another voice room
|
||||||
"""
|
"""
|
||||||
cmd = {
|
cmd = {
|
||||||
"cmd": "SELECT_VOICE_CHANNEL",
|
"cmd": "SELECT_VOICE_CHANNEL",
|
||||||
"args": {
|
"args": {
|
||||||
"channel_id": id,
|
"channel_id": room_id,
|
||||||
"force": True
|
"force": True
|
||||||
},
|
},
|
||||||
"nonce": "deadbeef"
|
"nonce": "deadbeef"
|
||||||
|
|
@ -703,14 +710,14 @@ class DiscordConnector:
|
||||||
if self.websocket:
|
if self.websocket:
|
||||||
self.websocket.send(json.dumps(cmd))
|
self.websocket.send(json.dumps(cmd))
|
||||||
|
|
||||||
def change_text_room(self, id):
|
def change_text_room(self, room_id):
|
||||||
"""
|
"""
|
||||||
Switch to another text room
|
Switch to another text room
|
||||||
"""
|
"""
|
||||||
cmd = {
|
cmd = {
|
||||||
"cmd": "SELECT_TEXT_CHANNEL",
|
"cmd": "SELECT_TEXT_CHANNEL",
|
||||||
"args": {
|
"args": {
|
||||||
"channel_id": id
|
"channel_id": room_id
|
||||||
},
|
},
|
||||||
"nonce": "deadbeef"
|
"nonce": "deadbeef"
|
||||||
}
|
}
|
||||||
|
|
@ -718,7 +725,8 @@ class DiscordConnector:
|
||||||
self.websocket.send(json.dumps(cmd))
|
self.websocket.send(json.dumps(cmd))
|
||||||
|
|
||||||
def update_overlays_from_data(self):
|
def update_overlays_from_data(self):
|
||||||
if self.websocket == None:
|
"""Send new data out to overlay windows"""
|
||||||
|
if self.websocket is None:
|
||||||
self.discover.voice_overlay.set_blank()
|
self.discover.voice_overlay.set_blank()
|
||||||
if self.discover.text_overlay:
|
if self.discover.text_overlay:
|
||||||
self.discover.text_overlay.set_blank()
|
self.discover.text_overlay.set_blank()
|
||||||
|
|
@ -773,12 +781,13 @@ class DiscordConnector:
|
||||||
|
|
||||||
This will be mixed in with 'None' in the list where a voice channel is
|
This will be mixed in with 'None' in the list where a voice channel is
|
||||||
"""
|
"""
|
||||||
if (guild_id == 0):
|
if guild_id == 0:
|
||||||
return
|
return
|
||||||
self.rate_limited_channels.append(guild_id)
|
self.rate_limited_channels.append(guild_id)
|
||||||
|
|
||||||
def schedule_reconnect(self):
|
def schedule_reconnect(self):
|
||||||
if self.reconnect_cb == None:
|
"""Set a timer to attempt reconnection"""
|
||||||
|
if self.reconnect_cb is None:
|
||||||
log.info("Scheduled a reconnect")
|
log.info("Scheduled a reconnect")
|
||||||
self.reconnect_cb = GLib.timeout_add_seconds(60, self.connect)
|
self.reconnect_cb = GLib.timeout_add_seconds(60, self.connect)
|
||||||
else:
|
else:
|
||||||
|
|
@ -792,25 +801,30 @@ class DiscordConnector:
|
||||||
"""
|
"""
|
||||||
log.info("Connecting...")
|
log.info("Connecting...")
|
||||||
if self.websocket:
|
if self.websocket:
|
||||||
log.warn("Already connected?")
|
log.warning("Already connected?")
|
||||||
return
|
return
|
||||||
if self.reconnect_cb:
|
if self.reconnect_cb:
|
||||||
GLib.source_remove(self.reconnect_cb)
|
GLib.source_remove(self.reconnect_cb)
|
||||||
self.reconnect_cb = None
|
self.reconnect_cb = None
|
||||||
try:
|
try:
|
||||||
self.websocket = websocket.create_connection(
|
self.websocket = websocket.create_connection(
|
||||||
"ws://127.0.0.1:6463/?v=1&client_id=%s" % (self.oauth_token),
|
f"ws://127.0.0.1:6463/?v=1&client_id={self.oauth_token}",
|
||||||
origin="http://localhost:3000",
|
origin="http://localhost:3000",
|
||||||
timeout=0.1
|
timeout=0.1
|
||||||
)
|
)
|
||||||
if self.socket_watch:
|
if self.socket_watch:
|
||||||
GLib.source_remove(self.socket_watch)
|
GLib.source_remove(self.socket_watch)
|
||||||
self.socket_watch = GLib.io_add_watch(
|
self.socket_watch = GLib.io_add_watch(
|
||||||
self.websocket.sock, GLib.PRIORITY_DEFAULT_IDLE, GLib.IOCondition.HUP | GLib.IOCondition.IN | GLib.IOCondition.ERR, self.socket_glib)
|
self.websocket.sock,
|
||||||
except ConnectionError as error:
|
GLib.PRIORITY_DEFAULT_IDLE,
|
||||||
|
GLib.IOCondition.HUP | GLib.IOCondition.IN | GLib.IOCondition.ERR,
|
||||||
|
self.socket_glib
|
||||||
|
)
|
||||||
|
except ConnectionError as _error:
|
||||||
self.schedule_reconnect()
|
self.schedule_reconnect()
|
||||||
|
|
||||||
def socket_glib(self, fd, condition):
|
def socket_glib(self, _fd, condition):
|
||||||
|
"""Handle new data on socket"""
|
||||||
if condition == GLib.IO_IN and self.websocket:
|
if condition == GLib.IO_IN and self.websocket:
|
||||||
recv, _w, _e = select.select((self.websocket.sock,), (), (), 0)
|
recv, _w, _e = select.select((self.websocket.sock,), (), (), 0)
|
||||||
while recv:
|
while recv:
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,15 @@
|
||||||
"""Main application class"""
|
"""Main application class"""
|
||||||
import gettext
|
import gettext
|
||||||
import os
|
import os
|
||||||
import time
|
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import traceback
|
import traceback
|
||||||
import logging
|
import logging
|
||||||
import pkg_resources
|
|
||||||
import json
|
import json
|
||||||
import signal
|
import signal
|
||||||
import gi
|
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
|
import gi
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
from .settings_window import MainSettingsWindow
|
from .settings_window import MainSettingsWindow
|
||||||
from .voice_overlay import VoiceOverlayWindow
|
from .voice_overlay import VoiceOverlayWindow
|
||||||
|
|
@ -33,7 +32,7 @@ from .audio_assist import DiscoverAudioAssist
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
# pylint: disable=wrong-import-position,wrong-import-order
|
# pylint: disable=wrong-import-position,wrong-import-order
|
||||||
from gi.repository import Gtk, GLib, Gio, Gdk # nopep8
|
from gi.repository import Gtk, GLib, Gio # nopep8
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from xdg.BaseDirectory import xdg_config_home
|
from xdg.BaseDirectory import xdg_config_home
|
||||||
|
|
@ -99,7 +98,7 @@ class Discover:
|
||||||
Read in arg list from command or RPC and act accordingly
|
Read in arg list from command or RPC and act accordingly
|
||||||
"""
|
"""
|
||||||
if "--help" in data or "-h" in data:
|
if "--help" in data or "-h" in data:
|
||||||
print("%s: discover-overlay [OPTIONS]... " % (_("Usage")))
|
print(f"{_("Usage")}: discover-overlay [OPTIONS]... ")
|
||||||
print(_("Show an X11 or wlroots overlay with information"))
|
print(_("Show an X11 or wlroots overlay with information"))
|
||||||
print(_("from Discord client"))
|
print(_("from Discord client"))
|
||||||
print("")
|
print("")
|
||||||
|
|
@ -158,14 +157,16 @@ class Discover:
|
||||||
self.connection.request_text_rooms_for_guild(match.group(1))
|
self.connection.request_text_rooms_for_guild(match.group(1))
|
||||||
|
|
||||||
def config_set(self, context, key, value):
|
def config_set(self, context, key, value):
|
||||||
|
"""Set a config value and save to disk"""
|
||||||
config = self.config()
|
config = self.config()
|
||||||
if not context in config.sections():
|
if not context in config.sections():
|
||||||
config.add_section(context)
|
config.add_section(context)
|
||||||
config.set(context, key, value)
|
config.set(context, key, value)
|
||||||
with open(self.config_file, 'w') as file:
|
with open(self.config_file, 'w', encoding="utf-8") as file:
|
||||||
config.write(file)
|
config.write(file)
|
||||||
|
|
||||||
def config(self):
|
def config(self):
|
||||||
|
"""Read config from disk"""
|
||||||
config = ConfigParser(interpolation=None)
|
config = ConfigParser(interpolation=None)
|
||||||
config.read(self.config_file)
|
config.read(self.config_file)
|
||||||
return config
|
return config
|
||||||
|
|
@ -174,7 +175,7 @@ class Discover:
|
||||||
"""
|
"""
|
||||||
Called when the RPC file has been altered
|
Called when the RPC file has been altered
|
||||||
"""
|
"""
|
||||||
with open(self.rpc_file, "r") as tfile:
|
with open(self.rpc_file, "r", encoding="utf-8") as tfile:
|
||||||
data = tfile.readlines()
|
data = tfile.readlines()
|
||||||
if len(data) >= 1:
|
if len(data) >= 1:
|
||||||
self.do_args(data[0].strip().split(" "), False)
|
self.do_args(data[0].strip().split(" "), False)
|
||||||
|
|
@ -249,9 +250,7 @@ class Discover:
|
||||||
|
|
||||||
self.voice_overlay.set_horizontal(config.getboolean(
|
self.voice_overlay.set_horizontal(config.getboolean(
|
||||||
"main", "horizontal", fallback=False))
|
"main", "horizontal", fallback=False))
|
||||||
self.voice_overlay.set_guild_ids(self.parse_guild_ids(
|
self.voice_overlay.set_overflow_style(
|
||||||
config.get("main", "guild_ids", fallback="")))
|
|
||||||
self.voice_overlay.set_overflow(
|
|
||||||
config.getint("main", "overflow", fallback=0))
|
config.getint("main", "overflow", fallback=0))
|
||||||
self.voice_overlay.set_show_connection(config.getboolean(
|
self.voice_overlay.set_show_connection(config.getboolean(
|
||||||
"main", "show_connection", fallback=False))
|
"main", "show_connection", fallback=False))
|
||||||
|
|
@ -259,7 +258,7 @@ class Discover:
|
||||||
"main", "show_title", fallback=False))
|
"main", "show_title", fallback=False))
|
||||||
self.voice_overlay.set_show_disconnected(config.getboolean(
|
self.voice_overlay.set_show_disconnected(config.getboolean(
|
||||||
"main", "show_disconnected", fallback=False))
|
"main", "show_disconnected", fallback=False))
|
||||||
self.voice_overlay.set_border_width(
|
self.voice_overlay.set_drawn_border_width(
|
||||||
config.getint("main", "border_width", fallback=2))
|
config.getint("main", "border_width", fallback=2))
|
||||||
self.voice_overlay.set_icon_transparency(config.getfloat(
|
self.voice_overlay.set_icon_transparency(config.getfloat(
|
||||||
"main", "icon_transparency", fallback=1.0))
|
"main", "icon_transparency", fallback=1.0))
|
||||||
|
|
@ -432,6 +431,7 @@ class Discover:
|
||||||
self.config_file, self.rpc_file, self.channel_file, [])
|
self.config_file, self.rpc_file, self.channel_file, [])
|
||||||
|
|
||||||
def toggle_show(self, _obj=None):
|
def toggle_show(self, _obj=None):
|
||||||
|
"""Toggle all overlays off or on"""
|
||||||
if self.voice_overlay:
|
if self.voice_overlay:
|
||||||
hide = not self.voice_overlay.hidden
|
hide = not self.voice_overlay.hidden
|
||||||
self.voice_overlay.set_hidden(hide)
|
self.voice_overlay.set_hidden(hide)
|
||||||
|
|
@ -457,6 +457,8 @@ class Discover:
|
||||||
self.notification_overlay.set_force_xshape(force)
|
self.notification_overlay.set_force_xshape(force)
|
||||||
|
|
||||||
def set_show_task(self, visible):
|
def set_show_task(self, visible):
|
||||||
|
"""Set if the overlay should allow itself to appear on taskbar.
|
||||||
|
Not working at last check"""
|
||||||
if self.voice_overlay:
|
if self.voice_overlay:
|
||||||
self.voice_overlay.set_task(visible)
|
self.voice_overlay.set_task(visible)
|
||||||
if self.text_overlay:
|
if self.text_overlay:
|
||||||
|
|
@ -465,11 +467,13 @@ class Discover:
|
||||||
self.notification_overlay.set_task(visible)
|
self.notification_overlay.set_task(visible)
|
||||||
|
|
||||||
def set_mute_async(self, mute):
|
def set_mute_async(self, mute):
|
||||||
if mute != None:
|
"""Set mute status from another thread"""
|
||||||
|
if mute is not None:
|
||||||
GLib.idle_add(self.connection.set_mute, mute)
|
GLib.idle_add(self.connection.set_mute, mute)
|
||||||
|
|
||||||
def set_deaf_async(self, deaf):
|
def set_deaf_async(self, deaf):
|
||||||
if deaf != None:
|
"""Set deaf status from another thread"""
|
||||||
|
if deaf is not None:
|
||||||
GLib.idle_add(self.connection.set_deaf, deaf)
|
GLib.idle_add(self.connection.set_deaf, deaf)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -499,13 +503,12 @@ def entrypoint():
|
||||||
|
|
||||||
# Prepare logger
|
# Prepare logger
|
||||||
logging.getLogger().setLevel(logging.INFO)
|
logging.getLogger().setLevel(logging.INFO)
|
||||||
FORMAT = "%(levelname)s - %(name)s - %(message)s"
|
log_format = "%(levelname)s - %(name)s - %(message)s"
|
||||||
if "--debug" in sys.argv or "-v" in sys.argv:
|
if "--debug" in sys.argv or "-v" in sys.argv:
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
logging.basicConfig(filename=debug_file, format=FORMAT)
|
logging.basicConfig(filename=debug_file, format=log_format)
|
||||||
else:
|
else:
|
||||||
logging.basicConfig(format=FORMAT)
|
logging.basicConfig(format=log_format)
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
log.info("Starting Discover Overlay: %s",
|
log.info("Starting Discover Overlay: %s",
|
||||||
pkg_resources.get_distribution('discover_overlay').version)
|
pkg_resources.get_distribution('discover_overlay').version)
|
||||||
|
|
||||||
|
|
@ -520,26 +523,26 @@ def entrypoint():
|
||||||
# Send command to overlay
|
# Send command to overlay
|
||||||
line = ""
|
line = ""
|
||||||
for arg in sys.argv[1:]:
|
for arg in sys.argv[1:]:
|
||||||
line = "%s %s" % (line, arg)
|
line = f"{line} {arg}"
|
||||||
with open(rpc_file, "w") as tfile:
|
with open(rpc_file, "w", encoding="utf-8") as tfile:
|
||||||
tfile.write(line)
|
tfile.write(line)
|
||||||
log.warning("Sent RPC command")
|
log.warning("Sent RPC command")
|
||||||
else:
|
else:
|
||||||
if "-c" in sys.argv or "--configure" in sys.argv:
|
if "-c" in sys.argv or "--configure" in sys.argv:
|
||||||
# Show config window
|
# Show config window
|
||||||
settings = MainSettingsWindow(
|
_settings = MainSettingsWindow(
|
||||||
config_file, rpc_file, channel_file, sys.argv[1:])
|
config_file, rpc_file, channel_file, sys.argv[1:])
|
||||||
Gtk.main()
|
Gtk.main()
|
||||||
else:
|
else:
|
||||||
# Tell any other running overlay to close
|
# Tell any other running overlay to close
|
||||||
with open(rpc_file, "w") as tfile:
|
with open(rpc_file, "w", encoding="utf-8") as tfile:
|
||||||
tfile.write("--close")
|
tfile.write("--close")
|
||||||
# Show the overlay
|
# Show the overlay
|
||||||
Discover(rpc_file, config_file, channel_file,
|
Discover(rpc_file, config_file, channel_file,
|
||||||
debug_file, sys.argv[1:])
|
debug_file, sys.argv[1:])
|
||||||
return
|
return
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex: # pylint: disable=broad-except
|
||||||
log.error(ex)
|
log.error(ex)
|
||||||
log.error(traceback.format_exc())
|
log.error(traceback.format_exc())
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""An X11 window which can be moved and resized"""
|
"""An X11 window which can be moved and resized"""
|
||||||
|
import logging
|
||||||
import gi
|
import gi
|
||||||
import cairo
|
import cairo
|
||||||
import logging
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
# pylint: disable=wrong-import-position
|
# pylint: disable=wrong-import-position
|
||||||
from gi.repository import Gtk, Gdk # nopep8
|
from gi.repository import Gtk, Gdk # nopep8
|
||||||
|
|
@ -24,10 +24,12 @@ log = logging.getLogger(__name__)
|
||||||
class DraggableWindow(Gtk.Window):
|
class DraggableWindow(Gtk.Window):
|
||||||
"""An X11 window which can be moved and resized"""
|
"""An X11 window which can be moved and resized"""
|
||||||
|
|
||||||
def __init__(self, pos_x=0.0, pos_y=0.0, width=0.1, height=0.1, message="Message", settings=None, monitor=None):
|
def __init__(self, pos_x=0.0, pos_y=0.0, width=0.1, height=0.1,
|
||||||
|
message="Message", settings=None, monitor=None):
|
||||||
Gtk.Window.__init__(self, type=Gtk.WindowType.POPUP)
|
Gtk.Window.__init__(self, type=Gtk.WindowType.POPUP)
|
||||||
self.monitor = monitor
|
self.monitor = monitor
|
||||||
(screen_x, screen_y, screen_width, screen_height) = self.get_display_coords()
|
(_screen_x, _screen_y, screen_width,
|
||||||
|
screen_height) = self.get_display_coords()
|
||||||
self.pos_x = pos_x * screen_width
|
self.pos_x = pos_x * screen_width
|
||||||
self.pos_y = pos_y * screen_height
|
self.pos_y = pos_y * screen_height
|
||||||
self.width = max(40, width * screen_width)
|
self.width = max(40, width * screen_width)
|
||||||
|
|
@ -84,8 +86,8 @@ class DraggableWindow(Gtk.Window):
|
||||||
if event.state & Gdk.ModifierType.BUTTON1_MASK:
|
if event.state & Gdk.ModifierType.BUTTON1_MASK:
|
||||||
if self.drag_type == 1:
|
if self.drag_type == 1:
|
||||||
# Center is move
|
# Center is move
|
||||||
(screen_x, screen_y, screen_width,
|
(screen_x, screen_y, _screen_width,
|
||||||
screen_height) = self.get_display_coords()
|
_screen_height) = self.get_display_coords()
|
||||||
self.pos_x = (event.x_root - screen_x) - self.drag_x
|
self.pos_x = (event.x_root - screen_x) - self.drag_x
|
||||||
self.pos_y = (event.y_root - screen_y) - self.drag_y
|
self.pos_y = (event.y_root - screen_y) - self.drag_y
|
||||||
self.force_location()
|
self.force_location()
|
||||||
|
|
@ -151,6 +153,7 @@ class DraggableWindow(Gtk.Window):
|
||||||
context.fill()
|
context.fill()
|
||||||
|
|
||||||
def get_display_coords(self):
|
def get_display_coords(self):
|
||||||
|
"""Get coordinates for this display"""
|
||||||
display = Gdk.Display.get_default()
|
display = Gdk.Display.get_default()
|
||||||
if "get_monitor" in dir(display):
|
if "get_monitor" in dir(display):
|
||||||
monitor = display.get_monitor(self.monitor)
|
monitor = display.get_monitor(self.monitor)
|
||||||
|
|
@ -171,4 +174,5 @@ class DraggableWindow(Gtk.Window):
|
||||||
height = float(height)
|
height = float(height)
|
||||||
pos_x = pos_x / scale
|
pos_x = pos_x / scale
|
||||||
pos_y = pos_y / scale
|
pos_y = pos_y / scale
|
||||||
return (pos_x / screen_width, pos_y / screen_height, width / screen_width, height / screen_height)
|
return (pos_x / screen_width, pos_y / screen_height,
|
||||||
|
width / screen_width, height / screen_height)
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""A Wayland full-screen window which can be moved and resized"""
|
"""A Wayland full-screen window which can be moved and resized"""
|
||||||
|
import logging
|
||||||
import cairo
|
import cairo
|
||||||
import gi
|
import gi
|
||||||
import logging
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
# pylint: disable=wrong-import-position
|
# pylint: disable=wrong-import-position
|
||||||
from gi.repository import Gtk, Gdk # nopep8
|
from gi.repository import Gtk, Gdk # nopep8
|
||||||
|
|
@ -29,12 +29,14 @@ log = logging.getLogger(__name__)
|
||||||
class DraggableWindowWayland(Gtk.Window):
|
class DraggableWindowWayland(Gtk.Window):
|
||||||
"""A Wayland full-screen window which can be moved and resized"""
|
"""A Wayland full-screen window which can be moved and resized"""
|
||||||
|
|
||||||
def __init__(self, pos_x=0.0, pos_y=0.0, width=0.1, height=0.1, message="Message", settings=None, steamos=False, monitor=None):
|
def __init__(self, pos_x=0.0, pos_y=0.0, width=0.1, height=0.1,
|
||||||
|
message="Message", settings=None, steamos=False, monitor=None):
|
||||||
Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL)
|
Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL)
|
||||||
if steamos:
|
if steamos:
|
||||||
monitor = 0
|
monitor = 0
|
||||||
self.monitor = monitor
|
self.monitor = monitor
|
||||||
(screen_x, screen_y, screen_width, screen_height) = self.get_display_coords()
|
(_screen_x, _screen_y, screen_width,
|
||||||
|
screen_height) = self.get_display_coords()
|
||||||
self.pos_x = pos_x * screen_width
|
self.pos_x = pos_x * screen_width
|
||||||
self.pos_y = pos_y * screen_height
|
self.pos_y = pos_y * screen_height
|
||||||
self.width = max(40, width * screen_width)
|
self.width = max(40, width * screen_width)
|
||||||
|
|
@ -48,8 +50,8 @@ class DraggableWindowWayland(Gtk.Window):
|
||||||
self.connect('button-press-event', self.button_press)
|
self.connect('button-press-event', self.button_press)
|
||||||
self.connect('button-release-event', self.button_release)
|
self.connect('button-release-event', self.button_release)
|
||||||
|
|
||||||
log.info("Starting: %d,%d %d x %d" %
|
log.info("Starting: %d,%d %d x %d",
|
||||||
(self.pos_x, self.pos_y, self.width, self.height))
|
self.pos_x, self.pos_y, self.width, self.height)
|
||||||
|
|
||||||
self.set_app_paintable(True)
|
self.set_app_paintable(True)
|
||||||
|
|
||||||
|
|
@ -76,21 +78,24 @@ class DraggableWindowWayland(Gtk.Window):
|
||||||
self.force_location()
|
self.force_location()
|
||||||
|
|
||||||
def set_steamos_window_size(self):
|
def set_steamos_window_size(self):
|
||||||
|
"""Prepare window for a gamescope steamos session"""
|
||||||
# Huge bunch of assumptions.
|
# Huge bunch of assumptions.
|
||||||
# Gamescope only has one monitor
|
# Gamescope only has one monitor
|
||||||
# Gamescope has no scale factor
|
# Gamescope has no scale factor
|
||||||
|
# Probably never possible to reach here, as Gamescope/SteamOS
|
||||||
|
# is X11 for overlays
|
||||||
display = Gdk.Display.get_default()
|
display = Gdk.Display.get_default()
|
||||||
if "get_monitor" in dir(display):
|
if "get_monitor" in dir(display):
|
||||||
monitor = display.get_monitor(0)
|
monitor = display.get_monitor(0)
|
||||||
if monitor:
|
if monitor:
|
||||||
geometry = monitor.get_geometry()
|
geometry = monitor.get_geometry()
|
||||||
scale_factor = monitor.get_scale_factor()
|
log.info("%d %d", geometry.width, geometry.height)
|
||||||
log.info("%d %d" % (geometry.width, geometry.height))
|
|
||||||
self.set_size_request(geometry.width, geometry.height)
|
self.set_size_request(geometry.width, geometry.height)
|
||||||
|
|
||||||
def force_location(self):
|
def force_location(self):
|
||||||
"""Move the window to previously given co-ords. In wayland just clip to current screen"""
|
"""Move the window to previously given co-ords. In wayland just clip to current screen"""
|
||||||
(screen_x, screen_y, screen_width, screen_height) = self.get_display_coords()
|
(_screen_x, _screen_y, screen_width,
|
||||||
|
screen_height) = self.get_display_coords()
|
||||||
self.width = min(self.width, screen_width)
|
self.width = min(self.width, screen_width)
|
||||||
self.height = min(self.height, screen_height)
|
self.height = min(self.height, screen_height)
|
||||||
self.pos_x = max(0, self.pos_x)
|
self.pos_x = max(0, self.pos_x)
|
||||||
|
|
@ -189,6 +194,7 @@ class DraggableWindowWayland(Gtk.Window):
|
||||||
context.restore()
|
context.restore()
|
||||||
|
|
||||||
def get_display_coords(self):
|
def get_display_coords(self):
|
||||||
|
"""Get coordinates from display"""
|
||||||
display = Gdk.Display.get_default()
|
display = Gdk.Display.get_default()
|
||||||
if "get_monitor" in dir(display):
|
if "get_monitor" in dir(display):
|
||||||
monitor = display.get_monitor(self.monitor)
|
monitor = display.get_monitor(self.monitor)
|
||||||
|
|
@ -199,5 +205,7 @@ class DraggableWindowWayland(Gtk.Window):
|
||||||
|
|
||||||
def get_coords(self):
|
def get_coords(self):
|
||||||
"""Return the position and size of the window"""
|
"""Return the position and size of the window"""
|
||||||
(screen_x, screen_y, screen_width, screen_height) = self.get_display_coords()
|
(_screen_x, _screen_y, screen_width,
|
||||||
return (float(self.pos_x) / screen_width, float(self.pos_y) / screen_height, float(self.width) / screen_width, float(self.height) / screen_height)
|
screen_height) = self.get_display_coords()
|
||||||
|
return (float(self.pos_x) / screen_width, float(self.pos_y) / screen_height,
|
||||||
|
float(self.width) / screen_width, float(self.height) / screen_height)
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,19 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""Functions & Classes to assist image loading."""
|
"""Functions & Classes to assist image loading."""
|
||||||
import urllib
|
|
||||||
import threading
|
import threading
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import copy
|
||||||
import gi
|
import gi
|
||||||
import requests
|
import requests
|
||||||
import cairo
|
import cairo
|
||||||
import PIL
|
import PIL
|
||||||
import PIL.Image as Image
|
import PIL.Image as Image
|
||||||
import os
|
|
||||||
import io
|
|
||||||
import copy
|
|
||||||
gi.require_version('GdkPixbuf', '2.0')
|
gi.require_version('GdkPixbuf', '2.0')
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
# pylint: disable=wrong-import-position
|
# pylint: disable=wrong-import-position
|
||||||
from gi.repository import Gio, GdkPixbuf, Gtk # nopep8
|
from gi.repository import Gtk # nopep8
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -43,7 +41,7 @@ class SurfaceGetter():
|
||||||
"""Downloads and decodes"""
|
"""Downloads and decodes"""
|
||||||
try:
|
try:
|
||||||
resp = requests.get(
|
resp = requests.get(
|
||||||
self.url, stream=True, headers={
|
self.url, stream=True, timeout=10, headers={
|
||||||
'Referer': 'https://streamkit.discord.com/overlay/voice',
|
'Referer': 'https://streamkit.discord.com/overlay/voice',
|
||||||
'User-Agent': 'Mozilla/5.0'
|
'User-Agent': 'Mozilla/5.0'
|
||||||
}
|
}
|
||||||
|
|
@ -69,6 +67,7 @@ class SurfaceGetter():
|
||||||
log.error("Unknown image type: %s", self.url)
|
log.error("Unknown image type: %s", self.url)
|
||||||
|
|
||||||
def get_file(self):
|
def get_file(self):
|
||||||
|
"""Attempt to load the file"""
|
||||||
errors = []
|
errors = []
|
||||||
# Grab icon from icon theme
|
# Grab icon from icon theme
|
||||||
icon_theme = Gtk.IconTheme.get_default()
|
icon_theme = Gtk.IconTheme.get_default()
|
||||||
|
|
@ -99,13 +98,13 @@ class SurfaceGetter():
|
||||||
try:
|
try:
|
||||||
image = Image.open(mixpath)
|
image = Image.open(mixpath)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
errors.append("Value Error - Unable to read %s" % (mixpath))
|
errors.append(f"Value Error - Unable to read {mixpath}")
|
||||||
except TypeError:
|
except TypeError:
|
||||||
errors.append("Type Error - Unable to read %s" % (mixpath))
|
errors.append(f"Type Error - Unable to read {mixpath}")
|
||||||
except PIL.UnidentifiedImageError:
|
except PIL.UnidentifiedImageError:
|
||||||
errors.append("Unknown image type: %s" % (mixpath))
|
errors.append(f"Unknown image type: {mixpath}")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
errors.append("File not found: %s" % (mixpath))
|
errors.append(f"File not found: {mixpath}")
|
||||||
if image:
|
if image:
|
||||||
(surface, mask) = from_pil(image)
|
(surface, mask) = from_pil(image)
|
||||||
if surface:
|
if surface:
|
||||||
|
|
@ -115,7 +114,7 @@ class SurfaceGetter():
|
||||||
log.error(error)
|
log.error(error)
|
||||||
|
|
||||||
|
|
||||||
def from_pil(image, alpha=1.0, format='BGRa'):
|
def from_pil(image, alpha=1.0, image_format='BGRa'):
|
||||||
"""
|
"""
|
||||||
:param im: Pillow Image
|
:param im: Pillow Image
|
||||||
:param alpha: 0..1 alpha to add to non-alpha images
|
:param alpha: 0..1 alpha to add to non-alpha images
|
||||||
|
|
@ -125,10 +124,10 @@ def from_pil(image, alpha=1.0, format='BGRa'):
|
||||||
mask = bytearray()
|
mask = bytearray()
|
||||||
if 'A' not in image.getbands():
|
if 'A' not in image.getbands():
|
||||||
image.putalpha(int(alpha * 255.0))
|
image.putalpha(int(alpha * 255.0))
|
||||||
arr = bytearray(image.tobytes('raw', format))
|
arr = bytearray(image.tobytes('raw', image_format))
|
||||||
mask = arr
|
mask = arr
|
||||||
else:
|
else:
|
||||||
arr = bytearray(image.tobytes('raw', format))
|
arr = bytearray(image.tobytes('raw', image_format))
|
||||||
mask = copy.deepcopy((arr))
|
mask = copy.deepcopy((arr))
|
||||||
idx = 0
|
idx = 0
|
||||||
while idx < len(arr):
|
while idx < len(arr):
|
||||||
|
|
@ -148,9 +147,12 @@ def from_pil(image, alpha=1.0, format='BGRa'):
|
||||||
|
|
||||||
|
|
||||||
def to_pil(surface):
|
def to_pil(surface):
|
||||||
|
"""Return a PIL Image from the Cairo surface"""
|
||||||
if surface.get_format() == cairo.Format.ARGB32:
|
if surface.get_format() == cairo.Format.ARGB32:
|
||||||
return Image.frombuffer('RGBA', (surface.get_width(), surface.get_height()), surface.get_data(), 'raw', "BGRA", surface.get_stride())
|
return Image.frombuffer('RGBA', (surface.get_width(), surface.get_height()),
|
||||||
return Image.frombuffer("RGB", (surface.get_width(), surface.get_height()), surface.get_data(), 'raw', "BGRX", surface.get_stride())
|
surface.get_data(), 'raw', "BGRA", surface.get_stride())
|
||||||
|
return Image.frombuffer("RGB", (surface.get_width(), surface.get_height()),
|
||||||
|
surface.get_data(), 'raw', "BGRX", surface.get_stride())
|
||||||
|
|
||||||
|
|
||||||
def get_surface(func, identifier, ava, size):
|
def get_surface(func, identifier, ava, size):
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,15 @@
|
||||||
"""Notification window for text"""
|
"""Notification window for text"""
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
import re
|
|
||||||
import cairo
|
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
import cairo
|
||||||
import gi
|
import gi
|
||||||
from .image_getter import get_surface, draw_img_to_rect, get_aspected_size
|
from .image_getter import get_surface, draw_img_to_rect
|
||||||
from .overlay import OverlayWindow
|
from .overlay import OverlayWindow
|
||||||
gi.require_version("Gtk", "3.0")
|
|
||||||
gi.require_version('PangoCairo', '1.0')
|
gi.require_version('PangoCairo', '1.0')
|
||||||
# pylint: disable=wrong-import-position,wrong-import-order
|
# pylint: disable=wrong-import-position,wrong-import-order
|
||||||
from gi.repository import Gtk, Pango, PangoCairo # nopep8
|
from gi.repository import Pango, PangoCairo # nopep8
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -34,12 +33,54 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
OverlayWindow.__init__(self, discover, piggyback)
|
OverlayWindow.__init__(self, discover, piggyback)
|
||||||
self.text_spacing = 4
|
self.text_spacing = 4
|
||||||
self.content = []
|
self.content = []
|
||||||
self.test_content = [{"icon": "https://cdn.discordapp.com/icons/951077080769114172/991abffc0d2a5c040444be4d1a4085f4.webp?size=96", "title": "Title1"},
|
self.test_content = [
|
||||||
{"title": "Title2", "body": "Body", "icon": None},
|
{
|
||||||
{"icon": "https://cdn.discordapp.com/icons/951077080769114172/991abffc0d2a5c040444be4d1a4085f4.webp?size=96", "title": "Title 3",
|
"icon": (
|
||||||
"body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."},
|
"https://cdn.discordapp.com/"
|
||||||
{"icon": None, "title": "Title 3", "body": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."},
|
"icons/951077080769114172/991abffc0d2a5c040444be4d1a4085f4.webp?size=96"
|
||||||
{"icon": "https://cdn.discordapp.com/avatars/147077941317206016/6a6935192076489fa6dc1eb5dafbf6e7.webp?size=128", "title": "PM", "body": "Birdy test"}]
|
),
|
||||||
|
"title": "Title1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Title2",
|
||||||
|
"body": "Body",
|
||||||
|
"icon": None
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": ("https://cdn.discordapp.com/"
|
||||||
|
"icons/951077080769114172/991abffc0d2a5c040444be4d1a4085f4.webp?size=96"
|
||||||
|
),
|
||||||
|
"title": "Title 3",
|
||||||
|
"body": ("Lorem ipsum dolor sit amet, consectetur adipiscing elit,"
|
||||||
|
" sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
|
||||||
|
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris "
|
||||||
|
"nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
|
||||||
|
"reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla "
|
||||||
|
"pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa "
|
||||||
|
"qui officia deserunt mollit anim id est laborum."
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": None,
|
||||||
|
"title": "Title 3",
|
||||||
|
"body": ("Lorem ipsum dolor sit amet, consectetur adipiscing elit, "
|
||||||
|
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
|
||||||
|
"Ut enim ad minim veniam, quis nostrud exercitation ullamco "
|
||||||
|
"laboris nisi ut aliquip ex ea commodo consequat. Duis aute "
|
||||||
|
"irure dolor in reprehenderit in voluptate velit esse cillum "
|
||||||
|
"dolore eu fugiat nulla pariatur. Excepteur sint occaecat "
|
||||||
|
"cupidatat non proident, sunt in culpa qui officia deserunt "
|
||||||
|
"mollit anim id est laborum."
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": ("https://cdn.discordapp.com/"
|
||||||
|
"avatars/147077941317206016/6a6935192076489fa6dc1eb5dafbf6e7.webp?size=128"
|
||||||
|
),
|
||||||
|
"title": "PM",
|
||||||
|
"body": "Birdy test"
|
||||||
|
}
|
||||||
|
]
|
||||||
self.text_font = None
|
self.text_font = None
|
||||||
self.text_size = 13
|
self.text_size = 13
|
||||||
self.text_time = None
|
self.text_time = None
|
||||||
|
|
@ -67,11 +108,12 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
self.redraw()
|
self.redraw()
|
||||||
|
|
||||||
def set_blank(self):
|
def set_blank(self):
|
||||||
|
"""Set to no data and redraw"""
|
||||||
self.content = []
|
self.content = []
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def tick(self):
|
def tick(self):
|
||||||
# This doesn't really belong in overlay or settings
|
"""Remove old messages from dataset"""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
newlist = []
|
newlist = []
|
||||||
oldsize = len(self.content)
|
oldsize = len(self.content)
|
||||||
|
|
@ -85,6 +127,7 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def add_notification_message(self, data):
|
def add_notification_message(self, data):
|
||||||
|
"""Add new message to dataset"""
|
||||||
noti = None
|
noti = None
|
||||||
data = data['data']
|
data = data['data']
|
||||||
message_id = data['message']['id']
|
message_id = data['message']['id']
|
||||||
|
|
@ -108,59 +151,50 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
self.get_all_images()
|
self.get_all_images()
|
||||||
|
|
||||||
def set_padding(self, padding):
|
def set_padding(self, padding):
|
||||||
"""
|
"""Config option: Padding between notifications, in window-space pixels"""
|
||||||
Set the padding between notifications
|
|
||||||
"""
|
|
||||||
if self.padding != padding:
|
if self.padding != padding:
|
||||||
self.padding = padding
|
self.padding = padding
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_border_radius(self, radius):
|
def set_border_radius(self, radius):
|
||||||
"""
|
"""Config option: Radius of the border, in window-space pixels"""
|
||||||
Set the radius of the border
|
|
||||||
"""
|
|
||||||
if self.border_radius != radius:
|
if self.border_radius != radius:
|
||||||
self.border_radius = radius
|
self.border_radius = radius
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_icon_size(self, size):
|
def set_icon_size(self, size):
|
||||||
"""
|
"""Config option: Size of icons, in window-space pixels"""
|
||||||
Set Icon size
|
|
||||||
"""
|
|
||||||
if self.icon_size != size:
|
if self.icon_size != size:
|
||||||
self.icon_size = size
|
self.icon_size = size
|
||||||
self.image_list = {}
|
self.image_list = {}
|
||||||
self.get_all_images()
|
self.get_all_images()
|
||||||
|
|
||||||
def set_icon_pad(self, pad):
|
def set_icon_pad(self, pad):
|
||||||
"""
|
"""Config option: Padding between icon and message, in window-space pixels"""
|
||||||
Set padding between icon and message
|
|
||||||
"""
|
|
||||||
if self.icon_pad != pad:
|
if self.icon_pad != pad:
|
||||||
self.icon_pad = pad
|
self.icon_pad = pad
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_icon_left(self, left):
|
def set_icon_left(self, left):
|
||||||
|
"""Config option: Icon on left or right of text"""
|
||||||
if self.icon_left != left:
|
if self.icon_left != left:
|
||||||
self.icon_left = left
|
self.icon_left = left
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_text_time(self, timer):
|
def set_text_time(self, timer):
|
||||||
"""
|
"""Config option: Duration that a message will be visible for, in seconds"""
|
||||||
Set the duration that a message will be visible for.
|
|
||||||
"""
|
|
||||||
self.text_time = timer
|
self.text_time = timer
|
||||||
self.timer_after_draw = timer
|
self.timer_after_draw = timer
|
||||||
|
|
||||||
def set_limit_width(self, limit):
|
def set_limit_width(self, limit):
|
||||||
"""
|
"""Config option: Word wrap limit, in window-space pixels
|
||||||
Set the word wrap limit in pixels
|
|
||||||
"""
|
"""
|
||||||
if self.limit_width != limit:
|
if self.limit_width != limit:
|
||||||
self.limit_width = limit
|
self.limit_width = limit
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def get_all_images(self):
|
def get_all_images(self):
|
||||||
|
"""Return a list of all downloaded images"""
|
||||||
the_list = self.content
|
the_list = self.content
|
||||||
if self.testing:
|
if self.testing:
|
||||||
the_list = self.test_content
|
the_list = self.test_content
|
||||||
|
|
@ -171,47 +205,38 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
get_surface(self.recv_icon, icon, icon,
|
get_surface(self.recv_icon, icon, icon,
|
||||||
self.icon_size)
|
self.icon_size)
|
||||||
|
|
||||||
def recv_icon(self, identifier, pix, mask):
|
def recv_icon(self, identifier, pix, _mask):
|
||||||
"""
|
"""Callback from image_getter for icons"""
|
||||||
Called when image_getter has downloaded an image
|
|
||||||
"""
|
|
||||||
self.image_list[identifier] = pix
|
self.image_list[identifier] = pix
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_fg(self, fg_col):
|
def set_fg(self, fg_col):
|
||||||
"""
|
"""Config option: Set default text colour"""
|
||||||
Set default text colour
|
|
||||||
"""
|
|
||||||
if self.fg_col != fg_col:
|
if self.fg_col != fg_col:
|
||||||
self.fg_col = fg_col
|
self.fg_col = fg_col
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_bg(self, bg_col):
|
def set_bg(self, bg_col):
|
||||||
"""
|
"""Config option: Set background colour"""
|
||||||
Set background colour
|
|
||||||
"""
|
|
||||||
if self.bg_col != bg_col:
|
if self.bg_col != bg_col:
|
||||||
self.bg_col = bg_col
|
self.bg_col = bg_col
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_show_icon(self, icon):
|
def set_show_icon(self, icon):
|
||||||
"""
|
"""Config option: Set if icons should be shown inline"""
|
||||||
Set if icons should be shown inline
|
|
||||||
"""
|
|
||||||
if self.show_icon != icon:
|
if self.show_icon != icon:
|
||||||
self.show_icon = icon
|
self.show_icon = icon
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
self.get_all_images()
|
self.get_all_images()
|
||||||
|
|
||||||
def set_reverse_order(self, rev):
|
def set_reverse_order(self, rev):
|
||||||
|
"""Config option: Reverse order of messages"""
|
||||||
if self.reverse_order != rev:
|
if self.reverse_order != rev:
|
||||||
self.reverse_order = rev
|
self.reverse_order = rev
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_font(self, font):
|
def set_font(self, font):
|
||||||
"""
|
"""Config option: Font used to render text"""
|
||||||
Set font used to render text
|
|
||||||
"""
|
|
||||||
if self.text_font != font:
|
if self.text_font != font:
|
||||||
self.text_font = font
|
self.text_font = font
|
||||||
|
|
||||||
|
|
@ -222,13 +247,13 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def recv_attach(self, identifier, pix):
|
def recv_attach(self, identifier, pix):
|
||||||
"""
|
"""Callback from image_getter for attachments"""
|
||||||
Called when an image has been downloaded by image_getter
|
|
||||||
"""
|
|
||||||
self.icons[identifier] = pix
|
self.icons[identifier] = pix
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def calc_all_height(self):
|
def calc_all_height(self):
|
||||||
|
"""Return the height in window-space pixels required
|
||||||
|
to draw this overlay with current dataset"""
|
||||||
h = 0
|
h = 0
|
||||||
my_list = self.content
|
my_list = self.content
|
||||||
if self.testing:
|
if self.testing:
|
||||||
|
|
@ -240,6 +265,7 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
return h
|
return h
|
||||||
|
|
||||||
def calc_height(self, line):
|
def calc_height(self, line):
|
||||||
|
"""Return height in window-space pixels required to draw individual notification"""
|
||||||
icon_width = 0
|
icon_width = 0
|
||||||
icon_pad = 0
|
icon_pad = 0
|
||||||
icon = line['icon']
|
icon = line['icon']
|
||||||
|
|
@ -257,9 +283,8 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
layout = self.create_pango_layout(message)
|
layout = self.create_pango_layout(message)
|
||||||
layout.set_auto_dir(True)
|
layout.set_auto_dir(True)
|
||||||
layout.set_markup(message, -1)
|
layout.set_markup(message, -1)
|
||||||
attr = layout.get_attributes()
|
(_floating_x, _floating_y, floating_width,
|
||||||
(floating_x, floating_y, floating_width,
|
_floating_height) = self.get_floating_coords()
|
||||||
floating_height) = self.get_floating_coords()
|
|
||||||
width = self.limit_width if floating_width > self.limit_width else floating_width
|
width = self.limit_width if floating_width > self.limit_width else floating_width
|
||||||
layout.set_width((Pango.SCALE * (width -
|
layout.set_width((Pango.SCALE * (width -
|
||||||
(self.border_radius * 4 + icon_width + icon_pad))))
|
(self.border_radius * 4 + icon_width + icon_pad))))
|
||||||
|
|
@ -267,12 +292,13 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
if self.text_font:
|
if self.text_font:
|
||||||
font = Pango.FontDescription(self.text_font)
|
font = Pango.FontDescription(self.text_font)
|
||||||
layout.set_font_description(font)
|
layout.set_font_description(font)
|
||||||
text_width, text_height = layout.get_pixel_size()
|
_text_width, text_height = layout.get_pixel_size()
|
||||||
if text_height < icon_width:
|
if text_height < icon_width:
|
||||||
text_height = icon_width
|
text_height = icon_width
|
||||||
return text_height + (self.border_radius*4) + self.padding
|
return text_height + (self.border_radius*4) + self.padding
|
||||||
|
|
||||||
def has_content(self):
|
def has_content(self):
|
||||||
|
"""Return true if this overlay has meaningful content to show"""
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
return False
|
return False
|
||||||
if self.hidden:
|
if self.hidden:
|
||||||
|
|
@ -282,15 +308,13 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
return self.content
|
return self.content
|
||||||
|
|
||||||
def overlay_draw(self, w, context, data=None):
|
def overlay_draw(self, w, context, data=None):
|
||||||
"""
|
"""Draw the overlay"""
|
||||||
Draw the overlay
|
|
||||||
"""
|
|
||||||
if self.piggyback:
|
if self.piggyback:
|
||||||
self.piggyback.overlay_draw(w, context, data)
|
self.piggyback.overlay_draw(w, context, data)
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
return
|
return
|
||||||
self.context = context
|
self.context = context
|
||||||
(width, height) = self.get_size()
|
(_width, height) = self.get_size()
|
||||||
if not self.piggyback_parent:
|
if not self.piggyback_parent:
|
||||||
context.set_antialias(cairo.ANTIALIAS_GOOD)
|
context.set_antialias(cairo.ANTIALIAS_GOOD)
|
||||||
|
|
||||||
|
|
@ -319,7 +343,6 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
current_y = 0
|
current_y = 0
|
||||||
if self.align_vert == 1: # Center. Oh god why
|
if self.align_vert == 1: # Center. Oh god why
|
||||||
current_y = (height/2.0) - (self.calc_all_height() / 2.0)
|
current_y = (height/2.0) - (self.calc_all_height() / 2.0)
|
||||||
tnow = time.time()
|
|
||||||
if self.testing:
|
if self.testing:
|
||||||
the_list = self.test_content
|
the_list = self.test_content
|
||||||
else:
|
else:
|
||||||
|
|
@ -354,10 +377,7 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
self.context = None
|
self.context = None
|
||||||
|
|
||||||
def draw_text(self, pos_y, text, icon):
|
def draw_text(self, pos_y, text, icon):
|
||||||
"""
|
"""Draw a text message, returning the Y position of the next message"""
|
||||||
Draw a text message, returning the Y position of the next message
|
|
||||||
"""
|
|
||||||
|
|
||||||
icon_width = self.icon_size
|
icon_width = self.icon_size
|
||||||
icon_pad = self.icon_pad
|
icon_pad = self.icon_pad
|
||||||
if not self.show_icon:
|
if not self.show_icon:
|
||||||
|
|
@ -371,8 +391,8 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
layout.set_markup(text, -1)
|
layout.set_markup(text, -1)
|
||||||
attr = layout.get_attributes()
|
attr = layout.get_attributes()
|
||||||
|
|
||||||
(floating_x, floating_y, floating_width,
|
(_floating_x, _floating_y, floating_width,
|
||||||
floating_height) = self.get_floating_coords()
|
_floating_height) = self.get_floating_coords()
|
||||||
width = self.limit_width if floating_width > self.limit_width else floating_width
|
width = self.limit_width if floating_width > self.limit_width else floating_width
|
||||||
layout.set_width((Pango.SCALE * (width -
|
layout.set_width((Pango.SCALE * (width -
|
||||||
(self.border_radius * 4 + icon_width + icon_pad))))
|
(self.border_radius * 4 + icon_width + icon_pad))))
|
||||||
|
|
@ -475,7 +495,6 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
self.get_pango_context(), self.render_custom, None)
|
self.get_pango_context(), self.render_custom, None)
|
||||||
|
|
||||||
text = layout.get_text()
|
text = layout.get_text()
|
||||||
count = 0
|
|
||||||
|
|
||||||
layout.set_attributes(attr)
|
layout.set_attributes(attr)
|
||||||
|
|
||||||
|
|
@ -486,7 +505,6 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
self.get_pango_context(), self.render_custom, None)
|
self.get_pango_context(), self.render_custom, None)
|
||||||
|
|
||||||
text = layout.get_text()
|
text = layout.get_text()
|
||||||
count = 0
|
|
||||||
|
|
||||||
layout.set_attributes(attr)
|
layout.set_attributes(attr)
|
||||||
|
|
||||||
|
|
@ -501,11 +519,9 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
return next_y
|
return next_y
|
||||||
|
|
||||||
def render_custom(self, ctx, shape, path, _data):
|
def render_custom(self, ctx, shape, path, _data):
|
||||||
"""
|
"""Draw an inline image as a custom emoticon"""
|
||||||
Draw an inline image as a custom emoticon
|
|
||||||
"""
|
|
||||||
if shape.data >= len(self.image_list):
|
if shape.data >= len(self.image_list):
|
||||||
log.warning(f"{shape.data} >= {len(self.image_list)}")
|
log.warning("%s >= %s", shape.data, len(self.image_list))
|
||||||
return
|
return
|
||||||
# key is the url to the image
|
# key is the url to the image
|
||||||
key = self.image_list[shape.data]
|
key = self.image_list[shape.data]
|
||||||
|
|
@ -521,9 +537,7 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def sanitize_string(self, string):
|
def sanitize_string(self, string):
|
||||||
"""
|
"""Sanitize a text message so that it doesn't intefere with Pango's XML format"""
|
||||||
Sanitize a text message so that it doesn't intefere with Pango's XML format
|
|
||||||
"""
|
|
||||||
string = string.replace("&", "&")
|
string = string.replace("&", "&")
|
||||||
string = string.replace("<", "<")
|
string = string.replace("<", "<")
|
||||||
string = string .replace(">", ">")
|
string = string .replace(">", ">")
|
||||||
|
|
@ -532,6 +546,7 @@ class NotificationOverlayWindow(OverlayWindow):
|
||||||
return string
|
return string
|
||||||
|
|
||||||
def set_testing(self, testing):
|
def set_testing(self, testing):
|
||||||
|
"""Toggle placeholder images for testing"""
|
||||||
self.testing = testing
|
self.testing = testing
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
self.get_all_images()
|
self.get_all_images()
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import sys
|
||||||
import logging
|
import logging
|
||||||
import gi
|
import gi
|
||||||
import cairo
|
import cairo
|
||||||
import Xlib
|
|
||||||
from Xlib.display import Display
|
from Xlib.display import Display
|
||||||
from Xlib import X, Xatom
|
from Xlib import X, Xatom
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
|
|
@ -46,7 +45,7 @@ class OverlayWindow(Gtk.Window):
|
||||||
"""
|
"""
|
||||||
window = Gtk.Window()
|
window = Gtk.Window()
|
||||||
screen = window.get_screen()
|
screen = window.get_screen()
|
||||||
screen_type = "%s" % (screen)
|
screen_type = f"{screen}"
|
||||||
self.is_wayland = False
|
self.is_wayland = False
|
||||||
if "Wayland" in screen_type:
|
if "Wayland" in screen_type:
|
||||||
self.is_wayland = True
|
self.is_wayland = True
|
||||||
|
|
@ -124,10 +123,12 @@ class OverlayWindow(Gtk.Window):
|
||||||
# this process hanging if it happens
|
# this process hanging if it happens
|
||||||
self.connect('destroy', self.window_exited)
|
self.connect('destroy', self.window_exited)
|
||||||
|
|
||||||
def window_exited(self, window=None):
|
def window_exited(self, _window=None):
|
||||||
|
"""Window closed. Exit app"""
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def set_gamescope_xatom(self, enabled):
|
def set_gamescope_xatom(self, enabled):
|
||||||
|
"""Set Gamescope XAtom to identify self as an overlay candidate"""
|
||||||
if self.piggyback_parent:
|
if self.piggyback_parent:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -136,7 +137,7 @@ class OverlayWindow(Gtk.Window):
|
||||||
self.is_xatom_set = enabled
|
self.is_xatom_set = enabled
|
||||||
display = Display()
|
display = Display()
|
||||||
atom = display.intern_atom("GAMESCOPE_EXTERNAL_OVERLAY")
|
atom = display.intern_atom("GAMESCOPE_EXTERNAL_OVERLAY")
|
||||||
opaq = display.intern_atom("_NET_WM_WINDOW_OPACITY")
|
# Since unused: _NET_WM_WINDOW_OPACITY
|
||||||
|
|
||||||
if self.get_toplevel().get_window():
|
if self.get_toplevel().get_window():
|
||||||
topw = display.create_resource_object(
|
topw = display.create_resource_object(
|
||||||
|
|
@ -148,7 +149,7 @@ class OverlayWindow(Gtk.Window):
|
||||||
log.info("Setting GAMESCOPE_EXTERNAL_OVERLAY to %s", enabled)
|
log.info("Setting GAMESCOPE_EXTERNAL_OVERLAY to %s", enabled)
|
||||||
display.sync()
|
display.sync()
|
||||||
else:
|
else:
|
||||||
log.warn("Unable to set GAMESCOPE_EXTERNAL_OVERLAY")
|
log.warning("Unable to set GAMESCOPE_EXTERNAL_OVERLAY")
|
||||||
|
|
||||||
def set_wayland_state(self):
|
def set_wayland_state(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -169,13 +170,16 @@ class OverlayWindow(Gtk.Window):
|
||||||
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.TOP, True)
|
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.TOP, True)
|
||||||
|
|
||||||
def set_piggyback(self, other_overlay):
|
def set_piggyback(self, other_overlay):
|
||||||
|
"""Sets as piggybacking off the given (other) overlay"""
|
||||||
other_overlay.piggyback = self
|
other_overlay.piggyback = self
|
||||||
self.piggyback_parent = other_overlay
|
self.piggyback_parent = other_overlay
|
||||||
|
|
||||||
def has_content(self):
|
def has_content(self):
|
||||||
|
"""Return true if overlay has meaningful content"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def overlay_draw_pre(self, _w, context, data=None):
|
def overlay_draw_pre(self, _w, context, data=None):
|
||||||
|
"""Prepare for drawing the overlay. Calls overlay_draw after preparations"""
|
||||||
content = self.has_content()
|
content = self.has_content()
|
||||||
if self.piggyback and self.piggyback.has_content():
|
if self.piggyback and self.piggyback.has_content():
|
||||||
content = True
|
content = True
|
||||||
|
|
@ -224,16 +228,18 @@ class OverlayWindow(Gtk.Window):
|
||||||
"""
|
"""
|
||||||
if width > 1.0 and height > 1.0:
|
if width > 1.0 and height > 1.0:
|
||||||
# Old data.
|
# Old data.
|
||||||
(screen_x, screen_y, screen_width,
|
(_screen_x, _screen_y, screen_width,
|
||||||
screen_height) = self.get_display_coords()
|
screen_height) = self.get_display_coords()
|
||||||
pos_x = float(pos_x) / screen_width
|
pos_x = float(pos_x) / screen_width
|
||||||
pos_y = float(pos_y) / screen_height
|
pos_y = float(pos_y) / screen_height
|
||||||
width = float(width) / screen_width
|
width = float(width) / screen_width
|
||||||
height = float(height) / screen_height
|
height = float(height) / screen_height
|
||||||
|
|
||||||
if self.floating != floating or self.pos_x != pos_x or self.pos_y != pos_y or self.width != width or self.height != height:
|
if (self.floating != floating or self.pos_x != pos_x or
|
||||||
|
self.pos_y != pos_y or self.width != width or self.height != height):
|
||||||
# Special case for Cinnamon desktop : see https://github.com/trigg/Discover/issues/322
|
# Special case for Cinnamon desktop : see https://github.com/trigg/Discover/issues/322
|
||||||
if 'XDG_SESSION_DESKTOP' in os.environ and os.environ['XDG_SESSION_DESKTOP'] == 'cinnamon':
|
if ('XDG_SESSION_DESKTOP' in os.environ and
|
||||||
|
os.environ['XDG_SESSION_DESKTOP'] == 'cinnamon'):
|
||||||
floating = True
|
floating = True
|
||||||
|
|
||||||
self.floating = floating
|
self.floating = floating
|
||||||
|
|
@ -258,6 +264,7 @@ class OverlayWindow(Gtk.Window):
|
||||||
self.input_shape_combine_region(reg)
|
self.input_shape_combine_region(reg)
|
||||||
|
|
||||||
def set_hide_on_mouseover(self, hide):
|
def set_hide_on_mouseover(self, hide):
|
||||||
|
"""Set if the overlay should hide when mouse moves over it"""
|
||||||
if self.hide_on_mouseover != hide:
|
if self.hide_on_mouseover != hide:
|
||||||
self.hide_on_mouseover = hide
|
self.hide_on_mouseover = hide
|
||||||
if self.hide_on_mouseover:
|
if self.hide_on_mouseover:
|
||||||
|
|
@ -266,6 +273,7 @@ class OverlayWindow(Gtk.Window):
|
||||||
self.set_untouchable()
|
self.set_untouchable()
|
||||||
|
|
||||||
def set_mouseover_timer(self, time):
|
def set_mouseover_timer(self, time):
|
||||||
|
"""Set the time until the overlay reappears after mouse over"""
|
||||||
self.timeout_mouse_over = time
|
self.timeout_mouse_over = time
|
||||||
|
|
||||||
def unset_shape(self):
|
def unset_shape(self):
|
||||||
|
|
@ -299,6 +307,7 @@ class OverlayWindow(Gtk.Window):
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def get_display_coords(self):
|
def get_display_coords(self):
|
||||||
|
"""Get screen space co-ordinates of the monitor"""
|
||||||
if self.piggyback_parent:
|
if self.piggyback_parent:
|
||||||
return self.piggyback_parent.get_display_coords()
|
return self.piggyback_parent.get_display_coords()
|
||||||
monitor = self.get_monitor_from_plug()
|
monitor = self.get_monitor_from_plug()
|
||||||
|
|
@ -311,29 +320,35 @@ class OverlayWindow(Gtk.Window):
|
||||||
return (0, 0, 1920, 1080)
|
return (0, 0, 1920, 1080)
|
||||||
|
|
||||||
def get_floating_coords(self):
|
def get_floating_coords(self):
|
||||||
|
"""Get screen space co-ordinates of the window"""
|
||||||
(screen_x, screen_y, screen_width, screen_height) = self.get_display_coords()
|
(screen_x, screen_y, screen_width, screen_height) = self.get_display_coords()
|
||||||
if self.floating:
|
if self.floating:
|
||||||
if self.pos_x == None or self.pos_y == None or self.width == None or self.height == None:
|
if (self.pos_x is None or self.pos_y is None or
|
||||||
|
self.width is None or self.height is None):
|
||||||
log.error("No usable floating position")
|
log.error("No usable floating position")
|
||||||
|
|
||||||
if not self.is_wayland:
|
if not self.is_wayland:
|
||||||
return (screen_x + self.pos_x * screen_width, screen_y + self.pos_y * screen_height, self.width * screen_width, self.height * screen_height)
|
return (screen_x + self.pos_x * screen_width, screen_y + self.pos_y * screen_height,
|
||||||
return (self.pos_x * screen_width, self.pos_y * screen_height, self.width * screen_width, self.height * screen_height)
|
self.width * screen_width, self.height * screen_height)
|
||||||
|
return (self.pos_x * screen_width, self.pos_y * screen_height,
|
||||||
|
self.width * screen_width, self.height * screen_height)
|
||||||
else:
|
else:
|
||||||
return (screen_x, screen_y, screen_width, screen_height)
|
return (screen_x, screen_y, screen_width, screen_height)
|
||||||
|
|
||||||
def set_needs_redraw(self, be_pushy=False):
|
def set_needs_redraw(self, be_pushy=False):
|
||||||
|
"""Schedule this overlay for a redraw. If part of a
|
||||||
|
piggyback chain, pass it up to be redrawn by topmost parent"""
|
||||||
if (not self.hidden and self.enabled) or be_pushy:
|
if (not self.hidden and self.enabled) or be_pushy:
|
||||||
if self.piggyback_parent:
|
if self.piggyback_parent:
|
||||||
self.piggyback_parent.set_needs_redraw(be_pushy=True)
|
self.piggyback_parent.set_needs_redraw(be_pushy=True)
|
||||||
|
|
||||||
if self.redraw_id == None:
|
if self.redraw_id is None:
|
||||||
self.redraw_id = GLib.idle_add(self.redraw)
|
self.redraw_id = GLib.idle_add(self.redraw)
|
||||||
else:
|
else:
|
||||||
log.debug("Already awaiting paint")
|
log.debug("Already awaiting paint")
|
||||||
|
|
||||||
# If this overlay has data that expires after draw, plan for that here
|
# If this overlay has data that expires after draw, plan for that here
|
||||||
if self.timer_after_draw != None:
|
if self.timer_after_draw is not None:
|
||||||
GLib.timeout_add_seconds(self.timer_after_draw, self.redraw)
|
GLib.timeout_add_seconds(self.timer_after_draw, self.redraw)
|
||||||
|
|
||||||
def redraw(self):
|
def redraw(self):
|
||||||
|
|
@ -364,6 +379,7 @@ class OverlayWindow(Gtk.Window):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_hidden(self, hidden):
|
def set_hidden(self, hidden):
|
||||||
|
"""Set if the overlay should be hidden"""
|
||||||
self.hidden = hidden
|
self.hidden = hidden
|
||||||
self.set_enabled(self.enabled)
|
self.set_enabled(self.enabled)
|
||||||
|
|
||||||
|
|
@ -371,7 +387,7 @@ class OverlayWindow(Gtk.Window):
|
||||||
"""
|
"""
|
||||||
Set the monitor this overlay should display on.
|
Set the monitor this overlay should display on.
|
||||||
"""
|
"""
|
||||||
plug_name = "%s" % (idx)
|
plug_name = f"{idx}"
|
||||||
if self.monitor != plug_name:
|
if self.monitor != plug_name:
|
||||||
self.monitor = plug_name
|
self.monitor = plug_name
|
||||||
if self.is_wayland:
|
if self.is_wayland:
|
||||||
|
|
@ -387,6 +403,8 @@ class OverlayWindow(Gtk.Window):
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def get_monitor_from_plug(self):
|
def get_monitor_from_plug(self):
|
||||||
|
"""Return a GDK Monitor filtered by plug name
|
||||||
|
(HDMI-1, eDP-1, VGA etc)"""
|
||||||
if not self.monitor or self.monitor == "Any":
|
if not self.monitor or self.monitor == "Any":
|
||||||
return None
|
return None
|
||||||
display = Gdk.Display.get_default()
|
display = Gdk.Display.get_default()
|
||||||
|
|
@ -454,26 +472,31 @@ class OverlayWindow(Gtk.Window):
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
def set_task(self, visible):
|
def set_task(self, visible):
|
||||||
|
"""Set visible on taskbar. Not working at last check"""
|
||||||
self.set_skip_pager_hint(not visible)
|
self.set_skip_pager_hint(not visible)
|
||||||
self.set_skip_taskbar_hint(not visible)
|
self.set_skip_taskbar_hint(not visible)
|
||||||
|
|
||||||
def check_composite(self, _a=None, _b=None):
|
def check_composite(self, _a=None, _b=None):
|
||||||
# Called when an X11 session switched compositing on or off
|
"""Callback for compositing started/stopped in X11"""
|
||||||
self.redraw()
|
self.redraw()
|
||||||
|
|
||||||
def screen_changed(self, screen=None):
|
def screen_changed(self, _screen=None):
|
||||||
|
"""Callback to set monitor to display on"""
|
||||||
self.set_monitor(self.monitor)
|
self.set_monitor(self.monitor)
|
||||||
|
|
||||||
def mouseover(self, a=None, b=None):
|
def mouseover(self, _a=None, _b=None):
|
||||||
|
"""Callback when mouseover occurs, hides overlay"""
|
||||||
self.draw_blank = True
|
self.draw_blank = True
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def mouseout(self, a=None, b=None):
|
def mouseout(self, _a=None, _b=None):
|
||||||
|
"""Callback when mouseout occurs, sets a timer to show overlay"""
|
||||||
GLib.timeout_add_seconds(self.timeout_mouse_over, self.mouseout_timed)
|
GLib.timeout_add_seconds(self.timeout_mouse_over, self.mouseout_timed)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def mouseout_timed(self, a=None, b=None):
|
def mouseout_timed(self, _a=None, _b=None):
|
||||||
|
"""Callback a short while after mouseout occured, shows overlay"""
|
||||||
self.draw_blank = False
|
self.draw_blank = False
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,19 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""Settings window holding all settings tab"""
|
"""Settings window holding all settings tab"""
|
||||||
|
# pylint: disable=missing-function-docstring
|
||||||
import gettext
|
import gettext
|
||||||
import gi
|
|
||||||
import logging
|
import logging
|
||||||
import pkg_resources
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
from configparser import ConfigParser
|
||||||
|
import gi
|
||||||
|
import pkg_resources
|
||||||
from .autostart import Autostart, BazziteAutostart
|
from .autostart import Autostart, BazziteAutostart
|
||||||
from .draggable_window import DraggableWindow
|
from .draggable_window import DraggableWindow
|
||||||
from .draggable_window_wayland import DraggableWindowWayland
|
from .draggable_window_wayland import DraggableWindowWayland
|
||||||
|
|
||||||
from configparser import ConfigParser
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
# pylint: disable=wrong-import-position,wrong-import-order
|
# pylint: disable=wrong-import-position,wrong-import-order
|
||||||
from gi.repository import Gtk, Gdk, Gio # nopep8
|
from gi.repository import Gtk, Gdk, Gio # nopep8
|
||||||
|
|
@ -75,6 +76,14 @@ class MainSettingsWindow():
|
||||||
self.current_guild = "0"
|
self.current_guild = "0"
|
||||||
self.current_channel = "0"
|
self.current_channel = "0"
|
||||||
self.hidden_overlay = False
|
self.hidden_overlay = False
|
||||||
|
self.voice_floating_x = 0
|
||||||
|
self.voice_floating_y = 0
|
||||||
|
self.voice_floating_w = 0
|
||||||
|
self.voice_floating_h = 0
|
||||||
|
self.text_floating_x = 0
|
||||||
|
self.text_floating_y = 0
|
||||||
|
self.text_floating_w = 0
|
||||||
|
self.text_floating_h = 0
|
||||||
|
|
||||||
self.menu = self.make_menu()
|
self.menu = self.make_menu()
|
||||||
self.make_sys_tray_icon(self.menu)
|
self.make_sys_tray_icon(self.menu)
|
||||||
|
|
@ -111,16 +120,30 @@ class MainSettingsWindow():
|
||||||
if name.endswith("_all"):
|
if name.endswith("_all"):
|
||||||
widget.set_label(_(widget.get_label()))
|
widget.set_label(_(widget.get_label()))
|
||||||
|
|
||||||
self.widget['overview_main_text'].set_markup("<span size=\"larger\">%s (%s)</span>\n\n%s\n\n%s (<a href=\"https://discord.gg/jRKWMuDy5V\">https://discord.gg/jRKWMuDy5V</a>) %s (<a href=\"https://github.com/trigg/Discover\">https://github.com/trigg/Discover</a>)\n\n\n\n\n\n" % (
|
self.widget['overview_main_text'].set_markup(
|
||||||
|
"%s%s (%s)%s%s\n\n%s %s %s %s%s\n\n\n\n\n\n" % (
|
||||||
|
"<span size=\"larger\">",
|
||||||
_("Welcome to Discover Overlay"),
|
_("Welcome to Discover Overlay"),
|
||||||
pkg_resources.get_distribution('discover_overlay').version,
|
pkg_resources.get_distribution('discover_overlay').version,
|
||||||
_("Discover-Overlay is a GTK3 overlay written in Python3. It can be configured to show who is currently talking on discord or it can be set to display text and images from a preconfigured channel. It is fully customisable and can be configured to display anywhere on the screen. We fully support X11 and wlroots based environments. We felt the need to make this project due to the shortcomings in support on Linux by the official discord client."),
|
"</span>\n\n",
|
||||||
|
_(("Discover-Overlay is a GTK3 overlay written in Python3."
|
||||||
|
" It can be configured to show who is currently talking"
|
||||||
|
" on discord or it can be set to display text and images"
|
||||||
|
" from a preconfigured channel. It is fully customisable"
|
||||||
|
" and can be configured to display anywhere on the screen."
|
||||||
|
" We fully support X11 and wlroots based environments. We "
|
||||||
|
"felt the need to make this project due to the shortcomings"
|
||||||
|
" in support on Linux by the official discord client.")),
|
||||||
_("Please visit our discord"),
|
_("Please visit our discord"),
|
||||||
_(" for support. Or open an issue on our GitHub ")
|
"(<a href=\"https://discord.gg/jRKWMuDy5V\">https://discord.gg/jRKWMuDy5V</a>)",
|
||||||
))
|
_(" for support. Or open an issue on our GitHub "),
|
||||||
|
"(<a href=\"https://github.com/trigg/Discover\">",
|
||||||
|
"https://github.com/trigg/Discover</a>)"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
screen = window.get_screen()
|
screen = window.get_screen()
|
||||||
screen_type = "%s" % (screen)
|
screen_type = f"{screen}"
|
||||||
self.is_wayland = False
|
self.is_wayland = False
|
||||||
if "Wayland" in screen_type:
|
if "Wayland" in screen_type:
|
||||||
self.is_wayland = True
|
self.is_wayland = True
|
||||||
|
|
@ -185,6 +208,7 @@ class MainSettingsWindow():
|
||||||
self.widget['window'].set_default_icon_name(self.icon_name)
|
self.widget['window'].set_default_icon_name(self.icon_name)
|
||||||
|
|
||||||
def set_steamos_window_size(self):
|
def set_steamos_window_size(self):
|
||||||
|
"""Set window based on steamos usage"""
|
||||||
# Huge bunch of assumptions.
|
# Huge bunch of assumptions.
|
||||||
# Gamescope only has one monitor
|
# Gamescope only has one monitor
|
||||||
# Gamescope has no scale factor
|
# Gamescope has no scale factor
|
||||||
|
|
@ -193,23 +217,21 @@ class MainSettingsWindow():
|
||||||
monitor = display.get_monitor(0)
|
monitor = display.get_monitor(0)
|
||||||
if monitor:
|
if monitor:
|
||||||
geometry = monitor.get_geometry()
|
geometry = monitor.get_geometry()
|
||||||
scale_factor = monitor.get_scale_factor()
|
log.info("%d %d", geometry.width, geometry.height)
|
||||||
log.info("%d %d" % (geometry.width, geometry.height))
|
|
||||||
self.window.set_size_request(geometry.width, geometry.height)
|
self.window.set_size_request(geometry.width, geometry.height)
|
||||||
|
|
||||||
def keypress_in_settings(self, window, event):
|
def keypress_in_settings(self, window, event):
|
||||||
|
"""Callback to steal keypresses to assist SteamOS gamepad control"""
|
||||||
if self.spinning_focus:
|
if self.spinning_focus:
|
||||||
match event.keyval:
|
match event.keyval:
|
||||||
case Gdk.KEY_Right:
|
case Gdk.KEY_Right:
|
||||||
step = self.spinning_focus.get_increments().step
|
step = self.spinning_focus.get_increments().step
|
||||||
value = self.spinning_focus.get_value()
|
value = self.spinning_focus.get_value()
|
||||||
self.spinning_focus.set_value(value + step)
|
self.spinning_focus.set_value(value + step)
|
||||||
pass
|
|
||||||
case Gdk.KEY_Left:
|
case Gdk.KEY_Left:
|
||||||
step = self.spinning_focus.get_increments().step
|
step = self.spinning_focus.get_increments().step
|
||||||
value = self.spinning_focus.get_value()
|
value = self.spinning_focus.get_value()
|
||||||
self.spinning_focus.set_value(value - step)
|
self.spinning_focus.set_value(value - step)
|
||||||
pass
|
|
||||||
case Gdk.KEY_Up:
|
case Gdk.KEY_Up:
|
||||||
step = self.spinning_focus.get_increments().step
|
step = self.spinning_focus.get_increments().step
|
||||||
value = self.spinning_focus.get_value()
|
value = self.spinning_focus.get_value()
|
||||||
|
|
@ -230,11 +252,9 @@ class MainSettingsWindow():
|
||||||
case Gdk.KEY_Right:
|
case Gdk.KEY_Right:
|
||||||
value = self.scale_focus.get_value()
|
value = self.scale_focus.get_value()
|
||||||
self.scale_focus.set_value(value + 0.1)
|
self.scale_focus.set_value(value + 0.1)
|
||||||
pass
|
|
||||||
case Gdk.KEY_Left:
|
case Gdk.KEY_Left:
|
||||||
value = self.scale_focus.get_value()
|
value = self.scale_focus.get_value()
|
||||||
self.scale_focus.set_value(value - 0.1)
|
self.scale_focus.set_value(value - 0.1)
|
||||||
pass
|
|
||||||
case Gdk.KEY_Up:
|
case Gdk.KEY_Up:
|
||||||
value = self.scale_focus.get_value()
|
value = self.scale_focus.get_value()
|
||||||
self.scale_focus.set_value(value + 0.1)
|
self.scale_focus.set_value(value + 0.1)
|
||||||
|
|
@ -267,7 +287,7 @@ class MainSettingsWindow():
|
||||||
widget = self.window.get_focus()
|
widget = self.window.get_focus()
|
||||||
if widget:
|
if widget:
|
||||||
# I really want there to be a better way...
|
# I really want there to be a better way...
|
||||||
widget_type = "%s" % (widget)
|
widget_type = f"{widget}"
|
||||||
if 'Gtk.SpinButton' in widget_type:
|
if 'Gtk.SpinButton' in widget_type:
|
||||||
self.spinning_focus = widget
|
self.spinning_focus = widget
|
||||||
|
|
||||||
|
|
@ -285,16 +305,19 @@ class MainSettingsWindow():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def request_channels_from_guild(self, guild_id):
|
def request_channels_from_guild(self, guild_id):
|
||||||
with open(self.rpc_file, 'w') as f:
|
"""Send RPC to overlay to request updated channel list"""
|
||||||
f.write('--rpc --guild-request=%s' % (guild_id))
|
with open(self.rpc_file, 'w', encoding="utf-8") as f:
|
||||||
|
f.write(f"--rpc --guild-request={guild_id}")
|
||||||
|
|
||||||
def populate_guild_menu(self, _a=None, _b=None, _c=None, _d=None):
|
def populate_guild_menu(self, _a=None, _b=None, _c=None, _d=None):
|
||||||
|
"""Read guild data and repopulate widget.
|
||||||
|
Disable signal handling meanwhile to avoid recursive logic"""
|
||||||
g = self.widget['text_server']
|
g = self.widget['text_server']
|
||||||
c = self.widget['text_channel']
|
c = self.widget['text_channel']
|
||||||
g.handler_block(self.server_handler)
|
g.handler_block(self.server_handler)
|
||||||
c.handler_block(self.channel_handler)
|
c.handler_block(self.channel_handler)
|
||||||
try:
|
try:
|
||||||
with open(self.channel_file, "r") as tfile:
|
with open(self.channel_file, "r", encoding="utf-8") as tfile:
|
||||||
data = tfile.readlines()
|
data = tfile.readlines()
|
||||||
if len(data) >= 1:
|
if len(data) >= 1:
|
||||||
data = json.loads(data[0])
|
data = json.loads(data[0])
|
||||||
|
|
@ -322,21 +345,22 @@ class MainSettingsWindow():
|
||||||
c.handler_unblock(self.channel_handler)
|
c.handler_unblock(self.channel_handler)
|
||||||
|
|
||||||
def populate_monitor_menus(self, _a=None, _b=None):
|
def populate_monitor_menus(self, _a=None, _b=None):
|
||||||
v = self.widget['voice_monitor']
|
"""Get Monitor list from GTK and repopulate widget"""
|
||||||
t = self.widget['text_monitor']
|
voice = self.widget['voice_monitor']
|
||||||
m = self.widget['notification_monitor']
|
text = self.widget['text_monitor']
|
||||||
|
notify = self.widget['notification_monitor']
|
||||||
|
|
||||||
v_value = v.get_active()
|
v_value = voice.get_active()
|
||||||
t_value = t.get_active()
|
t_value = text.get_active()
|
||||||
m_value = m.get_active()
|
m_value = notify.get_active()
|
||||||
|
|
||||||
v.remove_all()
|
voice.remove_all()
|
||||||
t.remove_all()
|
text.remove_all()
|
||||||
m.remove_all()
|
notify.remove_all()
|
||||||
|
|
||||||
v.append_text("Any")
|
voice.append_text("Any")
|
||||||
t.append_text("Any")
|
text.append_text("Any")
|
||||||
m.append_text("Any")
|
notify.append_text("Any")
|
||||||
|
|
||||||
display = Gdk.Display.get_default()
|
display = Gdk.Display.get_default()
|
||||||
screen = self.window.get_screen()
|
screen = self.window.get_screen()
|
||||||
|
|
@ -348,41 +372,38 @@ class MainSettingsWindow():
|
||||||
manufacturer = this_mon.get_manufacturer()
|
manufacturer = this_mon.get_manufacturer()
|
||||||
model = this_mon.get_model()
|
model = this_mon.get_model()
|
||||||
connector = screen.get_monitor_plug_name(i)
|
connector = screen.get_monitor_plug_name(i)
|
||||||
monitor_label = "%s %s\n%s" % (
|
monitor_label = f"{manufacturer} {model}\n{connector}"
|
||||||
manufacturer, model, connector)
|
voice.append_text(monitor_label)
|
||||||
v.append_text(monitor_label)
|
text.append_text(monitor_label)
|
||||||
t.append_text(monitor_label)
|
notify.append_text(monitor_label)
|
||||||
m.append_text(monitor_label)
|
|
||||||
|
|
||||||
v.set_active(v_value)
|
voice.set_active(v_value)
|
||||||
t.set_active(t_value)
|
text.set_active(t_value)
|
||||||
m.set_active(m_value)
|
notify.set_active(m_value)
|
||||||
|
|
||||||
def close_window(self, widget=None, event=None):
|
def close_window(self, _widget=None, _event=None):
|
||||||
"""
|
"""Hide the settings window for use at a later date"""
|
||||||
Hide the settings window for use at a later date
|
|
||||||
"""
|
|
||||||
self.window.hide()
|
self.window.hide()
|
||||||
if self.ind == None and self.tray == None:
|
if self.ind is None and self.tray is None:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
if self.ind != None:
|
if self.ind is not None:
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
from gi.repository import AppIndicator3
|
from gi.repository import AppIndicator3
|
||||||
if self.ind.get_status() == AppIndicator3.IndicatorStatus.PASSIVE:
|
if self.ind.get_status() == AppIndicator3.IndicatorStatus.PASSIVE:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def close_app(self, widget=None, event=None):
|
def close_app(self, _widget=None, _event=None):
|
||||||
|
"""Close the app"""
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
def present_settings(self, _a=None):
|
def present_settings(self, _a=None):
|
||||||
"""
|
"""Show the settings window"""
|
||||||
Show the settings window
|
|
||||||
"""
|
|
||||||
self.widget['notebook'].set_current_page(0)
|
self.widget['notebook'].set_current_page(0)
|
||||||
self.window.show()
|
self.window.show()
|
||||||
|
|
||||||
def set_alignment_labels(self, horz):
|
def set_alignment_labels(self, horz):
|
||||||
|
"""Relabel alignment pulldowns"""
|
||||||
m1 = self.widget['voice_align_1'].get_model()
|
m1 = self.widget['voice_align_1'].get_model()
|
||||||
m2 = self.widget['voice_align_2'].get_model()
|
m2 = self.widget['voice_align_2'].get_model()
|
||||||
i = m1.get_iter_first()
|
i = m1.get_iter_first()
|
||||||
|
|
@ -409,6 +430,7 @@ class MainSettingsWindow():
|
||||||
m2.set_value(i2, 0, _("Bottom"))
|
m2.set_value(i2, 0, _("Bottom"))
|
||||||
|
|
||||||
def read_config(self):
|
def read_config(self):
|
||||||
|
"""Read config from disk"""
|
||||||
self.loading_config = True
|
self.loading_config = True
|
||||||
|
|
||||||
# Read config and put into gui
|
# Read config and put into gui
|
||||||
|
|
@ -522,8 +544,8 @@ class MainSettingsWindow():
|
||||||
self.widget['voice_square_avatar'].set_active(config.getboolean(
|
self.widget['voice_square_avatar'].set_active(config.getboolean(
|
||||||
"main", "square_avatar", fallback=True))
|
"main", "square_avatar", fallback=True))
|
||||||
|
|
||||||
self.widget['voice_fancy_avatar_shapes'].set_active(config.getboolean("main",
|
self.widget['voice_fancy_avatar_shapes'].set_active(
|
||||||
"fancy_border", fallback=True))
|
config.getboolean("main", "fancy_border", fallback=True))
|
||||||
|
|
||||||
self.widget['voice_order_avatars_by'].set_active(
|
self.widget['voice_order_avatars_by'].set_active(
|
||||||
config.getint("main", "order", fallback=0))
|
config.getint("main", "order", fallback=0))
|
||||||
|
|
@ -719,6 +741,7 @@ class MainSettingsWindow():
|
||||||
self.loading_config = False
|
self.loading_config = False
|
||||||
|
|
||||||
def make_colour(self, col):
|
def make_colour(self, col):
|
||||||
|
"""Create a Gdk Color from a col tuple"""
|
||||||
col = json.loads(col)
|
col = json.loads(col)
|
||||||
return Gdk.RGBA(col[0], col[1], col[2], col[3])
|
return Gdk.RGBA(col[0], col[1], col[2], col[3])
|
||||||
|
|
||||||
|
|
@ -732,6 +755,7 @@ class MainSettingsWindow():
|
||||||
return guild_ids
|
return guild_ids
|
||||||
|
|
||||||
def get_monitor_index_from_plug(self, monitor):
|
def get_monitor_index_from_plug(self, monitor):
|
||||||
|
"""Get monitor index from plug name"""
|
||||||
if not monitor or monitor == "Any":
|
if not monitor or monitor == "Any":
|
||||||
return 0
|
return 0
|
||||||
display = Gdk.Display.get_default()
|
display = Gdk.Display.get_default()
|
||||||
|
|
@ -746,9 +770,7 @@ class MainSettingsWindow():
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def get_monitor_obj(self, idx):
|
def get_monitor_obj(self, idx):
|
||||||
"""
|
"""Helper function to find the monitor object of the monitor"""
|
||||||
Helper function to find the monitor object of the monitor
|
|
||||||
"""
|
|
||||||
display = Gdk.Display.get_default()
|
display = Gdk.Display.get_default()
|
||||||
return display.get_monitor(idx)
|
return display.get_monitor(idx)
|
||||||
|
|
||||||
|
|
@ -780,17 +802,13 @@ class MainSettingsWindow():
|
||||||
self.tray.set_visible(False)
|
self.tray.set_visible(False)
|
||||||
|
|
||||||
def show_menu(self, obj, button, time):
|
def show_menu(self, obj, button, time):
|
||||||
"""
|
"""Show menu when System Tray icon is clicked"""
|
||||||
Show menu when System Tray icon is clicked
|
|
||||||
"""
|
|
||||||
self.menu.show_all()
|
self.menu.show_all()
|
||||||
self.menu.popup(
|
self.menu.popup(
|
||||||
None, None, Gtk.StatusIcon.position_menu, obj, button, time)
|
None, None, Gtk.StatusIcon.position_menu, obj, button, time)
|
||||||
|
|
||||||
def set_sys_tray_icon_visible(self, visible):
|
def set_sys_tray_icon_visible(self, visible):
|
||||||
"""
|
"""Sets whether the tray icon is visible"""
|
||||||
Sets whether the tray icon is visible
|
|
||||||
"""
|
|
||||||
if self.ind is not None:
|
if self.ind is not None:
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
from gi.repository import AppIndicator3
|
from gi.repository import AppIndicator3
|
||||||
|
|
@ -800,9 +818,7 @@ class MainSettingsWindow():
|
||||||
self.tray.set_visible(visible)
|
self.tray.set_visible(visible)
|
||||||
|
|
||||||
def make_menu(self):
|
def make_menu(self):
|
||||||
"""
|
"""Create System Menu"""
|
||||||
Create System Menu
|
|
||||||
"""
|
|
||||||
menu = Gtk.Menu()
|
menu = Gtk.Menu()
|
||||||
settings_opt = Gtk.MenuItem.new_with_label(_("Settings"))
|
settings_opt = Gtk.MenuItem.new_with_label(_("Settings"))
|
||||||
self.toggle_opt = Gtk.MenuItem.new_with_label(_("Hide overlay"))
|
self.toggle_opt = Gtk.MenuItem.new_with_label(_("Hide overlay"))
|
||||||
|
|
@ -822,11 +838,13 @@ class MainSettingsWindow():
|
||||||
return menu
|
return menu
|
||||||
|
|
||||||
def toggle_overlay(self, _a=None, _b=None):
|
def toggle_overlay(self, _a=None, _b=None):
|
||||||
|
"""Toggle overlay visibility"""
|
||||||
self.hidden_overlay = not self.hidden_overlay
|
self.hidden_overlay = not self.hidden_overlay
|
||||||
self.config_set("general", "hideoverlay", "%s" % (self.hidden_overlay))
|
self.config_set("general", "hideoverlay", f"{self.hidden_overlay}")
|
||||||
self.update_toggle_overlay()
|
self.update_toggle_overlay()
|
||||||
|
|
||||||
def update_toggle_overlay(self, _a=None, _b=None):
|
def update_toggle_overlay(self, _a=None, _b=None):
|
||||||
|
"""Update gui to reflect state of overlay visibility"""
|
||||||
self.widget['core_hide_overlay'].handler_block(
|
self.widget['core_hide_overlay'].handler_block(
|
||||||
self.hidden_overlay_handler)
|
self.hidden_overlay_handler)
|
||||||
|
|
||||||
|
|
@ -840,14 +858,17 @@ class MainSettingsWindow():
|
||||||
self.toggle_opt.set_label(_("Hide overlay"))
|
self.toggle_opt.set_label(_("Hide overlay"))
|
||||||
|
|
||||||
def close_overlay(self, _a=None, _b=None):
|
def close_overlay(self, _a=None, _b=None):
|
||||||
with open(self.rpc_file, 'w') as f:
|
"""Send RPC to tell the overlay to close"""
|
||||||
|
with open(self.rpc_file, 'w', encoding="utf-8") as f:
|
||||||
f.write('--rpc --close')
|
f.write('--rpc --close')
|
||||||
|
|
||||||
def overview_close(self, button):
|
def overview_close(self, _button):
|
||||||
|
"""Gui callback to close overlay. Remove and use close_overlay?"""
|
||||||
log.info("Quit pressed")
|
log.info("Quit pressed")
|
||||||
self.close_overlay()
|
self.close_overlay()
|
||||||
|
|
||||||
def voice_place_window(self, button):
|
def voice_place_window(self, button):
|
||||||
|
"""Toggle the voice placement"""
|
||||||
if self.voice_placement_window:
|
if self.voice_placement_window:
|
||||||
(pos_x, pos_y, width, height) = self.voice_placement_window.get_coords()
|
(pos_x, pos_y, width, height) = self.voice_placement_window.get_coords()
|
||||||
self.voice_floating_x = pos_x
|
self.voice_floating_x = pos_x
|
||||||
|
|
@ -857,18 +878,14 @@ class MainSettingsWindow():
|
||||||
|
|
||||||
config = ConfigParser(interpolation=None)
|
config = ConfigParser(interpolation=None)
|
||||||
config.read(self.config_file)
|
config.read(self.config_file)
|
||||||
if not "main" in config.sections():
|
if "main" not in config.sections():
|
||||||
config.add_section("main")
|
config.add_section("main")
|
||||||
config.set("main", "floating_x", "%f" %
|
config.set("main", "floating_x", f"{self.voice_floating_x:f}")
|
||||||
(self.voice_floating_x))
|
config.set("main", "floating_y", f"{self.voice_floating_y:f}")
|
||||||
config.set("main", "floating_y", "%f" %
|
config.set("main", "floating_w", f"{self.voice_floating_w:f}")
|
||||||
(self.voice_floating_y))
|
config.set("main", "floating_h", f"{self.voice_floating_h:f}")
|
||||||
config.set("main", "floating_w", "%f" %
|
|
||||||
(self.voice_floating_w))
|
|
||||||
config.set("main", "floating_h", "%f" %
|
|
||||||
(self.voice_floating_h))
|
|
||||||
|
|
||||||
with open(self.config_file, 'w') as file:
|
with open(self.config_file, 'w', encoding="utf-8") as file:
|
||||||
config.write(file)
|
config.write(file)
|
||||||
if button:
|
if button:
|
||||||
button.set_label(_("Place Window"))
|
button.set_label(_("Place Window"))
|
||||||
|
|
@ -890,11 +907,13 @@ class MainSettingsWindow():
|
||||||
self.voice_placement_window = DraggableWindow(
|
self.voice_placement_window = DraggableWindow(
|
||||||
pos_x=self.voice_floating_x, pos_y=self.voice_floating_y,
|
pos_x=self.voice_floating_x, pos_y=self.voice_floating_y,
|
||||||
width=self.voice_floating_w, height=self.voice_floating_h,
|
width=self.voice_floating_w, height=self.voice_floating_h,
|
||||||
message=_("Place & resize this window then press Save!"), settings=self, monitor=self.widget['voice_monitor'].get_active()-1)
|
message=_("Place & resize this window then press Save!"),
|
||||||
|
settings=self, monitor=self.widget['voice_monitor'].get_active()-1)
|
||||||
if button:
|
if button:
|
||||||
button.set_label(_("Save this position"))
|
button.set_label(_("Save this position"))
|
||||||
|
|
||||||
def text_place_window(self, button):
|
def text_place_window(self, button):
|
||||||
|
"""Toggle the text placement"""
|
||||||
if self.text_placement_window:
|
if self.text_placement_window:
|
||||||
(pos_x, pos_y, width, height) = self.text_placement_window.get_coords()
|
(pos_x, pos_y, width, height) = self.text_placement_window.get_coords()
|
||||||
self.text_floating_x = pos_x
|
self.text_floating_x = pos_x
|
||||||
|
|
@ -904,18 +923,14 @@ class MainSettingsWindow():
|
||||||
|
|
||||||
config = ConfigParser(interpolation=None)
|
config = ConfigParser(interpolation=None)
|
||||||
config.read(self.config_file)
|
config.read(self.config_file)
|
||||||
if not "text" in config.sections():
|
if "text" not in config.sections():
|
||||||
config.add_section("text")
|
config.add_section("text")
|
||||||
config.set("text", "floating_x", "%f" %
|
config.set("text", "floating_x", f"{self.text_floating_x:f}")
|
||||||
(self.text_floating_x))
|
config.set("text", "floating_y", f"{self.text_floating_y:f}")
|
||||||
config.set("text", "floating_y", "%f" %
|
config.set("text", "floating_w", f"{self.text_floating_w:f}")
|
||||||
(self.text_floating_y))
|
config.set("text", "floating_h", f"{self.text_floating_h:f}")
|
||||||
config.set("text", "floating_w", "%f" %
|
|
||||||
(self.text_floating_w))
|
|
||||||
config.set("text", "floating_h", "%f" %
|
|
||||||
(self.text_floating_h))
|
|
||||||
|
|
||||||
with open(self.config_file, 'w') as file:
|
with open(self.config_file, 'w', encoding="utf-8") as file:
|
||||||
config.write(file)
|
config.write(file)
|
||||||
if button:
|
if button:
|
||||||
button.set_label(_("Place Window"))
|
button.set_label(_("Place Window"))
|
||||||
|
|
@ -937,21 +952,25 @@ class MainSettingsWindow():
|
||||||
self.text_placement_window = DraggableWindow(
|
self.text_placement_window = DraggableWindow(
|
||||||
pos_x=self.text_floating_x, pos_y=self.text_floating_y,
|
pos_x=self.text_floating_x, pos_y=self.text_floating_y,
|
||||||
width=self.text_floating_w, height=self.text_floating_h,
|
width=self.text_floating_w, height=self.text_floating_h,
|
||||||
message=_("Place & resize this window then press Save!"), settings=self, monitor=self.widget['text_monitor'].get_active()-1)
|
message=_("Place & resize this window then press Save!"),
|
||||||
|
settings=self, monitor=self.widget['text_monitor'].get_active()-1)
|
||||||
if button:
|
if button:
|
||||||
button.set_label(_("Save this position"))
|
button.set_label(_("Save this position"))
|
||||||
|
|
||||||
def change_placement(self, placement_window):
|
def change_placement(self, placement_window):
|
||||||
|
"""Finish window placement"""
|
||||||
if placement_window == self.text_placement_window:
|
if placement_window == self.text_placement_window:
|
||||||
self.text_place_window(None)
|
self.text_place_window(None)
|
||||||
elif placement_window == self.voice_placement_window:
|
elif placement_window == self.voice_placement_window:
|
||||||
self.voice_place_window(None)
|
self.voice_place_window(None)
|
||||||
|
|
||||||
def text_server_refresh(self, button):
|
def text_server_refresh(self, _button):
|
||||||
with open(self.rpc_file, 'w') as f:
|
"""Send RPC to overlay to request a list of text channels"""
|
||||||
|
with open(self.rpc_file, 'w', encoding="utf-8") as f:
|
||||||
f.write('--rpc --refresh-guilds')
|
f.write('--rpc --refresh-guilds')
|
||||||
|
|
||||||
def config_set(self, context, key, value):
|
def config_set(self, context, key, value):
|
||||||
|
"""Write one key to config and save to disk"""
|
||||||
if self.loading_config:
|
if self.loading_config:
|
||||||
return
|
return
|
||||||
config = ConfigParser(interpolation=None)
|
config = ConfigParser(interpolation=None)
|
||||||
|
|
@ -959,10 +978,11 @@ class MainSettingsWindow():
|
||||||
if not context in config.sections():
|
if not context in config.sections():
|
||||||
config.add_section(context)
|
config.add_section(context)
|
||||||
config.set(context, key, value)
|
config.set(context, key, value)
|
||||||
with open(self.config_file, 'w') as file:
|
with open(self.config_file, 'w', encoding="utf-8") as file:
|
||||||
config.write(file)
|
config.write(file)
|
||||||
|
|
||||||
def config_remove_section(self, context):
|
def config_remove_section(self, context):
|
||||||
|
"""Remove a section from config and save to disk"""
|
||||||
if self.loading_config:
|
if self.loading_config:
|
||||||
return
|
return
|
||||||
config = ConfigParser(interpolation=None)
|
config = ConfigParser(interpolation=None)
|
||||||
|
|
@ -970,12 +990,12 @@ class MainSettingsWindow():
|
||||||
if context in config.sections():
|
if context in config.sections():
|
||||||
config.remove_section(context)
|
config.remove_section(context)
|
||||||
else:
|
else:
|
||||||
log.error("Unable to remove section %s" % (context))
|
log.error("Unable to remove section %s", context)
|
||||||
with open(self.config_file, 'w') as file:
|
with open(self.config_file, 'w', encoding="utf-8") as file:
|
||||||
config.write(file)
|
config.write(file)
|
||||||
|
|
||||||
def voice_anchor_float_changed(self, button):
|
def voice_anchor_float_changed(self, button):
|
||||||
self.config_set("main", "floating", "%s" % (button.get_active() == 0))
|
self.config_set("main", "floating", f"{(button.get_active() == 0)}")
|
||||||
self.update_floating_anchor()
|
self.update_floating_anchor()
|
||||||
|
|
||||||
def update_floating_anchor(self):
|
def update_floating_anchor(self):
|
||||||
|
|
@ -1003,10 +1023,10 @@ class MainSettingsWindow():
|
||||||
self.config_set("main", "monitor", plug)
|
self.config_set("main", "monitor", plug)
|
||||||
|
|
||||||
def voice_align_1_changed(self, button):
|
def voice_align_1_changed(self, button):
|
||||||
self.config_set("main", "rightalign", "%s" % (button.get_active()))
|
self.config_set("main", "rightalign", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_align_2_changed(self, button):
|
def voice_align_2_changed(self, button):
|
||||||
self.config_set("main", "topalign", "%s" % (button.get_active()))
|
self.config_set("main", "topalign", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_font_changed(self, button):
|
def voice_font_changed(self, button):
|
||||||
self.config_set("main", "font", button.get_font())
|
self.config_set("main", "font", button.get_font())
|
||||||
|
|
@ -1015,41 +1035,39 @@ class MainSettingsWindow():
|
||||||
self.config_set("main", "title_font", button.get_font())
|
self.config_set("main", "title_font", button.get_font())
|
||||||
|
|
||||||
def voice_icon_spacing_changed(self, button):
|
def voice_icon_spacing_changed(self, button):
|
||||||
self.config_set("main", "icon_spacing", "%s" %
|
self.config_set("main", "icon_spacing", f"{int(button.get_value())}")
|
||||||
(int(button.get_value())))
|
|
||||||
|
|
||||||
def voice_text_padding_changed(self, button):
|
def voice_text_padding_changed(self, button):
|
||||||
self.config_set("main", "text_padding", "%s" %
|
self.config_set("main", "text_padding", f"{int(button.get_value())}")
|
||||||
(int(button.get_value())))
|
|
||||||
|
|
||||||
def voice_text_vertical_offset_changed(self, button):
|
def voice_text_vertical_offset_changed(self, button):
|
||||||
self.config_set("main", "text_baseline_adj", "%s" %
|
self.config_set("main", "text_baseline_adj",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def voice_vertical_padding_changed(self, button):
|
def voice_vertical_padding_changed(self, button):
|
||||||
self.config_set("main", "vert_edge_padding", "%s" %
|
self.config_set("main", "vert_edge_padding",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def voice_horizontal_padding_changed(self, button):
|
def voice_horizontal_padding_changed(self, button):
|
||||||
self.config_set("main", "horz_edge_padding", "%s" %
|
self.config_set("main", "horz_edge_padding",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def voice_display_horizontally_changed(self, button):
|
def voice_display_horizontally_changed(self, button):
|
||||||
self.config_set("main", "horizontal", "%s" % (button.get_active()))
|
self.config_set("main", "horizontal", f"{button.get_active()}")
|
||||||
self.set_alignment_labels(button.get_active())
|
self.set_alignment_labels(button.get_active())
|
||||||
|
|
||||||
def voice_highlight_self_changed(self, button):
|
def voice_highlight_self_changed(self, button):
|
||||||
self.config_set("main", "highlight_self", "%s" % (button.get_active()))
|
self.config_set("main", "highlight_self", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_display_speakers_only(self, button):
|
def voice_display_speakers_only(self, button):
|
||||||
self.config_set("main", "only_speaking", "%s" % (button.get_active()))
|
self.config_set("main", "only_speaking", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_display_speakers_grace_period(self, button):
|
def voice_display_speakers_grace_period(self, button):
|
||||||
self.config_set("main", "only_speaking_grace", "%s" %
|
self.config_set("main", "only_speaking_grace",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def voice_toggle_test_content(self, button):
|
def voice_toggle_test_content(self, button):
|
||||||
self.config_set("main", "show_dummy", "%s" % (button.get_active()))
|
self.config_set("main", "show_dummy", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_talking_foreground_changed(self, button):
|
def voice_talking_foreground_changed(self, button):
|
||||||
colour = button.get_rgba()
|
colour = button.get_rgba()
|
||||||
|
|
@ -1097,54 +1115,48 @@ class MainSettingsWindow():
|
||||||
self.config_set("main", "avatar_bg_col", json.dumps(colour))
|
self.config_set("main", "avatar_bg_col", json.dumps(colour))
|
||||||
|
|
||||||
def voice_avatar_opacity_changed(self, button):
|
def voice_avatar_opacity_changed(self, button):
|
||||||
self.config_set("main", "icon_transparency", "%.2f" %
|
self.config_set("main", "icon_transparency",
|
||||||
(button.get_value()))
|
f"{button.get_value():.2f}")
|
||||||
|
|
||||||
def voice_avatar_size_changed(self, button):
|
def voice_avatar_size_changed(self, button):
|
||||||
self.config_set("main", "avatar_size", "%s" %
|
self.config_set("main", "avatar_size", f"{int(button.get_value())}")
|
||||||
(int(button.get_value())))
|
|
||||||
|
|
||||||
def voice_nick_length_changed(self, button):
|
def voice_nick_length_changed(self, button):
|
||||||
self.config_set("main", "nick_length", "%s" %
|
self.config_set("main", "nick_length", f"{int(button.get_value())}")
|
||||||
(int(button.get_value())))
|
|
||||||
|
|
||||||
def voice_display_icon_only_changed(self, button):
|
def voice_display_icon_only_changed(self, button):
|
||||||
self.config_set("main", "icon_only", "%s" % (not button.get_active()))
|
self.config_set("main", "icon_only", f"{(not button.get_active())}")
|
||||||
self.voice_show_name_hide_others(button.get_active())
|
self.voice_show_name_hide_others(button.get_active())
|
||||||
|
|
||||||
def voice_square_avatar_changed(self, button):
|
def voice_square_avatar_changed(self, button):
|
||||||
self.config_set("main", "square_avatar", "%s" % (button.get_active()))
|
self.config_set("main", "square_avatar", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_fancy_avatar_shapes_changed(self, button):
|
def voice_fancy_avatar_shapes_changed(self, button):
|
||||||
self.config_set("main", "fancy_border", "%s" % (button.get_active()))
|
self.config_set("main", "fancy_border", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_order_avatars_by_changed(self, button):
|
def voice_order_avatars_by_changed(self, button):
|
||||||
self.config_set("main", "order", "%s" % (button.get_active()))
|
self.config_set("main", "order", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_border_width_changed(self, button):
|
def voice_border_width_changed(self, button):
|
||||||
self.config_set("main", "border_width", "%s" %
|
self.config_set("main", "border_width", f"{int(button.get_value())}")
|
||||||
(int(button.get_value())))
|
|
||||||
|
|
||||||
def voice_overflow_style_changed(self, button):
|
def voice_overflow_style_changed(self, button):
|
||||||
self.config_set("main", "overflow", "%s" % (int(button.get_active())))
|
self.config_set("main", "overflow", f"{int(button.get_active())}")
|
||||||
|
|
||||||
def voice_show_title_changed(self, button):
|
def voice_show_title_changed(self, button):
|
||||||
self.config_set("main", "show_title", "%s" % (button.get_active()))
|
self.config_set("main", "show_title", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_show_connection_status_changed(self, button):
|
def voice_show_connection_status_changed(self, button):
|
||||||
self.config_set("main", "show_connection", "%s" %
|
self.config_set("main", "show_connection", f"{button.get_active()}")
|
||||||
(button.get_active()))
|
|
||||||
|
|
||||||
def voice_show_disconnected_changed(self, button):
|
def voice_show_disconnected_changed(self, button):
|
||||||
self.config_set("main", "show_disconnected", "%s" %
|
self.config_set("main", "show_disconnected", f"{button.get_active()}")
|
||||||
(button.get_active()))
|
|
||||||
|
|
||||||
def voice_dummy_count_changed(self, button):
|
def voice_dummy_count_changed(self, button):
|
||||||
self.config_set("main", "dummy_count", "%s" %
|
self.config_set("main", "dummy_count", f"{int(button.get_value())}")
|
||||||
(int(button.get_value())))
|
|
||||||
|
|
||||||
def voice_show_avatar_changed(self, button):
|
def voice_show_avatar_changed(self, button):
|
||||||
self.config_set("main", "show_avatar", "%s" % (button.get_active()))
|
self.config_set("main", "show_avatar", f"{button.get_active()}")
|
||||||
self.voice_show_avatar_hide_others(button.get_active())
|
self.voice_show_avatar_hide_others(button.get_active())
|
||||||
|
|
||||||
def voice_show_name_hide_others(self, val):
|
def voice_show_name_hide_others(self, val):
|
||||||
|
|
@ -1176,13 +1188,13 @@ class MainSettingsWindow():
|
||||||
self.widget['voice_avatar_opacity'].set_sensitive(False)
|
self.widget['voice_avatar_opacity'].set_sensitive(False)
|
||||||
|
|
||||||
def text_enable_changed(self, button):
|
def text_enable_changed(self, button):
|
||||||
self.config_set("text", "enabled", "%s" % (button.get_active()))
|
self.config_set("text", "enabled", f"{button.get_active()}")
|
||||||
|
|
||||||
def text_popup_style_changed(self, button):
|
def text_popup_style_changed(self, button):
|
||||||
self.config_set("text", "popup_style", "%s" % (button.get_active()))
|
self.config_set("text", "popup_style", f"{button.get_active()}")
|
||||||
|
|
||||||
def text_popup_time_changed(self, button):
|
def text_popup_time_changed(self, button):
|
||||||
self.config_set("text", "text_time", "%s" % (int(button.get_value())))
|
self.config_set("text", "text_time", f"{int(button.get_value())}")
|
||||||
|
|
||||||
def text_server_changed(self, button):
|
def text_server_changed(self, button):
|
||||||
if button.get_active() < 0:
|
if button.get_active() < 0:
|
||||||
|
|
@ -1225,25 +1237,24 @@ class MainSettingsWindow():
|
||||||
self.config_set("text", "monitor", plug)
|
self.config_set("text", "monitor", plug)
|
||||||
|
|
||||||
def text_show_attachments_changed(self, button):
|
def text_show_attachments_changed(self, button):
|
||||||
self.config_set("text", "show_attach", "%s" % (button.get_active()))
|
self.config_set("text", "show_attach", f"{button.get_active()}")
|
||||||
|
|
||||||
def text_line_limit_changed(self, button):
|
def text_line_limit_changed(self, button):
|
||||||
self.config_set("text", "line_limit", "%s" % (int(button.get_value())))
|
self.config_set("text", "line_limit", f"{int(button.get_value())}")
|
||||||
|
|
||||||
def notification_enable_changed(self, button):
|
def notification_enable_changed(self, button):
|
||||||
self.config_set("notification", "enabled", "%s" %
|
self.config_set("notification", "enabled", f"{button.get_active()}")
|
||||||
(button.get_active()))
|
|
||||||
|
|
||||||
def notification_reverse_order_changed(self, button):
|
def notification_reverse_order_changed(self, button):
|
||||||
self.config_set("notification", "rev", "%s" % (button.get_active()))
|
self.config_set("notification", "rev", f"{button.get_active()}")
|
||||||
|
|
||||||
def notification_popup_timer_changed(self, button):
|
def notification_popup_timer_changed(self, button):
|
||||||
self.config_set("notification", "text_time", "%s" %
|
self.config_set("notification", "text_time",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def notification_limit_popup_width_changed(self, button):
|
def notification_limit_popup_width_changed(self, button):
|
||||||
self.config_set("notification", "limit_width", "%s" %
|
self.config_set("notification", "limit_width",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def notification_font_changed(self, button):
|
def notification_font_changed(self, button):
|
||||||
self.config_set("notification", "font", button.get_font())
|
self.config_set("notification", "font", button.get_font())
|
||||||
|
|
@ -1267,40 +1278,36 @@ class MainSettingsWindow():
|
||||||
self.config_set("notification", "monitor", plug)
|
self.config_set("notification", "monitor", plug)
|
||||||
|
|
||||||
def notification_align_1_changed(self, button):
|
def notification_align_1_changed(self, button):
|
||||||
self.config_set("notification", "rightalign", "%s" %
|
self.config_set("notification", "rightalign", f"{button.get_active()}")
|
||||||
(button.get_active()))
|
|
||||||
|
|
||||||
def notification_align_2_changed(self, button):
|
def notification_align_2_changed(self, button):
|
||||||
self.config_set("notification", "topalign", "%s" %
|
self.config_set("notification", "topalign", f"{button.get_active()}")
|
||||||
(button.get_active()))
|
|
||||||
|
|
||||||
def notification_show_icon(self, button):
|
def notification_show_icon(self, button):
|
||||||
self.config_set("notification", "show_icon", "%s" %
|
self.config_set("notification", "show_icon", f"{button.get_active()}")
|
||||||
(button.get_active()))
|
|
||||||
|
|
||||||
def notification_icon_position_changed(self, button):
|
def notification_icon_position_changed(self, button):
|
||||||
self.config_set("notification", "icon_left", "%s" %
|
self.config_set("notification", "icon_left", f"{
|
||||||
(int(button.get_active() != 1)))
|
int(button.get_active() != 1)}")
|
||||||
|
|
||||||
def notification_icon_padding_changed(self, button):
|
def notification_icon_padding_changed(self, button):
|
||||||
self.config_set("notification", "icon_padding", "%s" %
|
self.config_set("notification", "icon_padding",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def notification_icon_size_changed(self, button):
|
def notification_icon_size_changed(self, button):
|
||||||
self.config_set("notification", "icon_size", "%s" %
|
self.config_set("notification", "icon_size",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def notification_padding_between_changed(self, button):
|
def notification_padding_between_changed(self, button):
|
||||||
self.config_set("notification", "padding", "%s" %
|
self.config_set("notification", "padding",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def notification_border_radius_changed(self, button):
|
def notification_border_radius_changed(self, button):
|
||||||
self.config_set("notification", "border_radius", "%s" %
|
self.config_set("notification", "border_radius",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def notification_show_test_content_changed(self, button):
|
def notification_show_test_content_changed(self, button):
|
||||||
self.config_set("notification", "show_dummy", "%s" %
|
self.config_set("notification", "show_dummy", f"{button.get_active()}")
|
||||||
(button.get_active()))
|
|
||||||
|
|
||||||
def core_run_on_startup_changed(self, button):
|
def core_run_on_startup_changed(self, button):
|
||||||
self.autostart_helper.set_autostart(button.get_active())
|
self.autostart_helper.set_autostart(button.get_active())
|
||||||
|
|
@ -1309,65 +1316,60 @@ class MainSettingsWindow():
|
||||||
self.autostart_helper_conf.set_autostart(button.get_active())
|
self.autostart_helper_conf.set_autostart(button.get_active())
|
||||||
|
|
||||||
def core_force_xshape_changed(self, button):
|
def core_force_xshape_changed(self, button):
|
||||||
self.config_set("general", "xshape", "%s" % (button.get_active()))
|
self.config_set("general", "xshape", f"{button.get_active()}")
|
||||||
|
|
||||||
def core_show_tray_icon_changed(self, button):
|
def core_show_tray_icon_changed(self, button):
|
||||||
self.set_sys_tray_icon_visible(button.get_active())
|
self.set_sys_tray_icon_visible(button.get_active())
|
||||||
self.config_set("general", "showsystray", "%s" % (button.get_active()))
|
self.config_set("general", "showsystray", f"{button.get_active()}")
|
||||||
self.widget['core_settings_min'].set_sensitive(button.get_active())
|
self.widget['core_settings_min'].set_sensitive(button.get_active())
|
||||||
|
|
||||||
def core_hide_overlay_changed(self, button):
|
def core_hide_overlay_changed(self, _button):
|
||||||
self.toggle_overlay()
|
self.toggle_overlay()
|
||||||
|
|
||||||
def core_settings_min_changed(self, button):
|
def core_settings_min_changed(self, button):
|
||||||
self.config_set("general", "start_min", "%s" % (button.get_active()))
|
self.config_set("general", "start_min", f"{button.get_active()}")
|
||||||
|
|
||||||
def core_reset_all(self, button):
|
def core_reset_all(self, _button):
|
||||||
self.config_remove_section("general")
|
self.config_remove_section("general")
|
||||||
self.read_config()
|
self.read_config()
|
||||||
|
|
||||||
def voice_reset_all(self, button):
|
def voice_reset_all(self, _button):
|
||||||
self.config_remove_section("main")
|
self.config_remove_section("main")
|
||||||
self.read_config()
|
self.read_config()
|
||||||
|
|
||||||
def text_reset_all(self, button):
|
def text_reset_all(self, _button):
|
||||||
self.config_remove_section("text")
|
self.config_remove_section("text")
|
||||||
self.read_config()
|
self.read_config()
|
||||||
|
|
||||||
def notification_reset_all(self, button):
|
def notification_reset_all(self, _button):
|
||||||
self.config_remove_section("notification")
|
self.config_remove_section("notification")
|
||||||
self.read_config()
|
self.read_config()
|
||||||
|
|
||||||
def voice_hide_mouseover_changed(self, button):
|
def voice_hide_mouseover_changed(self, button):
|
||||||
self.config_set("main", "autohide", "%s" % (button.get_active()))
|
self.config_set("main", "autohide", f"{button.get_active()}")
|
||||||
|
|
||||||
def text_hide_mouseover_changed(self, button):
|
def text_hide_mouseover_changed(self, button):
|
||||||
self.config_set("text", "autohide", "%s" % (button.get_active()))
|
self.config_set("text", "autohide", f"{button.get_active()}")
|
||||||
|
|
||||||
def voice_mouseover_timeout_changed(self, button):
|
def voice_mouseover_timeout_changed(self, button):
|
||||||
self.config_set("main", "autohide_timer", "%s" %
|
self.config_set("main", "autohide_timer", f"{int(button.get_value())}")
|
||||||
(int(button.get_value())))
|
|
||||||
|
|
||||||
def text_mouseover_timeout_changed(self, button):
|
def text_mouseover_timeout_changed(self, button):
|
||||||
self.config_set("text", "autohide_timer", "%s" %
|
self.config_set("text", "autohide_timer", f"{int(button.get_value())}")
|
||||||
(int(button.get_value())))
|
|
||||||
|
|
||||||
def inactive_fade_changed(self, button):
|
def inactive_fade_changed(self, button):
|
||||||
self.config_set("main", "fade_out_inactive", "%s" %
|
self.config_set("main", "fade_out_inactive", f"{button.get_active()}")
|
||||||
(button.get_active()))
|
|
||||||
|
|
||||||
def inactive_fade_opacity_changed(self, button):
|
def inactive_fade_opacity_changed(self, button):
|
||||||
self.config_set("main", "fade_out_limit", "%.2f" %
|
self.config_set("main", "fade_out_limit",
|
||||||
(button.get_value()))
|
f"{button.get_value():.2f}")
|
||||||
|
|
||||||
def inactive_time_changed(self, button):
|
def inactive_time_changed(self, button):
|
||||||
self.config_set("main", "inactive_time", "%s" %
|
self.config_set("main", "inactive_time", f"{int(button.get_value())}")
|
||||||
(int(button.get_value())))
|
|
||||||
|
|
||||||
def inactive_fade_time_changed(self, button):
|
def inactive_fade_time_changed(self, button):
|
||||||
self.config_set("main", "inactive_fade_time", "%s" %
|
self.config_set("main", "inactive_fade_time",
|
||||||
(int(button.get_value())))
|
f"{int(button.get_value())}")
|
||||||
|
|
||||||
def core_audio_assist_changed(self, button):
|
def core_audio_assist_changed(self, button):
|
||||||
self.config_set("general", "audio_assist", "%s" %
|
self.config_set("general", "audio_assist", f"{button.get_active()}")
|
||||||
(button.get_active()))
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ from .overlay import OverlayWindow
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
gi.require_version('PangoCairo', '1.0')
|
gi.require_version('PangoCairo', '1.0')
|
||||||
# pylint: disable=wrong-import-position,wrong-import-order
|
# pylint: disable=wrong-import-position,wrong-import-order
|
||||||
from gi.repository import Pango, PangoCairo, GLib # nopep8
|
from gi.repository import Pango, PangoCairo # nopep8
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -56,10 +56,12 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
self.redraw()
|
self.redraw()
|
||||||
|
|
||||||
def set_blank(self):
|
def set_blank(self):
|
||||||
|
""" Set contents blank and redraw """
|
||||||
self.content = []
|
self.content = []
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def tick(self):
|
def tick(self):
|
||||||
|
""" Check for old images """
|
||||||
if len(self.attachment) > self.line_limit:
|
if len(self.attachment) > self.line_limit:
|
||||||
# We've probably got old images!
|
# We've probably got old images!
|
||||||
oldlist = self.attachment
|
oldlist = self.attachment
|
||||||
|
|
@ -72,57 +74,43 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
self.attachment[url] = oldlist[url]
|
self.attachment[url] = oldlist[url]
|
||||||
|
|
||||||
def set_text_time(self, timer):
|
def set_text_time(self, timer):
|
||||||
"""
|
"""Config option: Time before messages disappear from overlay"""
|
||||||
Set the duration that a message will be visible for.
|
|
||||||
"""
|
|
||||||
if self.text_time != timer or self.timer_after_draw != timer:
|
if self.text_time != timer or self.timer_after_draw != timer:
|
||||||
self.text_time = timer
|
self.text_time = timer
|
||||||
self.timer_after_draw = timer
|
self.timer_after_draw = timer
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_text_list(self, tlist, altered):
|
def set_text_list(self, tlist, altered):
|
||||||
"""
|
"""Change contents of overlay"""
|
||||||
Update the list of text messages to show
|
|
||||||
"""
|
|
||||||
self.content = tlist[-self.line_limit:]
|
self.content = tlist[-self.line_limit:]
|
||||||
if altered:
|
if altered:
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_fg(self, fg_col):
|
def set_fg(self, fg_col):
|
||||||
"""
|
"""Config option: Sets the text colour"""
|
||||||
Set default text colour
|
|
||||||
"""
|
|
||||||
if self.fg_col != fg_col:
|
if self.fg_col != fg_col:
|
||||||
self.fg_col = fg_col
|
self.fg_col = fg_col
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_bg(self, bg_col):
|
def set_bg(self, bg_col):
|
||||||
"""
|
"""Config option: Set the background colour"""
|
||||||
Set background colour
|
|
||||||
"""
|
|
||||||
if self.bg_col != bg_col:
|
if self.bg_col != bg_col:
|
||||||
self.bg_col = bg_col
|
self.bg_col = bg_col
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_show_attach(self, attachment):
|
def set_show_attach(self, attachment):
|
||||||
"""
|
"""Config option: Show image attachments"""
|
||||||
Set if attachments should be shown inline
|
|
||||||
"""
|
|
||||||
if self.attachment != attachment:
|
if self.attachment != attachment:
|
||||||
self.show_attach = attachment
|
self.show_attach = attachment
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_popup_style(self, boolean):
|
def set_popup_style(self, boolean):
|
||||||
"""
|
"""Config option: Messages should disappear after being shown for some time"""
|
||||||
Set if message disappear after a certain duration
|
|
||||||
"""
|
|
||||||
if self.popup_style != boolean:
|
if self.popup_style != boolean:
|
||||||
self.popup_style = boolean
|
self.popup_style = boolean
|
||||||
|
|
||||||
def set_font(self, font):
|
def set_font(self, font):
|
||||||
"""
|
"""Config option: Set font used for rendering"""
|
||||||
Set font used to render text
|
|
||||||
"""
|
|
||||||
if self.text_font != font:
|
if self.text_font != font:
|
||||||
self.text_font = font
|
self.text_font = font
|
||||||
|
|
||||||
|
|
@ -133,28 +121,24 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_line_limit(self, limit):
|
def set_line_limit(self, limit):
|
||||||
"""
|
"""Config option: Limit number of lines rendered"""
|
||||||
Change maximum number of lines in overlay
|
|
||||||
"""
|
|
||||||
if self.line_limit != limit:
|
if self.line_limit != limit:
|
||||||
self.line_limit = limit
|
self.line_limit = limit
|
||||||
|
|
||||||
def make_line(self, message):
|
def make_line(self, message):
|
||||||
"""
|
"""Decode a recursive JSON object into pango markup."""
|
||||||
Decode a recursive JSON object into pango markup.
|
|
||||||
"""
|
|
||||||
ret = ""
|
ret = ""
|
||||||
if isinstance(message, list):
|
if isinstance(message, list):
|
||||||
for inner_message in message:
|
for inner_message in message:
|
||||||
ret = "%s%s" % (ret, self.make_line(inner_message))
|
ret = f"{ret}{self.make_line(inner_message)}"
|
||||||
elif isinstance(message, str):
|
elif isinstance(message, str):
|
||||||
ret = self.sanitize_string(message)
|
ret = self.sanitize_string(message)
|
||||||
elif message['type'] == 'strong':
|
elif message['type'] == 'strong':
|
||||||
ret = "<b>%s</b>" % (self.make_line(message['content']))
|
ret = f"<b>{self.make_line(message['content'])}</b>"
|
||||||
elif message['type'] == 'text':
|
elif message['type'] == 'text':
|
||||||
ret = self.sanitize_string(message['content'])
|
ret = self.sanitize_string(message['content'])
|
||||||
elif message['type'] == 'link':
|
elif message['type'] == 'link':
|
||||||
ret = "<u>%s</u>" % (self.make_line(message['content']))
|
ret = f"<u>{self.make_line(message['content'])}</u>"
|
||||||
elif message['type'] == 'emoji':
|
elif message['type'] == 'emoji':
|
||||||
if 'surrogate' in message:
|
if 'surrogate' in message:
|
||||||
# ['src'] is SVG URL
|
# ['src'] is SVG URL
|
||||||
|
|
@ -163,20 +147,21 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
else:
|
else:
|
||||||
### Add Image ###
|
### Add Image ###
|
||||||
self.image_list.append(
|
self.image_list.append(
|
||||||
f"https://cdn.discordapp.com/emojis/{message['emojiId']}.png?v=1"
|
f"https://cdn.discordapp.com/emojis/{
|
||||||
|
message['emojiId']}.png?v=1"
|
||||||
)
|
)
|
||||||
ret = "`"
|
ret = "`"
|
||||||
elif (message['type'] == 'inlineCode' or
|
elif (message['type'] == 'inlineCode' or
|
||||||
message['type'] == 'codeBlock' or
|
message['type'] == 'codeBlock' or
|
||||||
message['type'] == 'blockQuote'):
|
message['type'] == 'blockQuote'):
|
||||||
ret = "<span font_family=\"monospace\" background=\"#0004\">%s</span>" % (
|
ret = f"<span font_family=\"monospace\" background=\"#0004\">{
|
||||||
self.make_line(message['content']))
|
self.make_line(message['content'])}</span>"
|
||||||
elif message['type'] == 'u':
|
elif message['type'] == 'u':
|
||||||
ret = "<u>%s</u>" % (self.make_line(message['content']))
|
ret = f"<u>{self.make_line(message['content'])}</u>"
|
||||||
elif message['type'] == 'em':
|
elif message['type'] == 'em':
|
||||||
ret = "<i>%s</i>" % (self.make_line(message['content']))
|
ret = f"<i>{self.make_line(message['content'])}</i>"
|
||||||
elif message['type'] == 's':
|
elif message['type'] == 's':
|
||||||
ret = "<s>%s</s>" % (self.make_line(message['content']))
|
ret = f"<s>{self.make_line(message['content'])}</s>"
|
||||||
elif message['type'] == 'channel':
|
elif message['type'] == 'channel':
|
||||||
ret = self.make_line(message['content'])
|
ret = self.make_line(message['content'])
|
||||||
elif message['type'] == 'mention':
|
elif message['type'] == 'mention':
|
||||||
|
|
@ -189,14 +174,13 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
self.warned_filetypes.append(message['type'])
|
self.warned_filetypes.append(message['type'])
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def recv_attach(self, identifier, pix, mask):
|
def recv_attach(self, identifier, pix, _mask):
|
||||||
"""
|
"""Callback from image_getter"""
|
||||||
Called when an image has been downloaded by image_getter
|
|
||||||
"""
|
|
||||||
self.attachment[identifier] = pix
|
self.attachment[identifier] = pix
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def has_content(self):
|
def has_content(self):
|
||||||
|
"""Returns true if overlay has meaningful content to render"""
|
||||||
if self.piggyback and self.piggyback.has_content():
|
if self.piggyback and self.piggyback.has_content():
|
||||||
return True
|
return True
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
|
|
@ -206,15 +190,12 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
return self.content
|
return self.content
|
||||||
|
|
||||||
def overlay_draw(self, w, context, data=None):
|
def overlay_draw(self, w, context, data=None):
|
||||||
"""
|
"""Draw the overlay"""
|
||||||
Draw the overlay
|
|
||||||
"""
|
|
||||||
if self.piggyback:
|
if self.piggyback:
|
||||||
self.piggyback.overlay_draw(w, context, data)
|
self.piggyback.overlay_draw(w, context, data)
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
return
|
return
|
||||||
self.context = context
|
self.context = context
|
||||||
(width, height) = self.get_size()
|
|
||||||
if not self.piggyback_parent:
|
if not self.piggyback_parent:
|
||||||
context.set_antialias(cairo.ANTIALIAS_GOOD)
|
context.set_antialias(cairo.ANTIALIAS_GOOD)
|
||||||
context.set_source_rgba(0.0, 0.0, 0.0, 0.0)
|
context.set_source_rgba(0.0, 0.0, 0.0, 0.0)
|
||||||
|
|
@ -234,7 +215,6 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
context.translate(floating_x, floating_y)
|
context.translate(floating_x, floating_y)
|
||||||
context.rectangle(0, 0, floating_width, floating_height)
|
context.rectangle(0, 0, floating_width, floating_height)
|
||||||
context.clip()
|
context.clip()
|
||||||
pass
|
|
||||||
(floating_x, floating_y, floating_width,
|
(floating_x, floating_y, floating_width,
|
||||||
floating_height) = self.get_floating_coords()
|
floating_height) = self.get_floating_coords()
|
||||||
current_y = floating_height
|
current_y = floating_height
|
||||||
|
|
@ -249,7 +229,7 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
if 'nick_col' in line and line['nick_col']:
|
if 'nick_col' in line and line['nick_col']:
|
||||||
col = line['nick_col']
|
col = line['nick_col']
|
||||||
for in_line in line['content']:
|
for in_line in line['content']:
|
||||||
out_line = "%s%s" % (out_line, self.make_line(in_line))
|
out_line = f"{out_line}{self.make_line(in_line)}"
|
||||||
if line['attach'] and self.show_attach:
|
if line['attach'] and self.show_attach:
|
||||||
attachment = line['attach'][0]
|
attachment = line['attach'][0]
|
||||||
url = attachment['url']
|
url = attachment['url']
|
||||||
|
|
@ -267,10 +247,8 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
else:
|
else:
|
||||||
log.warning("Unknown file extension '%s'", extension)
|
log.warning("Unknown file extension '%s'", extension)
|
||||||
# cy = self.draw_text(cy, "%s" % (line['attach']))
|
# cy = self.draw_text(cy, "%s" % (line['attach']))
|
||||||
message = "<span foreground='%s'>%s</span>: %s" % (self.sanitize_string(col),
|
message = f"<span foreground='{self.sanitize_string(col)}'>{self.sanitize_string(
|
||||||
self.sanitize_string(
|
line["nick"])}</span>: {out_line}"
|
||||||
line["nick"]),
|
|
||||||
out_line)
|
|
||||||
current_y = self.draw_text(current_y, message)
|
current_y = self.draw_text(current_y, message)
|
||||||
if current_y <= 0:
|
if current_y <= 0:
|
||||||
# We've done enough
|
# We've done enough
|
||||||
|
|
@ -279,10 +257,8 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
self.context = None
|
self.context = None
|
||||||
|
|
||||||
def draw_attach(self, pos_y, url):
|
def draw_attach(self, pos_y, url):
|
||||||
"""
|
"""Draw an attachment"""
|
||||||
Draw an attachment
|
(_floating_x, _floating_y, floating_width,
|
||||||
"""
|
|
||||||
(floating_x, floating_y, floating_width,
|
|
||||||
floating_height) = self.get_floating_coords()
|
floating_height) = self.get_floating_coords()
|
||||||
if url in self.attachment and self.attachment[url]:
|
if url in self.attachment and self.attachment[url]:
|
||||||
pix = self.attachment[url]
|
pix = self.attachment[url]
|
||||||
|
|
@ -302,16 +278,14 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
return pos_y
|
return pos_y
|
||||||
|
|
||||||
def draw_text(self, pos_y, text):
|
def draw_text(self, pos_y, text):
|
||||||
"""
|
"""Draw a text message, returning the Y position of the next message"""
|
||||||
Draw a text message, returning the Y position of the next message
|
|
||||||
"""
|
|
||||||
layout = self.create_pango_layout(text)
|
layout = self.create_pango_layout(text)
|
||||||
layout.set_auto_dir(True)
|
layout.set_auto_dir(True)
|
||||||
layout.set_markup(text, -1)
|
layout.set_markup(text, -1)
|
||||||
attr = layout.get_attributes()
|
attr = layout.get_attributes()
|
||||||
|
|
||||||
(floating_x, floating_y, floating_width,
|
(_floating_x, _floating_y, floating_width,
|
||||||
floating_height) = self.get_floating_coords()
|
_floating_height) = self.get_floating_coords()
|
||||||
layout.set_width(Pango.SCALE * floating_width)
|
layout.set_width(Pango.SCALE * floating_width)
|
||||||
layout.set_spacing(Pango.SCALE * 3)
|
layout.set_spacing(Pango.SCALE * 3)
|
||||||
if self.text_font:
|
if self.text_font:
|
||||||
|
|
@ -351,11 +325,9 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
return pos_y - text_height
|
return pos_y - text_height
|
||||||
|
|
||||||
def render_custom(self, ctx, shape, path, _data):
|
def render_custom(self, ctx, shape, path, _data):
|
||||||
"""
|
"""Draw an inline image as a custom emoticon"""
|
||||||
Draw an inline image as a custom emoticon
|
|
||||||
"""
|
|
||||||
if shape.data >= len(self.image_list):
|
if shape.data >= len(self.image_list):
|
||||||
log.warning(f"{shape.data} >= {len(self.image_list)}")
|
log.warning("%s >= %s", shape.data, len(self.image_list))
|
||||||
return
|
return
|
||||||
# key is the url to the image
|
# key is the url to the image
|
||||||
key = self.image_list[shape.data]
|
key = self.image_list[shape.data]
|
||||||
|
|
@ -371,9 +343,7 @@ class TextOverlayWindow(OverlayWindow):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def sanitize_string(self, string):
|
def sanitize_string(self, string):
|
||||||
"""
|
"""Sanitize a text message so that it doesn't intefere with Pango's XML format"""
|
||||||
Sanitize a text message so that it doesn't intefere with Pango's XML format
|
|
||||||
"""
|
|
||||||
string = string.replace("&", "&")
|
string = string.replace("&", "&")
|
||||||
string = string.replace("<", "<")
|
string = string.replace("<", "<")
|
||||||
string = string .replace(">", ">")
|
string = string .replace(">", ">")
|
||||||
|
|
|
||||||
|
|
@ -15,16 +15,15 @@ import random
|
||||||
import gettext
|
import gettext
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import cairo
|
|
||||||
import sys
|
import sys
|
||||||
import locale
|
import locale
|
||||||
import pkg_resources
|
|
||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
|
import cairo
|
||||||
|
import pkg_resources
|
||||||
from .overlay import OverlayWindow
|
from .overlay import OverlayWindow
|
||||||
from .image_getter import get_surface, draw_img_to_rect, draw_img_to_mask
|
from .image_getter import get_surface, draw_img_to_rect, draw_img_to_mask
|
||||||
# pylint: disable=wrong-import-order
|
# pylint: disable=wrong-import-order
|
||||||
import gi
|
import gi
|
||||||
gi.require_version("Gtk", "3.0")
|
|
||||||
gi.require_version('PangoCairo', '1.0')
|
gi.require_version('PangoCairo', '1.0')
|
||||||
# pylint: disable=wrong-import-position,wrong-import-order
|
# pylint: disable=wrong-import-position,wrong-import-order
|
||||||
from gi.repository import Pango, PangoCairo, GLib # nopep8
|
from gi.repository import Pango, PangoCairo, GLib # nopep8
|
||||||
|
|
@ -55,12 +54,11 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
scream = ''
|
scream = ''
|
||||||
if random.randint(0, 20) == 2:
|
if random.randint(0, 20) == 2:
|
||||||
scream = random.randint(8, 15)*'a'
|
scream = random.randint(8, 15)*'a'
|
||||||
name = "Player %d %s" % (i, scream)
|
name = f"Player {i} {scream}"
|
||||||
self.dummy_data.append({
|
self.dummy_data.append({
|
||||||
"id": i,
|
"id": i,
|
||||||
"username": name,
|
"username": name,
|
||||||
"avatar": None,
|
"avatar": None,
|
||||||
"mute": False,
|
|
||||||
"deaf": mostly_false[random.randint(0, 7)],
|
"deaf": mostly_false[random.randint(0, 7)],
|
||||||
"mute": mostly_false[random.randint(0, 7)],
|
"mute": mostly_false[random.randint(0, 7)],
|
||||||
"speaking": speaking,
|
"speaking": speaking,
|
||||||
|
|
@ -82,6 +80,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.highlight_self = None
|
self.highlight_self = None
|
||||||
self.order = None
|
self.order = None
|
||||||
self.def_avatar = None
|
self.def_avatar = None
|
||||||
|
self.def_avatar_mask = None
|
||||||
self.channel_icon = None
|
self.channel_icon = None
|
||||||
self.channel_mask = None
|
self.channel_mask = None
|
||||||
self.channel_icon_url = None
|
self.channel_icon_url = None
|
||||||
|
|
@ -95,6 +94,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.border_width = 2
|
self.border_width = 2
|
||||||
self.icon_transparency = 0.0
|
self.icon_transparency = 0.0
|
||||||
self.fancy_border = False
|
self.fancy_border = False
|
||||||
|
self.only_speaking_grace_period = 0
|
||||||
|
|
||||||
self.fade_out_inactive = True
|
self.fade_out_inactive = True
|
||||||
self.fade_out_limit = 0.1
|
self.fade_out_limit = 0.1
|
||||||
|
|
@ -130,7 +130,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.redraw()
|
self.redraw()
|
||||||
|
|
||||||
def reset_action_timer(self):
|
def reset_action_timer(self):
|
||||||
# Reset time since last voice activity
|
"""Reset time since last voice activity"""
|
||||||
self.fade_opacity = 1.0
|
self.fade_opacity = 1.0
|
||||||
|
|
||||||
# Remove both fading-out effect and timer set last time this happened
|
# Remove both fading-out effect and timer set last time this happened
|
||||||
|
|
@ -141,13 +141,13 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
GLib.source_remove(self.fadeout_timeout)
|
GLib.source_remove(self.fadeout_timeout)
|
||||||
self.fadeout_timeout = None
|
self.fadeout_timeout = None
|
||||||
|
|
||||||
# If we're using this feature, schedule a new iactivity timer
|
# If we're using this feature, schedule a new inactivity timer
|
||||||
if self.fade_out_inactive:
|
if self.fade_out_inactive:
|
||||||
self.inactive_timeout = GLib.timeout_add_seconds(
|
self.inactive_timeout = GLib.timeout_add_seconds(
|
||||||
self.inactive_time, self.overlay_inactive)
|
self.inactive_time, self.overlay_inactive)
|
||||||
|
|
||||||
def overlay_inactive(self):
|
def overlay_inactive(self):
|
||||||
# Inactivity has hit the first threshold, start fading out
|
"""Timed callback when inactivity limit is hit"""
|
||||||
self.fade_start = perf_counter()
|
self.fade_start = perf_counter()
|
||||||
# Fade out in 200 steps over X seconds.
|
# Fade out in 200 steps over X seconds.
|
||||||
self.fadeout_timeout = GLib.timeout_add(
|
self.fadeout_timeout = GLib.timeout_add(
|
||||||
|
|
@ -156,8 +156,10 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def overlay_fadeout(self):
|
def overlay_fadeout(self):
|
||||||
|
"""Repeated callback after inactivity started"""
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
# There's no guarantee over the granularity of the callback here, so use our time-since to work out how faded out we should be
|
# There's no guarantee over the granularity of the callback here,
|
||||||
|
# so use our time-since to work out how faded out we should be
|
||||||
# Might look choppy on systems under high cpu usage but that's just how it's going to be
|
# Might look choppy on systems under high cpu usage but that's just how it's going to be
|
||||||
now = perf_counter()
|
now = perf_counter()
|
||||||
time_percent = (now - self.fade_start) / self.inactive_fade_time
|
time_percent = (now - self.fade_start) / self.inactive_fade_time
|
||||||
|
|
@ -171,21 +173,22 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def col(self, col, alpha=1.0):
|
def col(self, col, alpha=1.0):
|
||||||
"""
|
"""Convenience function to set the cairo context next colour.
|
||||||
Convenience function to set the cairo context next colour. Altered to account for fade-out function
|
Altered to account for fade-out function"""
|
||||||
"""
|
if alpha is None:
|
||||||
if alpha == None:
|
|
||||||
self.context.set_source_rgba(col[0], col[1], col[2], col[3])
|
self.context.set_source_rgba(col[0], col[1], col[2], col[3])
|
||||||
else:
|
else:
|
||||||
self.context.set_source_rgba(
|
self.context.set_source_rgba(
|
||||||
col[0], col[1], col[2], col[3] * alpha * self.fade_opacity)
|
col[0], col[1], col[2], col[3] * alpha * self.fade_opacity)
|
||||||
|
|
||||||
def set_icon_transparency(self, trans):
|
def set_icon_transparency(self, trans):
|
||||||
|
"""Config option: icon transparency"""
|
||||||
if self.icon_transparency != trans:
|
if self.icon_transparency != trans:
|
||||||
self.icon_transparency = trans
|
self.icon_transparency = trans
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_blank(self):
|
def set_blank(self):
|
||||||
|
"""Set data to blank and redraw"""
|
||||||
self.userlist = []
|
self.userlist = []
|
||||||
self.channel_icon = None
|
self.channel_icon = None
|
||||||
self.channel_icon_url = None
|
self.channel_icon_url = None
|
||||||
|
|
@ -194,7 +197,9 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_fade_out_inactive(self, enabled, fade_time, fade_duration, fade_to):
|
def set_fade_out_inactive(self, enabled, fade_time, fade_duration, fade_to):
|
||||||
if self.fade_out_inactive != enabled or self.inactive_time != fade_time or self.inactive_fade_time != fade_duration or self.fade_out_limit != fade_to:
|
"""Config option: fade out options"""
|
||||||
|
if (self.fade_out_inactive != enabled or self.inactive_time != fade_time or
|
||||||
|
self.inactive_fade_time != fade_duration or self.fade_out_limit != fade_to):
|
||||||
self.fade_out_inactive = enabled
|
self.fade_out_inactive = enabled
|
||||||
self.inactive_time = fade_time
|
self.inactive_time = fade_time
|
||||||
self.inactive_fade_time = fade_duration
|
self.inactive_fade_time = fade_duration
|
||||||
|
|
@ -202,288 +207,235 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.reset_action_timer()
|
self.reset_action_timer()
|
||||||
|
|
||||||
def set_title_font(self, font):
|
def set_title_font(self, font):
|
||||||
|
"""Config option: font used to render title"""
|
||||||
if self.title_font != font:
|
if self.title_font != font:
|
||||||
self.title_font = font
|
self.title_font = font
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_show_connection(self, show_connection):
|
def set_show_connection(self, show_connection):
|
||||||
|
"""Config option: show connection status alongside users"""
|
||||||
if self.show_connection != show_connection:
|
if self.show_connection != show_connection:
|
||||||
self.show_connection = show_connection
|
self.show_connection = show_connection
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_show_avatar(self, show_avatar):
|
def set_show_avatar(self, show_avatar):
|
||||||
|
"""Config option: show avatar icons"""
|
||||||
if self.show_avatar != show_avatar:
|
if self.show_avatar != show_avatar:
|
||||||
self.show_avatar = show_avatar
|
self.show_avatar = show_avatar
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_show_title(self, show_title):
|
def set_show_title(self, show_title):
|
||||||
|
"""Config option: show channel title alongside users"""
|
||||||
if self.show_title != show_title:
|
if self.show_title != show_title:
|
||||||
self.show_title = show_title
|
self.show_title = show_title
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_show_disconnected(self, show_disconnected):
|
def set_show_disconnected(self, show_disconnected):
|
||||||
|
"""Config option: show even when disconnected from voice chat"""
|
||||||
if self.show_disconnected != show_disconnected:
|
if self.show_disconnected != show_disconnected:
|
||||||
self.show_disconnected = show_disconnected
|
self.show_disconnected = show_disconnected
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_show_dummy(self, show_dummy):
|
def set_show_dummy(self, show_dummy):
|
||||||
"""
|
"""Config option: Show placeholder information"""
|
||||||
Toggle use of dummy userdata to help choose settings
|
|
||||||
"""
|
|
||||||
if self.use_dummy != show_dummy:
|
if self.use_dummy != show_dummy:
|
||||||
self.use_dummy = show_dummy
|
self.use_dummy = show_dummy
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_dummy_count(self, dummy_count):
|
def set_dummy_count(self, dummy_count):
|
||||||
|
"""Config option: Change the count of placeholders"""
|
||||||
if self.dummy_count != dummy_count:
|
if self.dummy_count != dummy_count:
|
||||||
self.dummy_count = dummy_count
|
self.dummy_count = dummy_count
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_overflow(self, overflow):
|
def set_overflow_style(self, overflow):
|
||||||
"""
|
"""Config option: Change handling of too many users to render"""
|
||||||
How should excessive numbers of users be dealt with?
|
|
||||||
"""
|
|
||||||
if self.overflow != overflow:
|
if self.overflow != overflow:
|
||||||
self.overflow = overflow
|
self.overflow = overflow
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_bg(self, background_colour):
|
def set_bg(self, background_colour):
|
||||||
"""
|
"""Config option: Set background colour. Used to draw the transparent window.
|
||||||
Set the background colour
|
Should not be changed as then the entire screen is obscured"""
|
||||||
"""
|
|
||||||
if self.norm_col != background_colour:
|
if self.norm_col != background_colour:
|
||||||
self.norm_col = background_colour
|
self.norm_col = background_colour
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_fg(self, foreground_colour):
|
def set_fg(self, foreground_colour):
|
||||||
"""
|
"""Config option: Set foreground colour. Used to render text"""
|
||||||
Set the text colour
|
|
||||||
"""
|
|
||||||
if self.text_col != foreground_colour:
|
if self.text_col != foreground_colour:
|
||||||
self.text_col = foreground_colour
|
self.text_col = foreground_colour
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_tk(self, talking_colour):
|
def set_tk(self, talking_colour):
|
||||||
"""
|
"""Config option: Set talking border colour.
|
||||||
Set the border colour for users who are talking
|
Used to render border around users who are talking"""
|
||||||
"""
|
|
||||||
if self.talk_col != talking_colour:
|
if self.talk_col != talking_colour:
|
||||||
self.talk_col = talking_colour
|
self.talk_col = talking_colour
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_mt(self, mute_colour):
|
def set_mt(self, mute_colour):
|
||||||
"""
|
"""Config option: Set mute colour. Used to render mute and deaf images"""
|
||||||
Set the colour of mute and deafen logos
|
|
||||||
"""
|
|
||||||
if self.mute_col != mute_colour:
|
if self.mute_col != mute_colour:
|
||||||
self.mute_col = mute_colour
|
self.mute_col = mute_colour
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_mute_bg(self, mute_bg_col):
|
def set_mute_bg(self, mute_bg_col):
|
||||||
"""
|
"""Config option: Set mute background colour.
|
||||||
Set the background colour for mute/deafen icon
|
Used to tint the user avatar before rendering the mute or deaf image above it"""
|
||||||
"""
|
|
||||||
if self.mute_bg_col != mute_bg_col:
|
if self.mute_bg_col != mute_bg_col:
|
||||||
self.mute_bg_col = mute_bg_col
|
self.mute_bg_col = mute_bg_col
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_avatar_bg_col(self, avatar_bg_col):
|
def set_avatar_bg_col(self, avatar_bg_col):
|
||||||
"""
|
"""Config option: Set avatar background colour.
|
||||||
Set Avatar background colour
|
Drawn before user avatar but only visible if default fallback avatar can't be found"""
|
||||||
"""
|
|
||||||
if self.avatar_bg_col != avatar_bg_col:
|
if self.avatar_bg_col != avatar_bg_col:
|
||||||
self.avatar_bg_col = avatar_bg_col
|
self.avatar_bg_col = avatar_bg_col
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_hi(self, highlight_colour):
|
def set_hi(self, highlight_colour):
|
||||||
"""
|
"""Config option: Set talking background colour.
|
||||||
Set the colour of background for speaking users
|
Used to render the background behind users name."""
|
||||||
"""
|
|
||||||
if self.hili_col != highlight_colour:
|
if self.hili_col != highlight_colour:
|
||||||
self.hili_col = highlight_colour
|
self.hili_col = highlight_colour
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_fg_hi(self, highlight_colour):
|
def set_fg_hi(self, highlight_colour):
|
||||||
"""
|
"""Config option: Set talking text colour.
|
||||||
Set the colour of background for speaking users
|
Used to render the usernames of users who are talking"""
|
||||||
"""
|
|
||||||
if self.text_hili_col != highlight_colour:
|
if self.text_hili_col != highlight_colour:
|
||||||
self.text_hili_col = highlight_colour
|
self.text_hili_col = highlight_colour
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_bo(self, border_colour):
|
def set_bo(self, border_colour):
|
||||||
"""
|
"""Config option: Set border colour. Used to render border around users"""
|
||||||
Set the colour for idle border
|
|
||||||
"""
|
|
||||||
if self.border_col != border_colour:
|
if self.border_col != border_colour:
|
||||||
self.border_col = border_colour
|
self.border_col = border_colour
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_avatar_size(self, size):
|
def set_avatar_size(self, size):
|
||||||
"""
|
"""Config option: Set avatar size in window-space pixels"""
|
||||||
Set the size of the avatar icons
|
|
||||||
"""
|
|
||||||
if self.avatar_size != size:
|
if self.avatar_size != size:
|
||||||
self.avatar_size = size
|
self.avatar_size = size
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_nick_length(self, size):
|
def set_nick_length(self, size):
|
||||||
"""
|
"""Config option: Limit username length"""
|
||||||
Set the length of nickname
|
|
||||||
"""
|
|
||||||
if self.nick_length != size:
|
if self.nick_length != size:
|
||||||
self.nick_length = size
|
self.nick_length = size
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_icon_spacing(self, i):
|
def set_icon_spacing(self, i):
|
||||||
"""
|
"""Config option: Space between users in the list, in window-space pixels"""
|
||||||
Set the spacing between avatar icons
|
|
||||||
"""
|
|
||||||
if self.icon_spacing != i:
|
if self.icon_spacing != i:
|
||||||
self.icon_spacing = i
|
self.icon_spacing = i
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_text_padding(self, i):
|
def set_text_padding(self, i):
|
||||||
"""
|
"""Config option: Space between user avatar and username, in window-space pixels"""
|
||||||
Set padding between text and border
|
|
||||||
"""
|
|
||||||
if self.text_pad != i:
|
if self.text_pad != i:
|
||||||
self.text_pad = i
|
self.text_pad = i
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_text_baseline_adj(self, i):
|
def set_text_baseline_adj(self, i):
|
||||||
"""
|
"""Config option: Vertical offset used to render all text, in window-space pixels"""
|
||||||
Set padding between text and border
|
|
||||||
"""
|
|
||||||
if self.text_baseline_adj != i:
|
if self.text_baseline_adj != i:
|
||||||
self.text_baseline_adj = i
|
self.text_baseline_adj = i
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_vert_edge_padding(self, i):
|
def set_vert_edge_padding(self, i):
|
||||||
"""
|
"""Config option: Vertical offset from edge of window, in window-space pixels"""
|
||||||
Set padding between top/bottom of screen and overlay contents
|
|
||||||
"""
|
|
||||||
if self.vert_edge_padding != i:
|
if self.vert_edge_padding != i:
|
||||||
self.vert_edge_padding = i
|
self.vert_edge_padding = i
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_horz_edge_padding(self, i):
|
def set_horz_edge_padding(self, i):
|
||||||
"""
|
"""Config option: Horizontal offset from edge of window, in window-space pixels"""
|
||||||
Set padding between left/right of screen and overlay contents
|
|
||||||
"""
|
|
||||||
if self.horz_edge_padding != i:
|
if self.horz_edge_padding != i:
|
||||||
self.horz_edge_padding = i
|
self.horz_edge_padding = i
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_square_avatar(self, i):
|
def set_square_avatar(self, i):
|
||||||
"""
|
"""Config option: Mask avatar with a circle before rendering"""
|
||||||
Set if the overlay should crop avatars to a circle or show full square image
|
|
||||||
"""
|
|
||||||
if self.round_avatar == i:
|
if self.round_avatar == i:
|
||||||
self.round_avatar = not i
|
self.round_avatar = not i
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_fancy_border(self, border):
|
def set_fancy_border(self, border):
|
||||||
"""
|
"""Config option: Use transparent edges of image as border,
|
||||||
Sets if border should wrap around non-square avatar images
|
instead of mask (square/circle)"""
|
||||||
"""
|
|
||||||
if self.fancy_border != border:
|
if self.fancy_border != border:
|
||||||
self.fancy_border = border
|
self.fancy_border = border
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_only_speaking(self, only_speaking):
|
def set_only_speaking(self, only_speaking):
|
||||||
"""
|
"""Config option: Filter user list to only those who
|
||||||
Set if overlay should only show people who are talking
|
are talking and those who have stopped talking recently"""
|
||||||
"""
|
|
||||||
if self.only_speaking != only_speaking:
|
if self.only_speaking != only_speaking:
|
||||||
self.only_speaking = only_speaking
|
self.only_speaking = only_speaking
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_only_speaking_grace_period(self, grace_period):
|
def set_only_speaking_grace_period(self, grace_period):
|
||||||
"""
|
"""Config option: How long after stopping speaking the user remains shown"""
|
||||||
Set grace period before hiding people who are not talking
|
|
||||||
"""
|
|
||||||
self.only_speaking_grace_period = grace_period
|
self.only_speaking_grace_period = grace_period
|
||||||
self.timer_after_draw = grace_period
|
self.timer_after_draw = grace_period
|
||||||
|
|
||||||
def set_highlight_self(self, highlight_self):
|
def set_highlight_self(self, highlight_self):
|
||||||
"""
|
"""Config option: Local User should be kept at top of list"""
|
||||||
Set if the overlay should highlight the user
|
|
||||||
"""
|
|
||||||
if self.highlight_self != highlight_self:
|
if self.highlight_self != highlight_self:
|
||||||
self.highlight_self = highlight_self
|
self.highlight_self = highlight_self
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_order(self, i):
|
def set_order(self, i):
|
||||||
"""
|
"""Config option: Set method used to order user list"""
|
||||||
Set the method used to order avatar icons & names
|
|
||||||
"""
|
|
||||||
if self.order != i:
|
if self.order != i:
|
||||||
self.order = i
|
self.order = i
|
||||||
self.sort_list(self.userlist)
|
self.sort_list(self.userlist)
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_icon_only(self, i):
|
def set_icon_only(self, i):
|
||||||
"""
|
"""Config option: Show only the avatar, without text or its background"""
|
||||||
Set if the overlay should draw only the icon
|
|
||||||
"""
|
|
||||||
if self.icon_only != i:
|
if self.icon_only != i:
|
||||||
self.icon_only = i
|
self.icon_only = i
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_border_width(self, width):
|
def set_drawn_border_width(self, width):
|
||||||
|
"""Config option: Set width of border around username and avatar"""
|
||||||
if self.border_width != width:
|
if self.border_width != width:
|
||||||
self.border_width = width
|
self.border_width = width
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_horizontal(self, horizontal=False):
|
def set_horizontal(self, horizontal=False):
|
||||||
|
"""Config option: Userlist should be drawn horizontally"""
|
||||||
if self.horizontal != horizontal:
|
if self.horizontal != horizontal:
|
||||||
self.horizontal = horizontal
|
self.horizontal = horizontal
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_guild_ids(self, guild_ids=tuple()):
|
|
||||||
if self.discover.connection:
|
|
||||||
for _id in guild_ids:
|
|
||||||
if _id not in self.guild_ids:
|
|
||||||
self.discover.connection.req_channels(_id)
|
|
||||||
self.guild_ids = guild_ids
|
|
||||||
|
|
||||||
def set_wind_col(self):
|
def set_wind_col(self):
|
||||||
"""
|
"""Use window colour to draw"""
|
||||||
Use window colour to draw
|
|
||||||
"""
|
|
||||||
self.col(self.wind_col, None)
|
self.col(self.wind_col, None)
|
||||||
|
|
||||||
def set_norm_col(self):
|
def set_norm_col(self):
|
||||||
"""
|
"""Use background colour to draw"""
|
||||||
Use background colour to draw
|
|
||||||
"""
|
|
||||||
self.col(self.norm_col)
|
self.col(self.norm_col)
|
||||||
|
|
||||||
def set_talk_col(self, alpha=1.0):
|
def set_talk_col(self, alpha=1.0):
|
||||||
"""
|
"""Use talking colour to draw"""
|
||||||
Use talking colour to draw
|
|
||||||
"""
|
|
||||||
self.col(self.talk_col, alpha)
|
self.col(self.talk_col, alpha)
|
||||||
|
|
||||||
def set_mute_col(self):
|
def set_mute_col(self):
|
||||||
"""
|
"""Use mute colour to draw"""
|
||||||
Use mute colour to draw
|
|
||||||
"""
|
|
||||||
self.col(self.mute_col)
|
self.col(self.mute_col)
|
||||||
|
|
||||||
def set_channel_title(self, channel_title):
|
def set_channel_title(self, channel_title):
|
||||||
"""
|
"""Set title above voice list"""
|
||||||
Set title above voice list
|
|
||||||
"""
|
|
||||||
if self.channel_title != channel_title:
|
if self.channel_title != channel_title:
|
||||||
self.channel_title = channel_title
|
self.channel_title = channel_title
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_channel_icon(self, url):
|
def set_channel_icon(self, url):
|
||||||
"""
|
"""Change the icon for channel"""
|
||||||
Change the icon for channel
|
|
||||||
"""
|
|
||||||
if not url:
|
if not url:
|
||||||
self.channel_icon = None
|
self.channel_icon = None
|
||||||
self.channel_icon_url = None
|
self.channel_icon_url = None
|
||||||
|
|
@ -493,9 +445,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.channel_icon_url = url
|
self.channel_icon_url = url
|
||||||
|
|
||||||
def set_user_list(self, userlist, alt):
|
def set_user_list(self, userlist, alt):
|
||||||
"""
|
"""Set the users in list to draw"""
|
||||||
Set the users in list to draw
|
|
||||||
"""
|
|
||||||
self.userlist = userlist
|
self.userlist = userlist
|
||||||
for user in userlist:
|
for user in userlist:
|
||||||
if "nick" in user:
|
if "nick" in user:
|
||||||
|
|
@ -508,14 +458,13 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def set_connection_status(self, connection):
|
def set_connection_status(self, connection):
|
||||||
"""
|
"""Set if discord has a clean connection to server"""
|
||||||
Set if discord has a clean connection to server
|
|
||||||
"""
|
|
||||||
if self.connection_status != connection['state']:
|
if self.connection_status != connection['state']:
|
||||||
self.connection_status = connection['state']
|
self.connection_status = connection['state']
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def sort_list(self, in_list):
|
def sort_list(self, in_list):
|
||||||
|
"""Take a userlist and sort it according to config option"""
|
||||||
if self.order == 1: # ID Sort
|
if self.order == 1: # ID Sort
|
||||||
in_list.sort(key=lambda x: x["id"])
|
in_list.sort(key=lambda x: x["id"])
|
||||||
elif self.order == 2: # Spoken sort
|
elif self.order == 2: # Spoken sort
|
||||||
|
|
@ -526,6 +475,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
return in_list
|
return in_list
|
||||||
|
|
||||||
def has_content(self):
|
def has_content(self):
|
||||||
|
"""Returns true if overlay has meaningful content to render"""
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
return False
|
return False
|
||||||
if self.hidden:
|
if self.hidden:
|
||||||
|
|
@ -535,9 +485,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
return self.userlist
|
return self.userlist
|
||||||
|
|
||||||
def overlay_draw(self, w, context, data=None):
|
def overlay_draw(self, w, context, data=None):
|
||||||
"""
|
"""Draw the Overlay"""
|
||||||
Draw the Overlay
|
|
||||||
"""
|
|
||||||
self.context = context
|
self.context = context
|
||||||
context.set_antialias(cairo.ANTIALIAS_GOOD)
|
context.set_antialias(cairo.ANTIALIAS_GOOD)
|
||||||
# Get size of window
|
# Get size of window
|
||||||
|
|
@ -566,7 +514,8 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
context.clip()
|
context.clip()
|
||||||
|
|
||||||
context.set_operator(cairo.OPERATOR_OVER)
|
context.set_operator(cairo.OPERATOR_OVER)
|
||||||
if not self.show_disconnected and self.connection_status == "DISCONNECTED" and not self.use_dummy:
|
if (not self.show_disconnected and self.connection_status == "DISCONNECTED"
|
||||||
|
and not self.use_dummy):
|
||||||
return
|
return
|
||||||
|
|
||||||
connection = self.discover.connection
|
connection = self.discover.connection
|
||||||
|
|
@ -624,14 +573,14 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
avatars_per_row = sys.maxsize
|
avatars_per_row = sys.maxsize
|
||||||
|
|
||||||
# Calculate height needed to show overlay
|
# Calculate height needed to show overlay
|
||||||
doTitle = False
|
do_title = False
|
||||||
doConnection = False
|
do_connection = False
|
||||||
if self.show_connection:
|
if self.show_connection:
|
||||||
users_to_draw.insert(0, None)
|
users_to_draw.insert(0, None)
|
||||||
doConnection = True
|
do_connection = True
|
||||||
if self.show_title and self.channel_title:
|
if self.show_title and self.channel_title:
|
||||||
users_to_draw.insert(0, None)
|
users_to_draw.insert(0, None)
|
||||||
doTitle = True
|
do_title = True
|
||||||
|
|
||||||
if self.horizontal:
|
if self.horizontal:
|
||||||
needed_width = (len(users_to_draw) * line_height) + \
|
needed_width = (len(users_to_draw) * line_height) + \
|
||||||
|
|
@ -655,7 +604,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
rows_to_draw = []
|
rows_to_draw = []
|
||||||
while len(users_to_draw) > 0:
|
while len(users_to_draw) > 0:
|
||||||
row = []
|
row = []
|
||||||
for i in range(0, min(avatars_per_row, len(users_to_draw))):
|
for _i in range(0, min(avatars_per_row, len(users_to_draw))):
|
||||||
row.append(users_to_draw.pop(0))
|
row.append(users_to_draw.pop(0))
|
||||||
rows_to_draw.append(row)
|
rows_to_draw.append(row)
|
||||||
for row in rows_to_draw:
|
for row in rows_to_draw:
|
||||||
|
|
@ -668,14 +617,14 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
|
|
||||||
for user in row:
|
for user in row:
|
||||||
if not user:
|
if not user:
|
||||||
if doTitle:
|
if do_title:
|
||||||
doTitle = False
|
do_title = False
|
||||||
text_width = self.draw_title(
|
text_width = self.draw_title(
|
||||||
context, current_x, current_y, avatar_size, line_height)
|
context, current_x, current_y, avatar_size, line_height)
|
||||||
elif doConnection:
|
elif do_connection:
|
||||||
text_width = self.draw_connection(
|
text_width = self.draw_connection(
|
||||||
context, current_x, current_y, avatar_size, line_height)
|
context, current_x, current_y, avatar_size, line_height)
|
||||||
doConnection = False
|
do_connection = False
|
||||||
else:
|
else:
|
||||||
self.draw_avatar(context, user, current_x,
|
self.draw_avatar(context, user, current_x,
|
||||||
current_y, avatar_size, line_height)
|
current_y, avatar_size, line_height)
|
||||||
|
|
@ -712,7 +661,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
cols_to_draw = []
|
cols_to_draw = []
|
||||||
while len(users_to_draw) > 0:
|
while len(users_to_draw) > 0:
|
||||||
col = []
|
col = []
|
||||||
for i in range(0, min(avatars_per_row, len(users_to_draw))):
|
for _i in range(0, min(avatars_per_row, len(users_to_draw))):
|
||||||
col.append(users_to_draw.pop(0))
|
col.append(users_to_draw.pop(0))
|
||||||
cols_to_draw.append(col)
|
cols_to_draw.append(col)
|
||||||
for col in cols_to_draw:
|
for col in cols_to_draw:
|
||||||
|
|
@ -725,22 +674,22 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
largest_text_width = 0
|
largest_text_width = 0
|
||||||
for user in col:
|
for user in col:
|
||||||
if not user:
|
if not user:
|
||||||
if doTitle:
|
if do_title:
|
||||||
# Draw header
|
# Draw header
|
||||||
text_width = self.draw_title(
|
text_width = self.draw_title(
|
||||||
context, current_x, current_y, avatar_size, line_height)
|
context, current_x, current_y, avatar_size, line_height)
|
||||||
largest_text_width = max(
|
largest_text_width = max(
|
||||||
text_width, largest_text_width)
|
text_width, largest_text_width)
|
||||||
current_y += line_height + self.icon_spacing
|
current_y += line_height + self.icon_spacing
|
||||||
doTitle = False
|
do_title = False
|
||||||
elif doConnection:
|
elif do_connection:
|
||||||
# Draw header
|
# Draw header
|
||||||
text_width = self.draw_connection(
|
text_width = self.draw_connection(
|
||||||
context, current_x, current_y, avatar_size, line_height)
|
context, current_x, current_y, avatar_size, line_height)
|
||||||
largest_text_width = max(
|
largest_text_width = max(
|
||||||
text_width, largest_text_width)
|
text_width, largest_text_width)
|
||||||
current_y += line_height + self.icon_spacing
|
current_y += line_height + self.icon_spacing
|
||||||
doConnection = False
|
do_connection = False
|
||||||
|
|
||||||
else:
|
else:
|
||||||
text_width = self.draw_avatar(
|
text_width = self.draw_avatar(
|
||||||
|
|
@ -758,9 +707,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.context = None
|
self.context = None
|
||||||
|
|
||||||
def recv_avatar(self, identifier, pix, mask):
|
def recv_avatar(self, identifier, pix, mask):
|
||||||
"""
|
"""Called when image_getter has downloaded an image"""
|
||||||
Called when image_getter has downloaded an image
|
|
||||||
"""
|
|
||||||
if identifier == 'def':
|
if identifier == 'def':
|
||||||
self.def_avatar = pix
|
self.def_avatar = pix
|
||||||
self.def_avatar_mask = mask
|
self.def_avatar_mask = mask
|
||||||
|
|
@ -773,16 +720,12 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.set_needs_redraw()
|
self.set_needs_redraw()
|
||||||
|
|
||||||
def delete_avatar(self, identifier):
|
def delete_avatar(self, identifier):
|
||||||
"""
|
"""Remove avatar image"""
|
||||||
Remove avatar image
|
|
||||||
"""
|
|
||||||
if identifier in self.avatars:
|
if identifier in self.avatars:
|
||||||
del self.avatars[identifier]
|
del self.avatars[identifier]
|
||||||
|
|
||||||
def draw_title(self, context, pos_x, pos_y, avatar_size, line_height):
|
def draw_title(self, context, pos_x, pos_y, avatar_size, line_height):
|
||||||
"""
|
"""Draw title at given Y position. Includes both text and image based on settings"""
|
||||||
Draw title at given Y position. Includes both text and image based on settings
|
|
||||||
"""
|
|
||||||
tw = 0
|
tw = 0
|
||||||
if not self.horizontal and not self.icon_only:
|
if not self.horizontal and not self.icon_only:
|
||||||
title = self.channel_title
|
title = self.channel_title
|
||||||
|
|
@ -826,9 +769,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
_("VOICE_CONNECTED")
|
_("VOICE_CONNECTED")
|
||||||
|
|
||||||
def draw_connection(self, context, pos_x, pos_y, avatar_size, line_height):
|
def draw_connection(self, context, pos_x, pos_y, avatar_size, line_height):
|
||||||
"""
|
"""Draw title at given Y position. Includes both text and image based on settings"""
|
||||||
Draw title at given Y position. Includes both text and image based on settings
|
|
||||||
"""
|
|
||||||
tw = 0
|
tw = 0
|
||||||
if not self.horizontal and not self.icon_only:
|
if not self.horizontal and not self.icon_only:
|
||||||
tw = self.draw_text(
|
tw = self.draw_text(
|
||||||
|
|
@ -846,13 +787,11 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
return tw
|
return tw
|
||||||
|
|
||||||
def draw_avatar(self, context, user, pos_x, pos_y, avatar_size, line_height):
|
def draw_avatar(self, context, user, pos_x, pos_y, avatar_size, line_height):
|
||||||
"""
|
"""Draw avatar at given Y position. Includes both text and image based on settings"""
|
||||||
Draw avatar at given Y position. Includes both text and image based on settings
|
|
||||||
"""
|
|
||||||
# Ensure pixbuf for avatar
|
# Ensure pixbuf for avatar
|
||||||
if user["id"] not in self.avatars and user["avatar"] and avatar_size > 0:
|
if user["id"] not in self.avatars and user["avatar"] and avatar_size > 0:
|
||||||
url = "https://cdn.discordapp.com/avatars/%s/%s.png" % (
|
url = f"https://cdn.discordapp.com/avatars/{
|
||||||
user['id'], user['avatar'])
|
user['id']}/{user['avatar']}.png"
|
||||||
get_surface(self.recv_avatar, url, user["id"],
|
get_surface(self.recv_avatar, url, user["id"],
|
||||||
self.avatar_size)
|
self.avatar_size)
|
||||||
|
|
||||||
|
|
@ -907,19 +846,18 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
self.mute_bg_col, avatar_size)
|
self.mute_bg_col, avatar_size)
|
||||||
return tw
|
return tw
|
||||||
|
|
||||||
def draw_text(self, context, string, pos_x, pos_y, tx_col, bg_col, avatar_size, line_height, font):
|
def draw_text(self, context, string, pos_x, pos_y,
|
||||||
"""
|
tx_col, bg_col, avatar_size, line_height, font):
|
||||||
Draw username & background at given position
|
"""Draw username & background at given position"""
|
||||||
"""
|
|
||||||
if self.nick_length < 32 and len(string) > self.nick_length:
|
if self.nick_length < 32 and len(string) > self.nick_length:
|
||||||
string = string[:(self.nick_length-1)] + u"\u2026"
|
string = string[:(self.nick_length-1)] + "\u2026"
|
||||||
|
|
||||||
context.save()
|
context.save()
|
||||||
layout = self.create_pango_layout(string)
|
layout = self.create_pango_layout(string)
|
||||||
layout.set_auto_dir(True)
|
layout.set_auto_dir(True)
|
||||||
layout.set_markup(string, -1)
|
layout.set_markup(string, -1)
|
||||||
(floating_x, floating_y, floating_width,
|
(_floating_x, _floating_y, floating_width,
|
||||||
floating_height) = self.get_floating_coords()
|
_floating_height) = self.get_floating_coords()
|
||||||
layout.set_width(Pango.SCALE * floating_width)
|
layout.set_width(Pango.SCALE * floating_width)
|
||||||
layout.set_spacing(Pango.SCALE * 3)
|
layout.set_spacing(Pango.SCALE * 3)
|
||||||
if font:
|
if font:
|
||||||
|
|
@ -971,6 +909,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
return text_width
|
return text_width
|
||||||
|
|
||||||
def blank_avatar(self, context, pos_x, pos_y, avatar_size):
|
def blank_avatar(self, context, pos_x, pos_y, avatar_size):
|
||||||
|
"""Draw a cut-out of the previous shape with a forcible transparent hole"""
|
||||||
context.save()
|
context.save()
|
||||||
if self.round_avatar:
|
if self.round_avatar:
|
||||||
context.arc(pos_x + (avatar_size / 2), pos_y +
|
context.arc(pos_x + (avatar_size / 2), pos_y +
|
||||||
|
|
@ -983,9 +922,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
context.restore()
|
context.restore()
|
||||||
|
|
||||||
def draw_avatar_pix(self, context, pixbuf, mask, pos_x, pos_y, border_colour, avatar_size):
|
def draw_avatar_pix(self, context, pixbuf, mask, pos_x, pos_y, border_colour, avatar_size):
|
||||||
"""
|
"""Draw avatar image at given position"""
|
||||||
Draw avatar image at given position
|
|
||||||
"""
|
|
||||||
if not self.show_avatar:
|
if not self.show_avatar:
|
||||||
return
|
return
|
||||||
# Empty the space for this
|
# Empty the space for this
|
||||||
|
|
@ -1021,13 +958,16 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
if self.round_avatar:
|
if self.round_avatar:
|
||||||
context.new_path()
|
context.new_path()
|
||||||
context.arc(pos_x + (avatar_size / 2), pos_y +
|
context.arc(pos_x + (avatar_size / 2), pos_y +
|
||||||
(avatar_size / 2), avatar_size / 2 + (self.border_width/2.0), 0, 2 * math.pi)
|
(avatar_size / 2), avatar_size / 2 +
|
||||||
|
(self.border_width/2.0), 0, 2 * math.pi)
|
||||||
context.set_line_width(self.border_width)
|
context.set_line_width(self.border_width)
|
||||||
context.stroke()
|
context.stroke()
|
||||||
else:
|
else:
|
||||||
context.new_path()
|
context.new_path()
|
||||||
context.rectangle(pos_x - (self.border_width/2), pos_y - (self.border_width/2),
|
context.rectangle(pos_x - (self.border_width/2),
|
||||||
avatar_size + self.border_width, avatar_size + self.border_width)
|
pos_y - (self.border_width/2),
|
||||||
|
avatar_size + self.border_width,
|
||||||
|
avatar_size + self.border_width)
|
||||||
context.set_line_width(self.border_width)
|
context.set_line_width(self.border_width)
|
||||||
|
|
||||||
context.stroke()
|
context.stroke()
|
||||||
|
|
@ -1053,13 +993,12 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
context.clip()
|
context.clip()
|
||||||
context.set_operator(cairo.OPERATOR_OVER)
|
context.set_operator(cairo.OPERATOR_OVER)
|
||||||
draw_img_to_rect(pixbuf, context, pos_x, pos_y,
|
draw_img_to_rect(pixbuf, context, pos_x, pos_y,
|
||||||
avatar_size, avatar_size, False, False, 0, 0, self.fade_opacity * self.icon_transparency)
|
avatar_size, avatar_size, False, False, 0, 0,
|
||||||
|
self.fade_opacity * self.icon_transparency)
|
||||||
context.restore()
|
context.restore()
|
||||||
|
|
||||||
def draw_mute(self, context, pos_x, pos_y, bg_col, avatar_size):
|
def draw_mute(self, context, pos_x, pos_y, bg_col, avatar_size):
|
||||||
"""
|
"""Draw Mute logo"""
|
||||||
Draw Mute logo
|
|
||||||
"""
|
|
||||||
if avatar_size <= 0:
|
if avatar_size <= 0:
|
||||||
return
|
return
|
||||||
context.save()
|
context.save()
|
||||||
|
|
@ -1126,9 +1065,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
context.restore()
|
context.restore()
|
||||||
|
|
||||||
def draw_deaf(self, context, pos_x, pos_y, bg_col, avatar_size):
|
def draw_deaf(self, context, pos_x, pos_y, bg_col, avatar_size):
|
||||||
"""
|
"""Draw deaf logo"""
|
||||||
Draw deaf logo
|
|
||||||
"""
|
|
||||||
if avatar_size <= 0:
|
if avatar_size <= 0:
|
||||||
return
|
return
|
||||||
context.save()
|
context.save()
|
||||||
|
|
@ -1188,6 +1125,7 @@ class VoiceOverlayWindow(OverlayWindow):
|
||||||
context.restore()
|
context.restore()
|
||||||
|
|
||||||
def draw_connection_icon(self, context, pos_x, pos_y, avatar_size):
|
def draw_connection_icon(self, context, pos_x, pos_y, avatar_size):
|
||||||
|
"""Draw a series of bars to show connectivity state"""
|
||||||
context.save()
|
context.save()
|
||||||
context.translate(pos_x, pos_y)
|
context.translate(pos_x, pos_y)
|
||||||
context.scale(avatar_size, avatar_size)
|
context.scale(avatar_size, avatar_size)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue