This commit is contained in:
emdee 2022-10-08 02:46:23 +00:00
parent 9e037f13c0
commit be6eb0e2a9
18 changed files with 135 additions and 71 deletions

25
ToDo.md
View file

@ -16,24 +16,29 @@ The code is in there but it's not working.
I may have broken it trying to wire up the ability to I may have broken it trying to wire up the ability to
set the audio device from the command line. set the audio device from the command line.
## Group peer_id ## Groups
There has been a change of API on a field named group.peer_id 1. peer_id There has been a change of API on a field named
The code is broken in places because I have not seen the path ```group.peer_id``` The code is broken in places because I have not
to change from the old API ro the new one. seen the path to change from the old API ro the new one.
2. There is no way to delete a group in the UI
3. Distinguish between Frieds, Groups and Whispers in the UI.
## Plugin system ## Plugin system
Needs better documentation and checking. 1. Needs better documentation and checking.
There's something broken in the way some of them plug into Qt menus.
Should the plugins be in toxygen or a separate repo? 2. There's something broken in the way some of them plug into Qt menus.
3. Should the plugins be in toxygen or a separate repo?
## check toxygen_wrapper ## check toxygen_wrapper
I've broken out toxygen_wrapper to be standalone, 1. I've broken out toxygen_wrapper to be standalone,
https://git.plastiras.org/emdee/toxygen_wrapper https://git.plastiras.org/emdee/toxygen_wrapper but the tox.py
but the tox.py needs each call double checking. needs each call double checking.

View file

@ -38,7 +38,7 @@ def setup_logging(oArgs):
setattr(oArgs, 'log_oFd', oFd) setattr(oArgs, 'log_oFd', oFd)
aKw['stream'] = oFd aKw['stream'] = oFd
coloredlogs.install(**aKw) coloredlogs.install(**aKw)
else: else:
aKw = dict(level=oArgs.loglevel, aKw = dict(level=oArgs.loglevel,
format='%(name)s %(levelname)-4s %(message)s') format='%(name)s %(levelname)-4s %(message)s')
@ -162,6 +162,7 @@ class App:
LOG.info("Starting toxygen version " +version) LOG.info("Starting toxygen version " +version)
self._version = version self._version = version
self._tox = None
self._app = self._settings = self._profile_manager = None self._app = self._settings = self._profile_manager = None
self._plugin_loader = self._messenger = None self._plugin_loader = self._messenger = None
self._tox = self._ms = self._init = self._main_loop = self._av_loop = None self._tox = self._ms = self._init = self._main_loop = self._av_loop = None
@ -268,7 +269,7 @@ class App:
if hasattr(oArgs, 'log_oFd'): if hasattr(oArgs, 'log_oFd'):
oArgs.log_oFd.close() oArgs.log_oFd.close()
delattr(oArgs, 'log_oFd') delattr(oArgs, 'log_oFd')
# failsafe: segfaults on exit # failsafe: segfaults on exit
if hasattr(self, '_tox'): if hasattr(self, '_tox'):
if self._tox and hasattr(self._tox, 'kill'): if self._tox and hasattr(self._tox, 'kill'):
@ -777,6 +778,7 @@ class App:
retval = tox_factory(data=data, settings=settings_, retval = tox_factory(data=data, settings=settings_,
args=self._args, app=self) args=self._args, app=self)
LOG.debug("_create_tox succeeded") LOG.debug("_create_tox succeeded")
self._tox = retval
return retval return retval
def _force_exit(self, retval=0): def _force_exit(self, retval=0):
@ -925,7 +927,7 @@ class App:
shuffle(lElts) shuffle(lElts)
LOG.debug(f"_test_bootstrap #Elts={len(lElts)}") LOG.debug(f"_test_bootstrap #Elts={len(lElts)}")
LOG.trace(f"_test_bootstrap lElts={lElts[:8]}") LOG.trace(f"_test_bootstrap lElts={lElts[:8]}")
shuffle(env['lElts']) shuffle(env['lElts'])
for host,port,key in lElts[:8]: for host,port,key in lElts[:8]:
try: try:
assert len(key) == 64, key assert len(key) == 64, key

View file

