- warning : broken

- Started refactor to separate config gui completely
This commit is contained in:
Trigg 2022-07-14 16:36:18 +00:00
parent 3e773ee103
commit 49500d3c75
8 changed files with 5023 additions and 287 deletions

View file

@ -1,83 +0,0 @@
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
"""Overview setting tab on settings window"""
import gettext
import json
import logging
import pkg_resources
from configparser import ConfigParser
import gi
import sys
from .settings import SettingsWindow
log = logging.getLogger(__name__)
t = gettext.translation('default', pkg_resources.resource_filename(
'discover_overlay', 'locales'), fallback=True)
_ = t.gettext
gi.require_version("Gtk", "3.0")
# pylint: disable=wrong-import-position,wrong-import-order
from gi.repository import Gtk, Gdk, GLib # nopep8
GUILD_DEFAULT_VALUE = "0"
class AboutSettingsWindow(Gtk.Grid):
"""Basic overview and a nicer looking landing page for Steam Deck"""
def __init__(self, discover):
Gtk.Grid.__init__(self)
self.discover = discover
self.create_gui()
def create_gui(self):
"""
Prepare the gui
"""
spacing_box_1 = Gtk.Box()
spacing_box_1.set_size_request(60, 60)
self.attach(spacing_box_1, 1, 0, 1, 1)
icon = Gtk.Image.new_from_icon_name("discover-overlay-tray", 256)
icon.set_pixel_size(128)
self.attach(icon, 1, 1, 1, 1)
spacing_box_2 = Gtk.Box()
spacing_box_2.set_size_request(60, 60)
self.attach(spacing_box_2, 1, 2, 1, 1)
blurb = Gtk.Label.new(None)
message = "<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" % (
_("Welcome to Discover Overlay"),
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."),
_("Please visit our discord"),
_(" for support. Or open an issue on our GitHub ")
)
blurb.set_markup(message)
blurb.set_line_wrap(True)
self.attach(blurb, 1, 3, 1, 1)
killapp = Gtk.Button.new_with_label(_("Close overlay"))
killapp.connect("pressed", self.close_app)
self.attach(killapp, 1, 5, 1, 1)
self.set_column_homogeneous(True)
def close_app(self, button):
log.info("Quit pressed")
sys.exit(0)
def present_settings(self):
self.show_all()

View file

@ -126,6 +126,7 @@ class DiscordConnector:
self.current_text = "0"
return
if channel != self.current_text:
self.current_text = channel
self.start_listening_text(channel)
if need_req:
self.req_channel_details(channel)
@ -305,7 +306,8 @@ class DiscordConnector:
self.set_in_room(j["data"]["user_id"], True)
elif j["evt"] == "VOICE_CHANNEL_SELECT":
if j["data"]["channel_id"]:
self.set_channel(j["data"]["channel_id"], j["data"]["guild_id"])
self.set_channel(j["data"]["channel_id"],
j["data"]["guild_id"])
else:
self.set_channel(None, None)
elif j["evt"] == "VOICE_CONNECTION_STATUS":
@ -344,15 +346,18 @@ class DiscordConnector:
elif j["cmd"] == "GET_GUILDS":
for guild in j["data"]["guilds"]:
self.guilds[guild["id"]] = guild
if len(self.discover.settings.voice_settings.guild_ids) == 0 or guild["id"] in self.discover.settings.voice_settings.guild_ids:
self.req_channels(guild["id"])
# TODO Update settings window with guild/channel list
# self.discover.settings.add_guild(guild["id"])
# if len(self.discover.settings.voice_settings.guild_ids) == 0 or guild["id"] in self.discover.settings.voice_settings.guild_ids:
# self.req_channels(guild["id"])
return
elif j["cmd"] == "GET_GUILD":
# We currently only get here because of a "CHANNEL_CREATE" event. Stupidly long winded way around
if j["data"]:
guild = j["data"]
if len(self.discover.settings.voice_settings.guild_ids) == 0 or guild["id"] in self.discover.settings.voice_settings.guild_ids:
self.req_channels(guild["id"])
# TODO Check if this is the guild in text settings, if so request an update list
# if len(self.discover.settings.voice_settings.guild_ids) == 0 or guild["id"] in self.discover.settings.voice_settings.guild_ids:
# self.req_channels(guild["id"])
return
elif j["cmd"] == "GET_CHANNELS":
self.guilds[j['nonce']]["channels"] = j["data"]["channels"]
@ -362,9 +367,10 @@ class DiscordConnector:
self.channels[channel["id"]] = channel
if channel["type"] == 2:
self.req_channel_details(channel["id"])
if j["nonce"] == self.discover.settings.text_settings.get_guild():
self.discover.settings.text_settings.set_channels(j["data"]["channels"])
self.check_guilds()
# TODO At this point change the channel list in settings
# if j["nonce"] == self.discover.settings.text_settings.get_guild():
# self.discover.settings.text_settings.set_channels(
# j["data"]["channels"])
return
elif j["cmd"] == "SUBSCRIBE":
# Only log errors
@ -375,10 +381,12 @@ class DiscordConnector:
return
elif j["cmd"] == "GET_SELECTED_VOICE_CHANNEL":
if 'data' in j and j['data'] and 'id' in j['data']:
self.set_channel(j['data']['id'],j['data']['guild_id'])
self.discover.voice_overlay.set_channel_title(j["data"]["name"])
self.set_channel(j['data']['id'], j['data']['guild_id'])
self.discover.voice_overlay.set_channel_title(
j["data"]["name"])
if self.current_guild in self.guilds and 'icon_url' in self.guilds[self.current_guild]:
self.discover.voice_overlay.set_channel_icon(self.guilds[self.current_guild]['icon_url'])
self.discover.voice_overlay.set_channel_icon(
self.guilds[self.current_guild]['icon_url'])
else:
self.discover.voice_overlay.set_channel_icon(None)
self.list_altered = True
@ -418,14 +426,6 @@ class DiscordConnector:
return
log.warning(j)
def check_guilds(self):
"""
Check if all of the guilds contain a channel
"""
for guild in self.guilds.values():
if len(self.discover.settings.voice_settings.guild_ids) > 0 and guild["id"] in self.discover.settings.voice_settings.guild_ids and "channels" not in guild:
return
def on_connected(self):
"""
Called when connection is finalised
@ -686,9 +686,6 @@ class DiscordConnector:
Called at 60Hz approximately but has near zero bearing on rendering
"""
if self.discover.show_settings_delay:
self.discover.show_settings_delay = False
self.discover.show_settings()
# Ensure connection
if not self.websocket:
if self.reconnect_delay <= 0:
@ -713,13 +710,9 @@ class DiscordConnector:
if self.discover.text_overlay.popup_style:
self.text_altered = True
if self.text_altered:
self.discover.text_overlay.set_text_list(self.text, self.text_altered)
self.discover.text_overlay.set_text_list(
self.text, self.text_altered)
self.text_altered = False
# Update guilds
self.discover.settings.text_settings.set_guilds(self.guilds)
# Check for changed channel
if self.authed:
self.set_text_channel(self.discover.settings.text_settings.get_channel())
if len(self.rate_limited_channels) > 0:
guild = self.rate_limited_channels.pop()