@ -101,7 +101,7 @@ class AV(common.tox_save.ToxAvSave):
def accept_call(self, friend_number, audio_enabled, video_enabled): def accept_call(self, friend_number, audio_enabled, video_enabled):
# obsolete # obsolete
return call_accept_call(self, friend_number, audio_enabled, video_enabled) return call_accept_call(self, friend_number, audio_enabled, video_enabled)
def call_accept_call(self, friend_number, audio_enabled, video_enabled): def call_accept_call(self, friend_number, audio_enabled, video_enabled):
LOG.debug(f"call_accept_call from {friend_number} {self._running}" + LOG.debug(f"call_accept_call from {friend_number} {self._running}" +
f"{audio_enabled} {video_enabled}") f"{audio_enabled} {video_enabled}")
@ -304,7 +304,7 @@ class AV(common.tox_save.ToxAvSave):
LOG.info("start_video_thread " \ LOG.info("start_video_thread " \
+f" device: {s['video']['device']}" \ +f" device: {s['video']['device']}" \
+f" supported: {s['video']['width']} {s['video']['height']}") +f" supported: {s['video']['width']} {s['video']['height']}")
self._video_running = True self._video_running = True
self._video_thread = BaseThread(target=self.send_video, self._video_thread = BaseThread(target=self.send_video,
name='_video_thread') name='_video_thread')

View file

@ -114,7 +114,7 @@ class CallsManager:
util_ui.tr('ERROR Accepting call from {friend_number}')) util_ui.tr('ERROR Accepting call from {friend_number}'))
else: else:
self._main_screen.active_call() self._main_screen.active_call()
finally: finally:
# does not terminate call - just the av_widget # does not terminate call - just the av_widget
if friend_number in self._incoming_calls: if friend_number in self._incoming_calls:
@ -127,7 +127,7 @@ class CallsManager:
pass pass
LOG.debug(f" closed self._call_widgets[{friend_number}]") LOG.debug(f" closed self._call_widgets[{friend_number}]")
def stop_call(self, friend_number, by_friend): def stop_call(self, friend_number, by_friend):
""" """
Stop call with friend Stop call with friend

View file

@ -44,7 +44,7 @@ class ContactsManager(ToxSave):
try: try:
self._ms._log(s) self._ms._log(s)
except: pass except: pass
def get_contact(self, num): def get_contact(self, num):
if num < 0 or num >= len(self._contacts): if num < 0 or num >= len(self._contacts):
return None return None
@ -254,10 +254,14 @@ class ContactsManager(ToxSave):
group = self.get_group_by_number(group_number) group = self.get_group_by_number(group_number)
peer = group.get_peer_by_id(peer_id) peer = group.get_peer_by_id(peer_id)
if peer: # broken if peer: # broken
if not self.check_if_contact_exists(peer.public_key): if hasattr(peer, 'public_key'):
self.add_group_peer(group, peer) LOG.error(f'no peer public_key ' + repr(dir(peer)))
else:
return self.get_contact_by_tox_id(peer.public_key) if not self.check_if_contact_exists(peer.public_key):
self.add_group_peer(group, peer)
return self.get_contact_by_tox_id(peer.public_key)
else:
LOG.warn(f'no peer group_number={group_number}')
def check_if_contact_exists(self, tox_id): def check_if_contact_exists(self, tox_id):
return any(filter(lambda c: c.tox_id == tox_id, self._contacts)) return any(filter(lambda c: c.tox_id == tox_id, self._contacts))
@ -455,7 +459,7 @@ class ContactsManager(ToxSave):
title = 'Friend failed' title = 'Friend failed'
text = 'Friend failed sending friend request' text = 'Friend failed sending friend request'
retval = text retval = text
except Exception as ex: # wrong data except Exception as ex: # wrong data
title = 'Friend add exception' title = 'Friend add exception'
text = 'Friend request exception with ' + str(ex) text = 'Friend request exception with ' + str(ex)
@ -466,7 +470,7 @@ class ContactsManager(ToxSave):
text = util_ui.tr(text) text = util_ui.tr(text)
util_ui.message_box(text, title) util_ui.message_box(text, title)
return retval return retval
def process_friend_request(self, tox_id, message): def process_friend_request(self, tox_id, message):
""" """
Accept or ignore friend request Accept or ignore friend request

View file

@ -86,7 +86,7 @@ class GroupChat(contact.Contact, ToxSave):
if peer_id > self._peers_limit: if peer_id > self._peers_limit:
LOG_WARN(f"add_peer id={peer_id} > {self._peers_limit}") LOG_WARN(f"add_peer id={peer_id} > {self._peers_limit}")
return return
peer = GroupChatPeer(peer_id, peer = GroupChatPeer(peer_id,
self._tox.group_peer_get_name(self._number, peer_id), self._tox.group_peer_get_name(self._number, peer_id),
self._tox.group_peer_get_status(self._number, peer_id), self._tox.group_peer_get_status(self._number, peer_id),

View file

@ -7,6 +7,9 @@ from groups.group_invite import GroupInvite
import wrapper.toxcore_enums_and_consts as constants import wrapper.toxcore_enums_and_consts as constants
from wrapper.toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
global LOG
import logging
LOG = logging.getLogger('app.'+'gs')
class GroupsService(tox_save.ToxSave): class GroupsService(tox_save.ToxSave):
@ -19,6 +22,8 @@ class GroupsService(tox_save.ToxSave):
self._widgets_factory_provider = widgets_factory_provider self._widgets_factory_provider = widgets_factory_provider
self._group_invites = [] self._group_invites = []
self._screen = None self._screen = None
# maybe just use self
self._tox = tox
def set_tox(self, tox): def set_tox(self, tox):
super().set_tox(tox) super().set_tox(tox)
@ -30,7 +35,11 @@ class GroupsService(tox_save.ToxSave):
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def create_new_gc(self, name, privacy_state, nick, status): def create_new_gc(self, name, privacy_state, nick, status):
group_number = self._tox.group_new(privacy_state, name, nick, status) try:
group_number = self._tox.group_new(privacy_state, name, nick, status)
except Exception as e:
LOG.error(f"create_new_gc {e}")
return
if group_number == -1: if group_number == -1:
return return
@ -48,8 +57,9 @@ class GroupsService(tox_save.ToxSave):
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def leave_group(self, group_number): def leave_group(self, group_number):
self._tox.group_leave(group_number) if type(group_number) == int:
self._contacts_manager.delete_group(group_number) self._tox.group_leave(group_number)
self._contacts_manager.delete_group(group_number)
def disconnect_from_group(self, group_number): def disconnect_from_group(self, group_number):
self._tox.group_disconnect(group_number) self._tox.group_disconnect(group_number)
@ -73,7 +83,7 @@ class GroupsService(tox_save.ToxSave):
e = f"Friend not connected friend_number={friend_number}" e = f"Friend not connected friend_number={friend_number}"
util_ui.message_box(title +'\n' +str(e), title) util_ui.message_box(title +'\n' +str(e), title)
return return
try: try:
self._tox.group_invite_friend(group_number, friend_number) self._tox.group_invite_friend(group_number, friend_number)
except Exception as e: except Exception as e:
@ -246,8 +256,14 @@ class GroupsService(tox_save.ToxSave):
self._group_invites.remove(invite) self._group_invites.remove(invite)
def _join_gc_via_invite(self, invite_data, friend_number, nick, status, password): def _join_gc_via_invite(self, invite_data, friend_number, nick, status, password):
group_number = self._tox.group_invite_accept(invite_data, friend_number, nick, status, password) if nick is None: nick = ''
self._add_new_group_by_number(group_number) if invite_data is None: invite_data = ''
try:
group_number = self._tox.group_invite_accept(invite_data, friend_number, nick, status, password)
except Exception as e:
LOG.error(f"_join_gc_via_invite {e}")
else:
self._add_new_group_by_number(group_number)
def _update_invites_button_state(self): def _update_invites_button_state(self):
self._main_screen.update_gc_invites_button_state() self._main_screen.update_gc_invites_button_state()

View file

@ -306,13 +306,13 @@ lKEEP_SETTINGS = ['uri',
'loglevel', 'loglevel',
'logfile', 'logfile',
'mode', 'mode',
# dunno # dunno
'audio_input', 'audio_input',
'audio_output', 'audio_output',
'audio', 'audio',
'video', 'video',
'ipv6_enabled', 'ipv6_enabled',
'udp_enabled', 'udp_enabled',
'local_discovery_enabled', 'local_discovery_enabled',
@ -378,15 +378,16 @@ def main(lArgs):
#setattr(aArgs, 'video', setup_video(oArgs)) #setattr(aArgs, 'video', setup_video(oArgs))
aArgs.video = setup_video(oArgs) aArgs.video = setup_video(oArgs)
assert 'video' in aArgs.__dict__ assert 'video' in aArgs.__dict__
#setattr(aArgs, 'audio', setup_audio(oArgs)) #setattr(aArgs, 'audio', setup_audio(oArgs))
aArgs.audio = setup_audio(oArgs) aArgs.audio = setup_audio(oArgs)
assert 'audio' in aArgs.__dict__ assert 'audio' in aArgs.__dict__
oArgs = aArgs oArgs = aArgs
toxygen = app.App(__version__, oArgs) toxygen = app.App(__version__, oArgs)
global oAPP global oAPP
oAPP = toxygen oAPP = toxygen
__builtins__['app'] = toxygen
i = toxygen.iMain() i = toxygen.iMain()
return i return i

View file

@ -167,7 +167,7 @@ def friend_status_message(contacts_manager, messenger):
friend = contacts_manager.get_friend_by_number(friend_number) friend = contacts_manager.get_friend_by_number(friend_number)
key = f"friend_number={friend_number}" key = f"friend_number={friend_number}"
if bTooSoon(key, sSlot, 10): return if bTooSoon(key, sSlot, 10): return
invoke_in_main_thread(friend.set_status_message, str(status_message, 'utf-8')) invoke_in_main_thread(friend.set_status_message, str(status_message, 'utf-8'))
LOG_DEBUG(f'User #{friend_number} has new status message') LOG_DEBUG(f'User #{friend_number} has new status message')
invoke_in_main_thread(messenger.send_messages, friend_number) invoke_in_main_thread(messenger.send_messages, friend_number)
@ -480,7 +480,7 @@ def group_private_message(window, tray, tox, messenger, settings, profile):
if settings['sound_notifications'] and bl and profile.status != TOX_USER_STATUS['BUSY']: if settings['sound_notifications'] and bl and profile.status != TOX_USER_STATUS['BUSY']:
sound_notification(SOUND_NOTIFICATION['MESSAGE']) sound_notification(SOUND_NOTIFICATION['MESSAGE'])
icon = util.join_path(util.get_images_directory(), 'icon_new_messages.png') icon = util.join_path(util.get_images_directory(), 'icon_new_messages.png')
if tray and hasattr(tray, 'setIcon'): if tray and hasattr(tray, 'setIcon'):
invoke_in_main_thread(tray.setIcon, QtGui.QIcon(icon)) invoke_in_main_thread(tray.setIcon, QtGui.QIcon(icon))
return wrapped return wrapped

View file

@ -119,11 +119,11 @@ class InitThread(BaseThread):
args=list(), args=list(),
kwargs=dict(lElts=None, oThread=self, iMax=2) kwargs=dict(lElts=None, oThread=self, iMax=2)
).start() ).start()
if self._is_first_start: if self._is_first_start:
LOG_INFO('starting plugins') LOG_INFO('starting plugins')
self._plugin_loader.load() self._plugin_loader.load()
except Exception as e: except Exception as e:
LOG_DEBUG(f"InitThread run: ERROR {e}") LOG_DEBUG(f"InitThread run: ERROR {e}")
pass pass
@ -157,7 +157,7 @@ class ToxAVIterateThread(BaseQThread):
def __init__(self, toxav): def __init__(self, toxav):
super().__init__() super().__init__()
self._toxav = toxav self._toxav = toxav
def run(self): def run(self):
LOG_DEBUG('ToxAVIterateThread run: ') LOG_DEBUG('ToxAVIterateThread run: ')
while not self._stop_thread: while not self._stop_thread:

View file

@ -50,7 +50,7 @@ class GroupBansScreen(CenteredWidget):
def _retranslate_ui(self): def _retranslate_ui(self):
# self.setWindowTitle(util_ui.tr('Bans list for group "{}"').format(self._group.name)) # self.setWindowTitle(util_ui.tr('Bans list for group "{}"').format(self._group.name))
pass pass
def _refresh_bans_list(self): def _refresh_bans_list(self):
self.bansListWidget.clear() self.bansListWidget.clear()
can_cancel_ban = self._group.is_self_moderator_or_founder() can_cancel_ban = self._group.is_self_moderator_or_founder()

View file

@ -27,6 +27,7 @@ class GroupInvitesScreen(CenteredWidget):
self._groups_service = groups_service self._groups_service = groups_service
self._profile = profile self._profile = profile
self._contacts_provider = contacts_provider self._contacts_provider = contacts_provider
self._tox = self._groups_service._tox
uic.loadUi(util.get_views_path('group_invites_screen'), self) uic.loadUi(util.get_views_path('group_invites_screen'), self)
@ -68,6 +69,8 @@ class GroupInvitesScreen(CenteredWidget):
password = self.passwordLineEdit.text() password = self.passwordLineEdit.text()
status = self.statusComboBox.currentIndex() status = self.statusComboBox.currentIndex()
if not nick:
nick = self._tox.self_get_name()
selected_invites = self._get_selected_invites() selected_invites = self._get_selected_invites()
for invite in selected_invites: for invite in selected_invites:
self._groups_service.accept_group_invite(invite, nick, status, password) self._groups_service.accept_group_invite(invite, nick, status, password)
@ -90,7 +93,7 @@ class GroupInvitesScreen(CenteredWidget):
for index in range(items_count): for index in range(items_count):
list_item = self.invitesListWidget.item(index) list_item = self.invitesListWidget.item(index)
item_widget = self.invitesListWidget.itemWidget(list_item) item_widget = self.invitesListWidget.itemWidget(list_item)
if item_widget.is_selected(): if item_widget and item_widget.is_selected():
selected.append(all_invites[index]) selected.append(all_invites[index])
return selected return selected

View file

@ -3,7 +3,6 @@ from PyQt5 import uic
import utils.util as util import utils.util as util
import utils.ui as util_ui import utils.ui as util_ui
class GroupManagementScreen(CenteredWidget): class GroupManagementScreen(CenteredWidget):
def __init__(self, groups_service, group): def __init__(self, groups_service, group):
@ -21,6 +20,7 @@ class GroupManagementScreen(CenteredWidget):
self.privacyStateComboBox.setCurrentIndex(1 if self._group.is_private else 0) self.privacyStateComboBox.setCurrentIndex(1 if self._group.is_private else 0)
self.peersLimitSpinBox.setValue(self._group.peers_limit) self.peersLimitSpinBox.setValue(self._group.peers_limit)
self.deletePushButton.clicked.connect(self._delete)
self.savePushButton.clicked.connect(self._save) self.savePushButton.clicked.connect(self._save)
def _retranslate_ui(self): def _retranslate_ui(self):
@ -28,12 +28,21 @@ class GroupManagementScreen(CenteredWidget):
self.passwordLabel.setText(util_ui.tr('Password:')) self.passwordLabel.setText(util_ui.tr('Password:'))
self.peerLimitLabel.setText(util_ui.tr('Peer limit:')) self.peerLimitLabel.setText(util_ui.tr('Peer limit:'))
self.privacyStateLabel.setText(util_ui.tr('Privacy state:')) self.privacyStateLabel.setText(util_ui.tr('Privacy state:'))
self.deletePushButton.setText(util_ui.tr('Delete'))
self.savePushButton.setText(util_ui.tr('Save')) self.savePushButton.setText(util_ui.tr('Save'))
self.privacyStateComboBox.clear() self.privacyStateComboBox.clear()
self.privacyStateComboBox.addItem(util_ui.tr('Public')) self.privacyStateComboBox.addItem(util_ui.tr('Public'))
self.privacyStateComboBox.addItem(util_ui.tr('Private')) self.privacyStateComboBox.addItem(util_ui.tr('Private'))
def _delete(self):
self._groups_service.leave_group(self._group.number)
self.close()
def _disconnect(self):
self._groups_service.disconnect_from_group(self._group.number)
self.close()
def _save(self): def _save(self):
password = self.passwordLineEdit.text() password = self.passwordLineEdit.text()
privacy_state = self.privacyStateComboBox.currentIndex() privacy_state = self.privacyStateComboBox.currentIndex()

View file

@ -76,13 +76,16 @@ class MainWindow(QtWidgets.QMainWindow):
self._contacts_manager = None self._contacts_manager = None
self._tray = tray self._tray = tray
self._app = app self._app = app
self._tox = app._tox
self._widget_factory = None self._widget_factory = None
self._modal_window = None self._modal_window = None
self._plugins_loader = None self._plugins_loader = None
self.setAcceptDrops(True) self.setAcceptDrops(True)
self._saved = False self._saved = False
self._smiley_window = None self._smiley_window = None
self._profile = self._toxes = self._messenger = None self._profile = None
self._toxes = None
self._messenger = None
self._file_transfer_handler = self._history_loader = self._groups_service = self._calls_manager = None self._file_transfer_handler = self._history_loader = self._groups_service = self._calls_manager = None
self._should_show_group_peers_list = False self._should_show_group_peers_list = False
self.initUI() self.initUI()
@ -91,6 +94,7 @@ class MainWindow(QtWidgets.QMainWindow):
# take a rough guess of 2/3 the default width at the default font # take a rough guess of 2/3 the default width at the default font
iMAX = settings['width'] * 2/3 / settings['message_font_size'] iMAX = settings['width'] * 2/3 / settings['message_font_size']
self._me = LogDialog(self, app) self._me = LogDialog(self, app)
self._pe = None
def set_dependencies(self, widget_factory, tray, contacts_manager, messenger, profile, plugins_loader, def set_dependencies(self, widget_factory, tray, contacts_manager, messenger, profile, plugins_loader,
file_transfer_handler, history_loader, calls_manager, groups_service, toxes, app): file_transfer_handler, history_loader, calls_manager, groups_service, toxes, app):
@ -159,6 +163,8 @@ class MainWindow(QtWidgets.QMainWindow):
self.actionLog_console = QtWidgets.QAction(window) self.actionLog_console = QtWidgets.QAction(window)
self.actionLog_console.setObjectName("actionLog_console") self.actionLog_console.setObjectName("actionLog_console")
self.actionPython_console = QtWidgets.QAction(window)
self.actionPython_console.setObjectName("actionLog_console")
self.updateSettings = QtWidgets.QAction(window) self.updateSettings = QtWidgets.QAction(window)
self.actionSettings = QtWidgets.QAction(window) self.actionSettings = QtWidgets.QAction(window)
self.actionSettings.setObjectName("actionSettings") self.actionSettings.setObjectName("actionSettings")
@ -196,6 +202,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.menuPlugins.addAction(self.reloadPlugins) self.menuPlugins.addAction(self.reloadPlugins)
self.menuPlugins.addAction(self.reloadToxchat) self.menuPlugins.addAction(self.reloadToxchat)
self.menuPlugins.addAction(self.actionLog_console) self.menuPlugins.addAction(self.actionLog_console)
self.menuPlugins.addAction(self.actionPython_console)
self.menuAbout.addAction(self.actionAbout_program) self.menuAbout.addAction(self.actionAbout_program)
@ -211,6 +218,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.actionQuit_program.triggered.connect(self.quit_program) self.actionQuit_program.triggered.connect(self.quit_program)
self.actionAbout_program.triggered.connect(self.about_program) self.actionAbout_program.triggered.connect(self.about_program)
self.actionLog_console.triggered.connect(self.log_console) self.actionLog_console.triggered.connect(self.log_console)
self.actionPython_console.triggered.connect(self.python_console)
self.actionNetwork.triggered.connect(self.network_settings) self.actionNetwork.triggered.connect(self.network_settings)
self.actionAdd_friend.triggered.connect(self.add_contact_triggered) self.actionAdd_friend.triggered.connect(self.add_contact_triggered)
self.createGC.triggered.connect(self.create_gc) self.createGC.triggered.connect(self.create_gc)
@ -264,6 +272,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.actionNetwork.setText(util_ui.tr("Network")) self.actionNetwork.setText(util_ui.tr("Network"))
self.actionAbout_program.setText(util_ui.tr("About program")) self.actionAbout_program.setText(util_ui.tr("About program"))
self.actionLog_console.setText(util_ui.tr("Console Log")) self.actionLog_console.setText(util_ui.tr("Console Log"))
self.actionPython_console.setText(util_ui.tr("Python Console"))
self.actionTest_tox.setText(util_ui.tr("Bootstrap")) self.actionTest_tox.setText(util_ui.tr("Bootstrap"))
self.actionTest_socks.setText(util_ui.tr("Test program")) self.actionTest_socks.setText(util_ui.tr("Test program"))
self.actionQuit_program.setText(util_ui.tr("Quit program")) self.actionQuit_program.setText(util_ui.tr("Quit program"))
@ -554,6 +563,18 @@ class MainWindow(QtWidgets.QMainWindow):
def log_console(self): def log_console(self):
self._me.show() self._me.show()
def python_console(self):
try:
if not self._pe:
from pyqtconsole.console import PythonConsole
self._pe = PythonConsole(sFont="Courier New", bBold=True)
self._pe.show()
self._pe.eval_queued()
# self._pe.eval_in_thread()
except Exception as e:
LOG.debug(e)
self._me.show()
def about_program(self): def about_program(self):
# TODO: replace with window # TODO: replace with window
text = util_ui.tr('Toxygen is Tox client written in Python.\nVersion: ') text = util_ui.tr('Toxygen is Tox client written in Python.\nVersion: ')

View file

@ -43,7 +43,7 @@ class AddContact(CenteredWidget):
if self._bootstrap: if self._bootstrap:
return return
self._bootstrap = True self._bootstrap = True
def _add_friend(self): def _add_friend(self):
if self._adding: if self._adding:
return return
@ -497,7 +497,7 @@ class AudioSettings(CenteredWidget):
uic.loadUi(get_views_path('audio_settings_screen'), self) uic.loadUi(get_views_path('audio_settings_screen'), self)
self._update_ui() self._update_ui()
self.center() self.center()
def closeEvent(self, event): def closeEvent(self, event):
if 'audio' not in self._settings: if 'audio' not in self._settings:
ex = f"self._settings=id(self._settings) {self._settings!r}" ex = f"self._settings=id(self._settings) {self._settings!r}"
@ -618,7 +618,7 @@ class VideoSettings(CenteredWidget):
if 'device' not in self._settings['video']: if 'device' not in self._settings['video']:
LOG.warn(f"'device' not in self._settings['video']: {self._settings!r}") LOG.warn(f"'device' not in self._settings['video']: {self._settings!r}")
self._settings['video']['device'] = self._devices[-1] self._settings['video']['device'] = self._devices[-1]
iIndex = self._settings['video']['device'] iIndex = self._settings['video']['device']
try: try:
index = self._devices.index(iIndex) index = self._devices.index(iIndex)
@ -628,7 +628,7 @@ class VideoSettings(CenteredWidget):
se = f"Video devices index error: index={iIndex} {e}" se = f"Video devices index error: index={iIndex} {e}"
LOG.warn(se) LOG.warn(se)
# util_ui.message_box(se, util_ui.tr(f"ERROR: Video devices error")) # util_ui.message_box(se, util_ui.tr(f"ERROR: Video devices error"))
self._settings['video']['device'] = self._devices[-1] self._settings['video']['device'] = self._devices[-1]
self._retranslate_ui() self._retranslate_ui()

View file

@ -412,4 +412,4 @@ class Settings(dict):
if key in aArgs.__dict__ and info[key] != val: if key in aArgs.__dict__ and info[key] != val:
aRet[key] = val aRet[key] = val
return aRet return aRet

View file

@ -3,7 +3,7 @@ import os
import sys import sys
from ctypes import CDLL from ctypes import CDLL
# You need a libs directory beside this directory # You need a libs directory beside this directory
# and you need to link your libtoxcore.so and libtoxav.so # and you need to link your libtoxcore.so and libtoxav.so
# and libtoxencryptsave.so into ../libs/ # and libtoxencryptsave.so into ../libs/
# Link all 3 to libtoxcore.so if you have only libtoxcore.so # Link all 3 to libtoxcore.so if you have only libtoxcore.so
@ -13,7 +13,7 @@ try:
except ImportError: except ImportError:
sLIBS_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), sLIBS_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)),
'libs') 'libs')
class LibToxCore: class LibToxCore:
def __init__(self): def __init__(self):
@ -40,11 +40,11 @@ class LibToxCore:
class LibToxAV: class LibToxAV:
def __init__(self): def __init__(self):
platform = util.get_platform() platform = sys.platform
if platform == 'Windows': if platform == 'win32':
# on Windows av api is in libtox.dll # on Windows av api is in libtox.dll
self._libtoxav = CDLL(os.path.join(sLIBS_DIR, 'libtox.dll')) self._libtoxav = CDLL(os.path.join(sLIBS_DIR, 'libtox.dll'))
elif platform == 'Darwin': elif platform == 'darwin':
self._libtoxav = CDLL('libtoxcore.dylib') self._libtoxav = CDLL('libtoxcore.dylib')
else: else:
libFile = os.path.join(sLIBS_DIR, 'libtoxav.so') libFile = os.path.join(sLIBS_DIR, 'libtoxav.so')