View file

@ -19,8 +19,11 @@ import re
import traceback
import logging
import pkg_resources
import json
import gi
import pidfile
from configparser import ConfigParser
from .settings_window import MainSettingsWindow
from .voice_overlay import VoiceOverlayWindow
from .text_overlay import TextOverlayWindow
@ -29,7 +32,7 @@ from .discord_connector import DiscordConnector
gi.require_version("Gtk", "3.0")
# pylint: disable=wrong-import-position,wrong-import-order
from gi.repository import Gtk, GLib, Gio # nopep8
from gi.repository import Gtk, GLib, Gio, Gdk # nopep8
try:
from xdg.BaseDirectory import xdg_config_home
@ -45,7 +48,8 @@ _ = t.gettext
class Discover:
"""Main application class"""
def __init__(self, rpc_file, debug_file, args):
def __init__(self, rpc_file, config_file, debug_file, args):
self.mix_settings = False
self.ind = None
self.tray = None
self.steamos = False
@ -61,6 +65,7 @@ class Discover:
"GameScope session detected. Enabling steam and gamescope integration")
self.steamos = True
self.show_settings_delay = True
self.mix_settings = True
settings = Gtk.Settings.get_default()
if settings:
settings.set_property(
@ -68,17 +73,24 @@ class Discover:
self.create_gui()
self.connection = DiscordConnector( self )
self.connection = DiscordConnector(self)
self.settings.text_settings.add_connector(self.connection)
self.connection.connect()
GLib.timeout_add((1000 / 60), self.connection.do_read)
GLib.timeout_add((1000 / 20), self.periodic_run)
self.rpc_file = rpc_file
self.config_file = config_file
rpc_file = Gio.File.new_for_path(rpc_file)
monitor = rpc_file.monitor_file(0, None)
monitor.connect("changed", self.rpc_changed)
config_file = Gio.File.new_for_path(config_file)
monitor_config = config_file.monitor_file(0, None)
monitor_config.connect("changed", self.config_changed)
self.config_changed()
Gtk.main()
def periodic_run(self, data=None):
@ -117,7 +129,7 @@ class Discover:
print(" --hide ", _("Hide overlay"))
print(" --show ", _("Show overlay"))
print(" --rpc ",
_("Send command, not start new instance. Only needed if running in flatpak"))
_("Send command, not start new instance."))
print(" --mute ", _("Set own user to mute"))
print(" --unmute ", _("Set unmuted"))
print(" --deaf ", _("Set own user to deafened"))
@ -128,11 +140,6 @@ class Discover:
print(_("For gamescope compatibility ensure ENV has 'GDK_BACKEND=x11'"))
if normal_close:
sys.exit(0)
if "--configure" in data or "-c" in data:
if self.settings:
self.show_settings()
else:
self.show_settings_delay = True
if "--close" in data or "-x" in data:
sys.exit(0)
if "--steamos" in data or "-s" in data:
@ -175,7 +182,230 @@ class Discover:
with open(self.rpc_file, "r") as tfile:
data = tfile.readlines()
if len(data) >= 1:
self.do_args(data[0].split(" "), False)
self.do_args(data[0].strip().split(" "), False)
def config_changed(self, _a=None, _b=None, _c=None, _d=None):
"""
Called when the config file has been altered
"""
# Read new config
config = ConfigParser(interpolation=None)
config.read(self.config_file)
# Set Voice overlay options
self.voice_overlay.set_align_x(config.getboolean(
"main", "rightalign", fallback=False))
self.voice_overlay.set_align_y(
config.getint("main", "topalign", fallback=1))
self.voice_overlay.set_bg(json.loads(config.get(
"main", "bg_col", fallback="[0.0,0.0,0.0,0.5]")))
self.voice_overlay.set_fg(json.loads(config.get(
"main", "fg_col", fallback="[1.0,1.0,1.0,1.0]")))
self.voice_overlay.set_fg_hi(json.loads(config.get(
"main", "fg_hi_col", fallback="[1.0,1.0,1.0,1.0]")))
self.voice_overlay.set_tk(json.loads(config.get(
"main", "tk_col", fallback="[0.0,0.7,0.0,1.0]")))
self.voice_overlay.set_mt(json.loads(config.get(
"main", "mt_col", fallback="[0.6,0.0,0.0,1.0]")))
self.voice_overlay.set_mute_bg(json.loads(config.get(
"main", "mt_bg_col", fallback="[0.0,0.0,0.0,0.5]")))
self.voice_overlay.set_hi(json.loads(config.get(
"main", "hi_col", fallback="[0.0,0.0,0.0,0.5]")))
self.voice_overlay.set_bo(json.loads(config.get(
"main", "bo_col", fallback="[0.0,0.0,0.0,0.0]")))
self.voice_overlay.set_avatar_bg_col(json.loads(config.get(
"main", "avatar_bg_col", fallback="[0.0,0.0,0.0,0.0]")))
self.voice_overlay.set_avatar_size(
config.getint("main", "avatar_size", fallback=48))
self.voice_overlay.set_icon_spacing(
config.getint("main", "icon_spacing", fallback=8))
self.voice_overlay.set_text_padding(
config.getint("main", "text_padding", fallback=6))
self.voice_overlay.set_text_baseline_adj(config.getint(
"main", "text_baseline_adj", fallback=0))
font = config.get("main", "font", fallback=None)
title_font = config.get("main", "title_font", fallback=None)
self.voice_overlay.set_square_avatar(config.getboolean(
"main", "square_avatar", fallback=True))
self.voice_overlay.set_only_speaking(config.getboolean(
"main", "only_speaking", fallback=False))
self.voice_overlay.set_highlight_self(config.getboolean(
"main", "highlight_self", fallback=False))
self.voice_overlay.set_icon_only(config.getboolean(
"main", "icon_only", fallback=False))
monitor = config.get("main", "monitor", fallback="None")
self.voice_overlay.set_vert_edge_padding(config.getint(
"main", "vert_edge_padding", fallback=0))
self.voice_overlay.set_horz_edge_padding(config.getint(
"main", "horz_edge_padding", fallback=0))
floating = config.getboolean("main", "floating", fallback=False)
floating_x = config.getint("main", "floating_x", fallback=0)
floating_y = config.getint("main", "floating_y", fallback=0)
floating_w = config.getint("main", "floating_w", fallback=400)
floating_h = config.getint("main", "floating_h", fallback=400)
self.voice_overlay.set_order(
config.getint("main", "order", fallback=0))
self.voice_overlay.set_hide_on_mouseover(
config.getboolean("text", "autohide", fallback=False))
self.voice_overlay.set_horizontal(config.getboolean(
"main", "horizontal", fallback=False))
self.voice_overlay.set_guild_ids(self.parse_guild_ids(
config.get("main", "guild_ids", fallback="")))
self.voice_overlay.set_overflow(
config.getint("main", "overflow", fallback=0))
self.voice_overlay.set_show_connection(config.getboolean(
"main", "show_connection", fallback=False))
self.voice_overlay.set_show_title(config.getboolean(
"main", "show_title", fallback=False))
self.voice_overlay.set_show_disconnected(config.getboolean(
"main", "show_disconnected", fallback=False))
self.voice_overlay.set_border_width(
config.getint("main", "border_width", fallback=2))
self.voice_overlay.set_icon_transparency(config.getfloat(
"main", "icon_transparency", fallback=1.0))
self.voice_overlay.set_fancy_border(config.getboolean("main",
"fancy_border", fallback=True))
self.voice_overlay.set_show_dummy(config.getboolean("main",
"show_dummy", fallback=False))
self.voice_overlay.set_dummy_count(config.getint("main",
"dummy_count", fallback=10))
self.voice_overlay.set_monitor(self.get_monitor_index(
monitor))
self.voice_overlay.set_enabled(True)
self.voice_overlay.set_floating(
floating, floating_x, floating_y, floating_w, floating_h)
if font:
self.voice_overlay.set_font(font)
if title_font:
self.voice_overlay.set_title_font(title_font)
# Set Text overlay options
self.text_overlay.set_enabled(config.getboolean(
"text", "enabled", fallback=False))
self.text_overlay.set_align_x(config.getboolean(
"text", "rightalign", fallback=True))
self.text_overlay.set_align_y(
config.getint("text", "topalign", fallback=2))
monitor = config.get("text", "monitor", fallback="None")
self.floating = config.getboolean("text", "floating", fallback=True)
self.floating_x = config.getint("text", "floating_x", fallback=0)
self.floating_y = config.getint("text", "floating_y", fallback=0)
self.floating_w = config.getint("text", "floating_w", fallback=400)
self.floating_h = config.getint("text", "floating_h", fallback=400)
self.channel = config.get("text", "channel", fallback="0")
self.guild = config.get("text", "guild", fallback="0")
self.font = config.get("text", "font", fallback=None)
self.text_overlay.set_bg(json.loads(config.get(
"text", "bg_col", fallback="[0.0,0.0,0.0,0.5]")))
self.text_overlay.set_fg(json.loads(config.get(
"text", "fg_col", fallback="[1.0,1.0,1.0,1.0]")))
self.text_overlay.set_popup_style(config.getboolean(
"text", "popup_style", fallback=False))
self.text_overlay.set_text_time(
config.getint("text", "text_time", fallback=30))
self.text_overlay.set_show_attach(config.getboolean(
"text", "show_attach", fallback=True))
self.text_overlay.set_line_limit(
config.getint("text", "line_limit", fallback=20))
self.text_overlay.set_hide_on_mouseover(
config.getboolean("text", "autohide", fallback=False))
self.text_overlay.set_monitor(self.get_monitor_index(
monitor))
self.text_overlay.set_floating(
floating, floating_x, floating_y, floating_w, floating_h)
if self.font:
self.text_overlay.set_font(self.font)
# Set Notification overlay options
self.notification_overlay.set_enabled(config.getboolean(
"notification", "enabled", fallback=False))
self.notification_overlay.set_align_x(config.getboolean(
"notification", "rightalign", fallback=True))
self.notification_overlay.set_align_y(
config.getint("notification", "topalign", fallback=2))
monitor = config.get("notification", "monitor", fallback="None")
floating = config.getboolean(
"notification", "floating", fallback=False)
floating_x = config.getint(
"notification", "floating_x", fallback=0)
floating_y = config.getint(
"notification", "floating_y", fallback=0)
floating_w = config.getint(
"notification", "floating_w", fallback=400)
floating_h = config.getint(
"notification", "floating_h", fallback=400)
font = config.get("notification", "font", fallback=None)
self.notification_overlay.set_bg(json.loads(config.get(
"notification", "bg_col", fallback="[0.0,0.0,0.0,0.5]")))
self.notification_overlay.set_fg(json.loads(config.get(
"notification", "fg_col", fallback="[1.0,1.0,1.0,1.0]")))
self.notification_overlay.set_text_time(config.getint(
"notification", "text_time", fallback=10))
self.notification_overlay.set_show_icon(config.getboolean(
"notification", "show_icon", fallback=True))
self.notification_overlay.set_reverse_order(config.getboolean(
"notification", "rev", fallback=False))
self.notification_overlay.set_limit_width(config.getint(
"notification", "limit_width", fallback=400))
self.notification_overlay.set_icon_left(config.getboolean(
"notification", "icon_left", fallback=True))
self.notification_overlay.set_icon_pad(config.getint(
"notification", "icon_padding", fallback=8))
self.notification_overlay.set_icon_size(config.getint(
"notification", "icon_size", fallback=32))
self.notification_overlay.set_padding(config.getint(
"notification", "padding", fallback=8))
self.notification_overlay.set_border_radius(config.getint(
"notification", "border_radius", fallback=8))
self.notification_overlay.set_monitor(self.get_monitor_index(
monitor))
self.notification_overlay.set_floating(
floating, floating_x, floating_y, floating_w, floating_h)
if self.font:
self.notification_overlay.set_font(self.font)
# Set Core settings
self.set_force_xshape(
config.getboolean("general", "xshape", fallback=False))
def get_monitor_index(self, name):
"""
Helper function to find the index number of the monitor
"""
display = Gdk.Display.get_default()
if "get_n_monitors" in dir(display):
for i in range(0, display.get_n_monitors()):
if display.get_monitor(i).get_model() == name:
return i
return 0
def get_monitor_obj(self, name):
"""
Helper function to find the monitor object of the monitor
"""
display = Gdk.Display.get_default()
if "get_n_monitors" in dir(display):
for i in range(0, display.get_n_monitors()):
if display.get_monitor(i).get_model() == name:
return display.get_monitor(i)
return None
def parse_guild_ids(self, guild_ids_str):
"""Parse the guild_ids from a str and return them in a list"""
guild_ids = []
for guild_id in guild_ids_str.split(","):
guild_id = guild_id.strip()
if guild_id != "":
guild_ids.append(guild_id)
return guild_ids
def create_gui(self):
"""
@ -190,62 +420,9 @@ class Discover:
else:
self.text_overlay = TextOverlayWindow(self)
self.notification_overlay = NotificationOverlayWindow(self)
self.menu = self.make_menu()
self.make_sys_tray_icon(self.menu)
self.settings = MainSettingsWindow(self)
if self.steamos:
# Larger fonts needed
css = Gtk.CssProvider.new()
css.load_from_data(bytes("* { font-size:20px; }", "utf-8"))
self.settings.get_style_context().add_provider(
css, Gtk.STYLE_PROVIDER_PRIORITY_USER)
def make_sys_tray_icon(self, menu):
"""
Attempt to create an AppIndicator icon, failing that attempt to make
a systemtray icon
"""
if self.steamos:
return
try:
gi.require_version('AppIndicator3', '0.1')
# pylint: disable=import-outside-toplevel
from gi.repository import AppIndicator3
self.ind = AppIndicator3.Indicator.new(
"discover_overlay",
"discover-overlay-tray",
AppIndicator3.IndicatorCategory.APPLICATION_STATUS)
# Hide for now since we don't know if it should be shown yet
self.ind.set_status(AppIndicator3.IndicatorStatus.PASSIVE)
self.ind.set_menu(menu)
except (ImportError, ValueError) as exception:
# Create System Tray
log.info("Falling back to Systray : %s", exception)
self.tray = Gtk.StatusIcon.new_from_icon_name(
"discover-overlay-tray")
self.tray.connect('popup-menu', self.show_menu)
# Hide for now since we don't know if it should be shown yet
self.tray.set_visible(False)
def make_menu(self):
"""
Create System Menu
"""
menu = Gtk.Menu()
settings_opt = Gtk.MenuItem.new_with_label(_("Settings"))
show_opt = Gtk.MenuItem.new_with_label(_("Toggle Hidden"))
close_opt = Gtk.MenuItem.new_with_label(_("Close"))
menu.append(settings_opt)
menu.append(show_opt)
menu.append(close_opt)
settings_opt.connect("activate", self.show_settings)
show_opt.connect("activate", self.toggle_show)
close_opt.connect("activate", self.close)
menu.show_all()
return menu
if self.mix_settings:
MainSettingsWindow(self.config_file)
def show_menu(self, obj, button, time):
"""
@ -264,18 +441,6 @@ class Discover:
if self.notification_overlay:
self.notification_overlay.set_hidden(hide)
def show_settings(self, _obj=None, _data=None):
"""
Show settings window
"""
self.settings.present_settings()
def hide_settings(self, _obj=None, _data=None):
"""
Hide settings window
"""
self.settings.close_window()
def close(self, _a=None, _b=None, _c=None):
"""
End of the program
@ -300,18 +465,6 @@ class Discover:
if self.notification_overlay:
self.notification_overlay.set_task(visible)
def set_sys_tray_icon_visible(self, visible):
"""
Sets whether the tray icon is visible
"""
if self.ind is not None:
# pylint: disable=import-outside-toplevel
from gi.repository import AppIndicator3
self.ind.set_status(
AppIndicator3.IndicatorStatus.ACTIVE if visible else AppIndicator3.IndicatorStatus.PASSIVE)
elif self.tray is not None:
self.tray.set_visible(visible)
def entrypoint():
"""
@ -332,6 +485,7 @@ def entrypoint():
pid_file = os.path.join(config_dir, "discover_overlay.pid")
rpc_file = os.path.join(config_dir, "discover_overlay.rpc")
config_file = os.path.join(config_dir, "config.ini")
debug_file = os.path.join(config_dir, "output.txt")
logging.getLogger().setLevel(logging.INFO)
FORMAT = "%(levelname)s - %(name)s - %(message)s"
@ -343,31 +497,21 @@ def entrypoint():
log = logging.getLogger(__name__)
log.info("Starting Discover Overlay: %s",
pkg_resources.get_distribution('discover_overlay').version)
# Flatpak compat mode
try:
if "container" in os.environ and os.environ["container"] == "flatpak":
if "--rpc" in sys.argv:
with open(rpc_file, "w") as tfile:
tfile.write(line)
log.warning("Sent RPC command")
else:
log.info("Flatpak compat mode started")
if "-c" in sys.argv or "--configure" in sys.argv:
settings = MainSettingsWindow(config_file)
Gtk.main()
sys.exit(0)
with open(rpc_file, "w") as tfile:
tfile.write("--close")
Discover(rpc_file, debug_file, sys.argv[1:])
Discover(rpc_file, config_file, debug_file, sys.argv[1:])
return
# Normal usage
try:
with pidfile.PIDFile(pid_file):
Discover(rpc_file, debug_file, sys.argv[1:])
except pidfile.AlreadyRunningError:
log.warning("Discover overlay is currently running")
with open(rpc_file, "w") as tfile:
tfile.write(line)
log.warning("Sent RPC command")
except Exception as ex:
log.error(ex)
log.error(traceback.format_exc())

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -266,14 +266,16 @@ class OverlayWindow(Gtk.Window):
self.hidden = hidden
self.set_enabled(self.enabled)
def set_monitor(self, idx=None, mon=None):
def set_monitor(self, idx=None):
"""
Set the monitor this overlay should display on.
"""
self.monitor = idx
if self.is_wayland:
if mon:
GtkLayerShell.set_monitor(self, mon)
display = Gdk.Display.get_default()
if "get_monitor" in dir(display):
monitor = display.get_monitor(self.monitor)
GtkLayerShell.set_monitor(self, monitor)
self.set_untouchable()
self.force_location()
self.needsredraw = True