View file

@ -172,7 +172,7 @@ class Tox:
LOG_ERROR(f"tox_kill {e!s}") LOG_ERROR(f"tox_kill {e!s}")
else: else:
LOG_DEBUG(f"tox_kill") LOG_DEBUG(f"tox_kill")
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Startup options # Startup options
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
@ -287,7 +287,7 @@ class Tox:
LOG_ERROR(f"libtoxcore.tox_bootstrap {e}") LOG_ERROR(f"libtoxcore.tox_bootstrap {e}")
# dunno # dunno
raise raise
tox_err_bootstrap = tox_err_bootstrap.value tox_err_bootstrap = tox_err_bootstrap.value
if tox_err_bootstrap == TOX_ERR_BOOTSTRAP['OK']: if tox_err_bootstrap == TOX_ERR_BOOTSTRAP['OK']:
return bool(result) return bool(result)
@ -776,7 +776,7 @@ class Tox:
if friend_list is None: if friend_list is None:
friend_list = create_string_buffer(sizeof(c_uint32) * friend_list_size) friend_list = create_string_buffer(sizeof(c_uint32) * friend_list_size)
friend_list = POINTER(c_uint32)(friend_list) friend_list = POINTER(c_uint32)(friend_list)
LOG_DEBUG(f"tox_self_get_friend_list") LOG_TRACE(f"tox_self_get_friend_list")
Tox.libtoxcore.tox_self_get_friend_list(self._tox_pointer, friend_list) Tox.libtoxcore.tox_self_get_friend_list(self._tox_pointer, friend_list)
return friend_list[0:friend_list_size] return friend_list[0:friend_list_size]
@ -1341,7 +1341,7 @@ class Tox:
POINTER(None)()) POINTER(None)())
self.file_recv_control_cb = None self.file_recv_control_cb = None
return return
LOG_DEBUG(f"tox_callback_file_recv_control") LOG_DEBUG(f"tox_callback_file_recv_control")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_int, c_void_p) c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_int, c_void_p)
self.file_recv_control_cb = c_callback(callback) self.file_recv_control_cb = c_callback(callback)
@ -1607,7 +1607,7 @@ class Tox:
POINTER(None)()) POINTER(None)())
self.file_recv_cb = None self.file_recv_cb = None
return return
LOG_DEBUG(f"tox_callback_file_recv") LOG_DEBUG(f"tox_callback_file_recv")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_uint32, c_uint64, c_char_p, c_size_t, c_void_p) c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_uint32, c_uint64, c_char_p, c_size_t, c_void_p)
self.file_recv_cb = c_callback(callback) self.file_recv_cb = c_callback(callback)
@ -1640,7 +1640,7 @@ class Tox:
POINTER(None)()) POINTER(None)())
self.file_recv_chunk_cb = None self.file_recv_chunk_cb = None
return return
LOG_DEBUG(f"tox_callback_file_recv_chunk") LOG_DEBUG(f"tox_callback_file_recv_chunk")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_uint64, POINTER(c_uint8), c_size_t, c_void_p) c_callback = CFUNCTYPE(None, c_void_p, c_uint32, c_uint32, c_uint64, POINTER(c_uint8), c_size_t, c_void_p)
self.file_recv_chunk_cb = c_callback(callback) self.file_recv_chunk_cb = c_callback(callback)
@ -1764,7 +1764,7 @@ class Tox:
self.friend_lossless_packet_cb = None self.friend_lossless_packet_cb = None
self.libtoxcore.tox_callback_friend_lossless_packet(self._tox_pointer, POINTER(None)()) self.libtoxcore.tox_callback_friend_lossless_packet(self._tox_pointer, POINTER(None)())
return return
LOG_DEBUG(f"callback_friend_lossless_packet") LOG_DEBUG(f"callback_friend_lossless_packet")
c_callback = CFUNCTYPE(None, c_void_p, c_uint32, POINTER(c_uint8), c_size_t, c_void_p) c_callback = CFUNCTYPE(None, c_void_p, c_uint32, POINTER(c_uint8), c_size_t, c_void_p)
self.friend_lossless_packet_cb = c_callback(callback) self.friend_lossless_packet_cb = c_callback(callback)
@ -2387,7 +2387,6 @@ class Tox:
error = c_int() error = c_int()
buff = create_string_buffer(TOX_GROUP_CHAT_ID_SIZE) buff = create_string_buffer(TOX_GROUP_CHAT_ID_SIZE)
LOG_DEBUG(f"tox_group_get_chat_id")
result = Tox.libtoxcore.tox_group_get_chat_id(self._tox_pointer, result = Tox.libtoxcore.tox_group_get_chat_id(self._tox_pointer,
group_number, group_number,
buff, byref(error)) buff, byref(error))
@ -2575,23 +2574,27 @@ class Tox:
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
def group_send_custom_packet(self, group_number, lossless, data): def group_send_custom_packet(self, group_number, lossless, data):
""" """Send a custom packet to the group.
Send a custom packet to the group.
If lossless is true the packet will be lossless. Lossless packet behaviour is comparable If lossless is true the packet will be lossless. Lossless
to TCP (reliability, arrive in order) but with packets instead of a stream. packet behaviour is comparable to TCP (reliability, arrive in
order) but with packets instead of a stream.
If lossless is false, the packet will be lossy. Lossy packets behave like UDP packets, If lossless is false, the packet will be lossy. Lossy packets
meaning they might never reach the other side or might arrive more than once (if someone behave like UDP packets, meaning they might never reach the
is messing with the connection) or might arrive in the wrong order. other side or might arrive more than once (if someone is
messing with the connection) or might arrive in the wrong
order.
Unless latency is an issue or message reliability is not important, it is recommended that you use Unless latency is an issue or message reliability is not
lossless custom packets. important, it is recommended that you use lossless custom
packets.
:param group_number: The group number of the group the message is intended for. :param group_number: The group number of the group the message is intended for.
:param lossless: True if the packet should be lossless. :param lossless: True if the packet should be lossless.
:param data A byte array containing the packet data. :param data A byte array containing the packet data.
:return True on success. :return True on success.
""" """
error = c_int() error = c_int()