View file

@ -13,92 +13,388 @@
"""Settings window holding all settings tab"""
import gettext
import gi
import logging
import pkg_resources
from .voice_settings import VoiceSettingsWindow
from .text_settings import TextSettingsWindow
from .general_settings import GeneralSettingsWindow
from .about_settings import AboutSettingsWindow
from .notification_settings import NotificationSettingsWindow
import sys
import os
import json
from configparser import ConfigParser
gi.require_version("Gtk", "3.0")
# pylint: disable=wrong-import-position,wrong-import-order
from gi.repository import Gtk # nopep8
from gi.repository import Gtk, Gdk # nopep8
log = logging.getLogger(__name__)
t = gettext.translation(
'default', pkg_resources.resource_filename('discover_overlay', 'locales'), fallback=True)
_ = t.gettext
class MainSettingsWindow(Gtk.Window):
"""Settings window holding all settings tab"""
class MainSettingsWindow():
"""Settings class"""
def __init__(self, discover):
Gtk.Window.__init__(self)
def __init__(self, config_file):
self.connect("destroy", self.close_window)
self.connect("delete-event", self.close_window)
self.config_file = config_file
self.discover = discover
self.text_overlay = discover.text_overlay
self.voice_overlay = discover.voice_overlay
self.notification_overlay = discover.notification_overlay
self.set_title(_("Discover Overlay Configuration"))
self.set_icon_name("discover-overlay")
self.set_default_size(280, 180)
builder = Gtk.Builder.new_from_file(pkg_resources.resource_filename(
'discover_overlay', 'glade/settings.glade'))
window = builder.get_object("settings_window")
window.connect("destroy", self.close_window)
window.connect("delete-event", self.close_window)
# Create
notebook = Gtk.Notebook()
window.set_default_size(280, 180)
if discover.steamos:
notebook.set_tab_pos(Gtk.PositionType.LEFT)
self.set_default_size(1280, 800)
# Make an array of all named widgets
self.widget = {}
for widget in builder.get_objects():
if widget.find_property("name"):
name = widget.get_property("name")
self.widget[name] = widget
self.about_settings = AboutSettingsWindow(self.discover)
about_label = Gtk.Label.new(_("Overview"))
notebook.append_page(self.about_settings)
notebook.set_tab_label(self.about_settings, about_label)
# Translate labels and buttons
if name.endswith("_label"):
widget.set_label(_(widget.get_label()))
if name.endswith("_button"):
widget.set_label(_(widget.get_label()))
self.voice_settings = VoiceSettingsWindow(self.voice_overlay, discover)
voice_label = Gtk.Label.new(_("Voice"))
notebook.append_page(self.voice_settings)
notebook.set_tab_label(self.voice_settings, voice_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" % (
_("Welcome to Discover Overlay"),
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."),
_("Please visit our discord"),
_(" for support. Or open an issue on our GitHub ")
))
self.text_settings = TextSettingsWindow(self.text_overlay, discover)
text_label = Gtk.Label.new(_("Text"))
notebook.append_page(self.text_settings)
notebook.set_tab_label(self.text_settings, text_label)
if "GAMESCOPE_WAYLAND_DISPLAY" in os.environ:
log.info(
"GameScope session detected. Enabling steam and gamescope integration")
self.steamos = True
settings = Gtk.Settings.get_default()
if settings:
settings.set_property(
"gtk-application-prefer-dark-theme", Gtk.true)
self.widget['notebook'].set_tab_pos(Gtk.PositionType.LEFT)
# TODO Not assume the display size. Probably poll it from GDK Display?
window.set_default_size(1280, 800)
self.notification_settings = NotificationSettingsWindow(
self.notification_overlay, discover)
notification_label = Gtk.Label.new(_("Notifications"))
notebook.append_page(self.notification_settings)
notebook.set_tab_label(self.notification_settings, notification_label)
# Larger fonts needed
css = Gtk.CssProvider.new()
css.load_from_data(bytes("* { font-size:20px; }", "utf-8"))
self.window.get_style_context().add_provider(
css, Gtk.STYLE_PROVIDER_PRIORITY_USER)
self.window = window
self.core_settings = GeneralSettingsWindow(self.discover)
core_label = Gtk.Label.new(_("Core"))
notebook.append_page(self.core_settings)
notebook.set_tab_label(self.core_settings, core_label)
self.add(notebook)
self.notebook = notebook
self.read_config()
window.show()
self.menu = self.make_menu()
self.make_sys_tray_icon(self.menu)
# builder.connect_signals(self)
def close_window(self, widget=None, event=None):
"""
Hide the settings window for use at a later date
"""
self.text_settings.close_window(widget, event)
self.voice_settings.close_window(widget, event)
self.core_settings.close_window(widget, event)
self.hide()
self.window.hide()
return True
def present_settings(self):
"""
Show the settings window
"""
self.about_settings.present_settings()
self.voice_settings.present_settings()
self.text_settings.present_settings()
self.notification_settings.present_settings()
self.core_settings.present_settings()
self.notebook.show()
self.show()
self.notebook.set_current_page(0)
# self.about_settings.present_settings()
# self.voice_settings.present_settings()
# self.text_settings.present_settings()
# self.notification_settings.present_settings()
# self.core_settings.present_settings()
# self.notebook.show()
# self.show()
self.widget['notebook'].set_current_page(0)
self.window.show()
def read_config(self):
# Read config and put into gui
config = ConfigParser(interpolation=None)
config.read(self.config_file)
# Read Voice section
self.voice_floating_x = config.getint("main", "floating_x", fallback=0)
self.voice_floating_y = config.getint("main", "floating_y", fallback=0)
self.voice_floating_w = config.getint(
"main", "floating_w", fallback=400)
self.voice_floating_h = config.getint(
"main", "floating_h", fallback=400)
if config.getboolean("main", "floating", fallback=False):
self.widget['voice_floating'].set_active(True)
else:
self.widget['voice_anchor_to_edge'].set_active(True)
self.widget['voice_align_1'].set_active(
config.getboolean("main", "rightalign", fallback=False))
self.widget['voice_align_2'].set_active(
config.getint("main", "topalign", fallback=1))
self.widget['voice_monitor'].set_active(self.get_monitor_index(
config.get("main", "monitor", fallback="None")))
font = config.get("main", "font", fallback=None)
if font:
self.widget['voice_font'].set_font(font)
title_font = config.get("main", "title_font", fallback=None)
if title_font:
self.widget['voice_title_font'].set_font(font)
self.widget['voice_icon_spacing'].set_value(
config.getint("main", "icon_spacing", fallback=8))
self.widget['voice_text_padding'].set_value(
config.getint("main", "text_padding", fallback=6))
self.widget['voice_text_vertical_offset'].set_value(
config.getint("main", "text_baseline_adj", fallback=0))
self.widget['voice_vertical_padding'].set_value(
config.getint("main", "vert_edge_padding", fallback=0))
self.widget['voice_horizontal_padding'].set_value(
config.getint("main", "horz_edge_padding", fallback=0))
self.widget['voice_display_horizontally'].set_active(
config.getboolean("main", "horizontal", fallback=False))
self.widget['voice_highlight_self'].set_active(
config.getboolean("main", "highlight_self", fallback=False))
self.widget['voice_display_speakers_only'].set_active(
config.getboolean("main", "only_speaking", fallback=False))
self.widget['voice_talking_foreground'].set_rgba(self.make_colour(config.get(
"main", "fg_hi_col", fallback="[1.0,1.0,1.0,1.0]")))
self.widget['voice_talking_background'].set_rgba(self.make_colour(config.get(
"main", "hi_col", fallback="[0.0,0.0,0.0,0.5]")))
self.widget['voice_talking_border'].set_rgba(self.make_colour(config.get(
"main", "tk_col", fallback="[0.0,0.7,0.0,1.0]")))
self.widget['voice_idle_foreground'].set_rgba(self.make_colour(config.get(
"main", "fg_col", fallback="[1.0,1.0,1.0,1.0]")))
self.widget['voice_idle_background'].set_rgba(self.make_colour(config.get(
"main", "bg_col", fallback="[0.0,0.0,0.0,0.5]")))
self.widget['voice_idle_border'].set_rgba(self.make_colour(config.get(
"main", "bo_col", fallback="[0.0,0.0,0.0,0.0]")))
self.widget['voice_mute_foreground'].set_rgba(self.make_colour(config.get(
"main", "mt_col", fallback="[0.6,0.0,0.0,1.0]")))
self.widget['voice_mute_background'].set_rgba(self.make_colour(config.get(
"main", "mt_bg_col", fallback="[0.0,0.0,0.0,0.5]")))
self.widget['voice_avatar_background'].set_rgba(self.make_colour(config.get(
"main", "avatar_bg_col", fallback="[0.0,0.0,0.0,0.0]")))
self.widget['voice_avatar_opacity'].set_value(config.getfloat(
"main", "icon_transparency", fallback=1.0))
self.widget['voice_avatar_size'].set_value(
config.getint("main", "avatar_size", fallback=48))
self.widget['voice_display_icon_only'].set_active(config.getboolean(
"main", "icon_only", fallback=False))
self.widget['voice_square_avatar'].set_active(config.getboolean(
"main", "square_avatar", fallback=True))
self.widget['voice_fancy_avatar_shapes'].set_active(config.getboolean("main",
"fancy_border", fallback=True))
self.widget['voice_order_avatars_by'].set_active(
config.getint("main", "order", fallback=0))
self.widget['voice_border_width'].set_value(
config.getint("main", "border_width", fallback=2))
self.widget['voice_overflow_style'].set_active(
config.getint("main", "overflow", fallback=0))
self.widget['voice_show_title'].set_active(config.getboolean(
"main", "show_title", fallback=False))
self.widget['voice_show_connection_status'].set_active(config.getboolean(
"main", "show_connection", fallback=False))
self.widget['voice_show_disconnected'].set_active(config.getboolean(
"main", "show_disconnected", fallback=False))
# Read Text section
self.widget['text_enable'].set_active(
config.getboolean("text", "enabled", fallback=False))
self.widget['text_popup_style'].set_active(
config.getboolean("text", "popup_style", fallback=False))
# TODO Find server & channel in lists. TODO Have lists
self.voice_guild = config.get("text", "guild", fallback="0")
self.widget['text_server'].set_active(0)
self.voice_channel = config.get("text", "channel", fallback="0")
self.widget['text_channel'].set_active(0)
font = config.get("text", "font", fallback=None)
if font:
self.widget['text_font'].set_font(font)
self.widget['text_colour'].set_rgba(self.make_colour(config.get(
"text", "fg_col", fallback="[1.0,1.0,1.0,1.0]")))
self.widget['text_background_colour'].set_rgba(self.make_colour(config.get(
"text", "bg_col", fallback="[0.0,0.0,0.0,0.5]")))
self.widget['text_monitor'].set_active(self.get_monitor_index(
config.get("text", "monitor", fallback="None")))
self.widget['text_show_attachments'].set_active(config.getboolean(
"text", "show_attach", fallback=True))
self.widget['text_line_limit'].set_value(
config.getint("text", "line_limit", fallback=20))
# Read Notification section
# Read Core section
def make_colour(self, col):
col = json.loads(col)
return Gdk.RGBA(col[0], col[1], col[2], col[3])
def parse_guild_ids(self, guild_ids_str):
"""Parse the guild_ids from a str and return them in a list"""
guild_ids = []
for guild_id in guild_ids_str.split(","):
guild_id = guild_id.strip()
if guild_id != "":
guild_ids.append(guild_id)
return guild_ids
def get_monitor_index(self, name):
"""
Helper function to find the index number of the monitor
"""
display = Gdk.Display.get_default()
if "get_n_monitors" in dir(display):
for i in range(0, display.get_n_monitors()):
if display.get_monitor(i).get_model() == name:
return i
return 0
def get_monitor_obj(self, name):
"""
Helper function to find the monitor object of the monitor
"""
display = Gdk.Display.get_default()
if "get_n_monitors" in dir(display):
for i in range(0, display.get_n_monitors()):
if display.get_monitor(i).get_model() == name:
return display.get_monitor(i)
return None
def make_sys_tray_icon(self, menu):
"""
Attempt to create an AppIndicator icon, failing that attempt to make
a systemtray icon
"""
try:
gi.require_version('AppIndicator3', '0.1')
# pylint: disable=import-outside-toplevel
from gi.repository import AppIndicator3
self.ind = AppIndicator3.Indicator.new(
"discover_overlay",
"discover-overlay-tray",
AppIndicator3.IndicatorCategory.APPLICATION_STATUS)
# Hide for now since we don't know if it should be shown yet
self.ind.set_status(AppIndicator3.IndicatorStatus.PASSIVE)
self.ind.set_menu(menu)
except (ImportError, ValueError) as exception:
# Create System Tray
log.info("Falling back to Systray : %s", exception)
self.tray = Gtk.StatusIcon.new_from_icon_name(
"discover-overlay-tray")
self.tray.connect('popup-menu', self.show_menu)
# Hide for now since we don't know if it should be shown yet
self.tray.set_visible(False)
def set_sys_tray_icon_visible(self, visible):
"""
Sets whether the tray icon is visible
"""
if self.ind is not None:
# pylint: disable=import-outside-toplevel
from gi.repository import AppIndicator3
self.ind.set_status(
AppIndicator3.IndicatorStatus.ACTIVE if visible else AppIndicator3.IndicatorStatus.PASSIVE)
elif self.tray is not None:
self.tray.set_visible(visible)
def make_menu(self):
"""
Create System Menu
"""
menu = Gtk.Menu()
settings_opt = Gtk.MenuItem.new_with_label(_("Settings"))
close_opt = Gtk.MenuItem.new_with_label(_("Close"))
menu.append(settings_opt)
menu.append(close_opt)
settings_opt.connect("activate", self.present_settings)
close_opt.connect("activate", self.close_window)
menu.show_all()
return menu
def voice_toggle_test_content(self, button):
self.voice_overlay.set_show_dummy(button.get_active())
self.show_dummy = button.get_active()
if self.show_dummy:
self.voice_overlay.set_enabled(True)
self.voice_overlay.set_hidden(False)
def overview_close(self, button):
log.info("Quit pressed")
sys.exit(0)
def voice_place_window(self, button):
pass
def text_place_window(self, button):
pass
def voice_floating_changed(self, button):
pass
def voice_monitor_changed(self, button):
pass
def text_server_refresh(self, button):
# TODO Implement refresh request via RPC
pass
def text_channel_refresh(self, button):
# TODO Implement refresh request via RPC
pass
def config_set(self, context, key, value):
config = ConfigParser(interpolation=None)
config.read(self.config_file)
config.set(context, key, value)
with open(self.config_file, 'w') as file:
config.write(file)
def voice_font_changed(self, button):
self.config_set("main", "font", button.get_font())

View file

@ -50,7 +50,7 @@ setup(
'Topic :: Communications :: Conferencing',
],
package_data={
'discover_overlay': ['locales/*/LC_MESSAGES/*.mo']
'discover_overlay': ['locales/*/LC_MESSAGES/*.mo', 'glade/*']
},
keywords='discord overlay voice linux',
license='GPLv3+',