diff --git a/Furious/Externals/GenTranslation.py b/Furious/Externals/GenTranslation.py index 27d56a9..a424634 100644 --- a/Furious/Externals/GenTranslation.py +++ b/Furious/Externals/GenTranslation.py @@ -35,6 +35,14 @@ TRANSLATION = { "ZH": "新的更改将于下次生效", "isReviewed": "True" }, + "Reconnect now?": { + "source": [ + "Furious.Qt.QtWidgets" + ], + "RU": "Переподключиться сейчас?", + "ZH": "现在重新连接?", + "isReviewed": "True" + }, "Unrecognized Configuration. Please modify it in the editor": { "source": [ "Furious.Qt.QtWidgets" @@ -1043,12 +1051,12 @@ TRANSLATION = { "ZH": "TUN模式已禁用(管理员)", "isReviewed": "True" }, - "TUN Mode Disabled (root)": { + "TUN Mode Disabled (Superuser)": { "source": [ "Furious.TrayActions.Settings" ], - "RU": "TUN режим отключен (root)", - "ZH": "TUN模式已禁用(root)", + "RU": "TUN режим отключен (Superuser)", + "ZH": "TUN模式已禁用(Superuser)", "isReviewed": "True" }, "Settings": { @@ -1701,5 +1709,37 @@ TRANSLATION = { "RU": "Автоматическая настройка буфера приема TCP", "ZH": "TCP接收缓冲区自动调优", "isReviewed": "True" + }, + "Restart The Application As Administrator": { + "source": [ + "Furious.Window.AppMainWindow" + ], + "RU": "Перезапустите приложение от имени администратора", + "ZH": "以管理员身份重新启动应用程序", + "isReviewed": "True" + }, + "Restart The Application As Superuser": { + "source": [ + "Furious.Window.AppMainWindow" + ], + "RU": "Перезапустите приложение от имени суперпользователя", + "ZH": "以Superuser身份重新启动应用程序", + "isReviewed": "True" + }, + "Administrator": { + "source": [ + "Furious.Widget.SystemTrayIcon" + ], + "RU": "Administrator", + "ZH": "管理员", + "isReviewed": "True" + }, + "I am, the supreme authority.": { + "source": [ + "Furious.Window.AppMainWindow" + ], + "RU": "Я — единственная высшая инстанция.", + "ZH": "我就是至高无上的存在。", + "isReviewed": "True" } } diff --git a/Furious/Frozenlib/AppCommands.py b/Furious/Frozenlib/AppCommands.py new file mode 100644 index 0000000..26618e2 --- /dev/null +++ b/Furious/Frozenlib/AppCommands.py @@ -0,0 +1,27 @@ +# Copyright (C) 2024–present Loren Eteval & contributors +# +# This file is part of Furious. +# +# 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 . + +from __future__ import annotations + +from enum import Enum + +__all__ = ['AppCommands'] + + +class AppCommands(Enum): + Empty = 'empty' + RunAs = 'runas' diff --git a/Furious/Frozenlib/AppResources.py b/Furious/Frozenlib/AppResources.py index e27f759..60e4e56 100644 --- a/Furious/Frozenlib/AppResources.py +++ b/Furious/Frozenlib/AppResources.py @@ -280,6 +280,70 @@ a.5.5 0 0 1-.478\ -.647L9.89 2.41 \ 4.157 8.5z\x22/>\x0d\x0a<\ /svg>\ +\x00\x00\x03\xd7\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 width=\x2216\ +\x22 height=\x2216\x22 fi\ +ll=\x22currentColor\ +\x22 class=\x22bi bi-p\ +erson-gear\x22 view\ +Box=\x220 0 16 16\x22>\ +\x0a \x0a\ +\ \x00\x00\x02\x12\ <\ svg xmlns=\x22http:\ @@ -850,6 +914,37 @@ zM3 4a1 1 0 0 1 \ -1 1H4a1 1 0 0 1\ -1-1V4z\x22/>\x0d\x0a\ +\x00\x00\x01\xcc\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 width=\x2216\ +\x22 height=\x2216\x22 fi\ +ll=\x22currentColor\ +\x22 class=\x22bi bi-f\ +older2\x22 viewBox=\ +\x220 0 16 16\x22>\x0a <\ +path d=\x22M1 3.5A1\ +.5 1.5 0 0 1 2.5\ + 2h2.764c.958 0 \ +1.76.56 2.311 1.\ +184C7.985 3.648 \ +8.48 4 9 4h4.5A1\ +.5 1.5 0 0 1 15 \ +5.5v7a1.5 1.5 0 \ +0 1-1.5 1.5h-11A\ +1.5 1.5 0 0 1 1 \ +12.5zM2.5 3a.5.5\ + 0 0 0-.5.5V6h12\ +v-.5a.5.5 0 0 0-\ +.5-.5H9c-.964 0-\ +1.71-.629-2.174-\ +1.154C6.374 3.33\ +4 5.82 3 5.264 3\ +zM14 7H2v5.5a.5.\ +5 0 0 0 .5.5h11a\ +.5.5 0 0 0 .5-.5\ +z\x22/>\x0a\ \x00\x00\x02U\ <\ svg xmlns=\x22http:\ @@ -1367,6 +1462,30 @@ A7.568 7.568 0 0\ 96 5.054-1.902Z\x22\ />\x0d\x0a \x0d\x0a\ +\x00\x00\x01]\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 width=\x2216\ +\x22 height=\x2216\x22 fi\ +ll=\x22currentColor\ +\x22 class=\x22bi bi-a\ +rrow-clockwise\x22 \ +viewBox=\x220 0 16 \ +16\x22>\x0a \x0a \x0a\ \x00\x00\x02<\ <\ svg xmlns=\x22http:\ @@ -1678,7 +1797,7 @@ m4.905-2.767-3.6\ .686-1.894a.503.\ 503 0 0 0-.461 0\ z\x22/>\x0d\x0a\ -\x00\x00\x03\xe1\ +\x00\x00\x03\xe3\ <\ svg xmlns=\x22http:\ //www.w3.org/200\ @@ -1687,62 +1806,62 @@ svg xmlns=\x22http:\ ll=\x22currentColor\ \x22 class=\x22bi bi-d\ iagram-3\x22 viewBo\ -x=\x220 0 16 16\x22>\x0a \ - \x0d\x0a\ + \x0a\ -\ + 0 .5.5zM0 11.5A\ +1.5 1.5 0 0 1 1.\ +5 10h1A1.5 1.5 0\ + 0 1 4 11.5v1A1.\ +5 1.5 0 0 1 2.5 \ +14h-1A1.5 1.5 0 \ +0 1 0 12.5zm1.5-\ +.5a.5.5 0 0 0-.5\ +.5v1a.5.5 0 0 0 \ +.5.5h1a.5.5 0 0 \ +0 .5-.5v-1a.5.5 \ +0 0 0-.5-.5zm4.5\ +.5A1.5 1.5 0 0 1\ + 7.5 10h1a1.5 1.\ +5 0 0 1 1.5 1.5v\ +1A1.5 1.5 0 0 1 \ +8.5 14h-1A1.5 1.\ +5 0 0 1 6 12.5zm\ +1.5-.5a.5.5 0 0 \ +0-.5.5v1a.5.5 0 \ +0 0 .5.5h1a.5.5 \ +0 0 0 .5-.5v-1a.\ +5.5 0 0 0-.5-.5z\ +m4.5.5a1.5 1.5 0\ + 0 1 1.5-1.5h1a1\ +.5 1.5 0 0 1 1.5\ + 1.5v1a1.5 1.5 0\ + 0 1-1.5 1.5h-1a\ +1.5 1.5 0 0 1-1.\ +5-1.5zm1.5-.5a.5\ +.5 0 0 0-.5.5v1a\ +.5.5 0 0 0 .5.5h\ +1a.5.5 0 0 0 .5-\ +.5v-1a.5.5 0 0 0\ +-.5-.5z\x22/>\x0d\x0a\ \x00\x00\x02E\ <\ svg xmlns=\x22http:\ @@ -2555,6 +2674,71 @@ l5.732-6.09H9a.5\ 47L9.89 2.41 4.1\ 57 8.5z\x22/>\x0d\x0a\ +\x00\x00\x03\xe4\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 width=\x2216\ +\x22 height=\x2216\x22 fi\ +ll=\x22currentColor\ +\x22 class=\x22bi bi-p\ +erson-gear\x22 view\ +Box=\x220 0 16 16\x22>\ +\x0a \x0a\ \x00\x00\x02,\ <\ svg xmlns=\x22http:\ @@ -3001,6 +3185,38 @@ h7a1 1 0 0 1 1 1\ v10a1 1 0 0 1-1 \ 1H4a1 1 0 0 1-1-\ 1V4z\x22/>\x0d\x0a\ +\x00\x00\x01\xd9\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 width=\x2216\ +\x22 height=\x2216\x22 fi\ +ll=\x22currentColor\ +\x22 class=\x22bi bi-f\ +older2\x22 viewBox=\ +\x220 0 16 16\x22>\x0a <\ +path fill=\x22white\ +\x22 d=\x22M1 3.5A1.5 \ +1.5 0 0 1 2.5 2h\ +2.764c.958 0 1.7\ +6.56 2.311 1.184\ +C7.985 3.648 8.4\ +8 4 9 4h4.5A1.5 \ +1.5 0 0 1 15 5.5\ +v7a1.5 1.5 0 0 1\ +-1.5 1.5h-11A1.5\ + 1.5 0 0 1 1 12.\ +5zM2.5 3a.5.5 0 \ +0 0-.5.5V6h12v-.\ +5a.5.5 0 0 0-.5-\ +.5H9c-.964 0-1.7\ +1-.629-2.174-1.1\ +54C6.374 3.334 5\ +.82 3 5.264 3zM1\ +4 7H2v5.5a.5.5 0\ + 0 0 .5.5h11a.5.\ +5 0 0 0 .5-.5z\x22/\ +>\x0a\ \x00\x00\x02\x96\ <\ svg xmlns=\x22http:\ @@ -3269,6 +3485,32 @@ white\x22 d=\x22M7.009\ .126 3.936-.896 \ 5.054-1.902Z\x22/>\x0d\ \x0a\ +\x00\x00\x01w\ +<\ +svg xmlns=\x22http:\ +//www.w3.org/200\ +0/svg\x22 width=\x2216\ +\x22 height=\x2216\x22 fi\ +ll=\x22currentColor\ +\x22 class=\x22bi bi-a\ +rrow-clockwise\x22 \ +viewBox=\x220 0 16 \ +16\x22>\x0a \x0a \x0a\ +\ \x00\x00\x02I\ <\ svg xmlns=\x22http:\ @@ -3455,7 +3697,7 @@ l.694 3.957-3.68\ 6-1.894a.503.503\ 0 0 0-.461 0z\x22/\ >\x0d\x0a\ -\x00\x00\x03\xee\ +\x00\x00\x03\xf0\ <\ svg xmlns=\x22http:\ //www.w3.org/200\ @@ -3464,62 +3706,62 @@ svg xmlns=\x22http:\ ll=\x22currentColor\ \x22 class=\x22bi bi-d\ iagram-3\x22 viewBo\ -x=\x220 0 16 16\x22>\x0a \ - \x0d\x0a\ + \x0a\ +.5.5zM0 11.5A1.5\ + 1.5 0 0 1 1.5 1\ +0h1A1.5 1.5 0 0 \ +1 4 11.5v1A1.5 1\ +.5 0 0 1 2.5 14h\ +-1A1.5 1.5 0 0 1\ + 0 12.5zm1.5-.5a\ +.5.5 0 0 0-.5.5v\ +1a.5.5 0 0 0 .5.\ +5h1a.5.5 0 0 0 .\ +5-.5v-1a.5.5 0 0\ + 0-.5-.5zm4.5.5A\ +1.5 1.5 0 0 1 7.\ +5 10h1a1.5 1.5 0\ + 0 1 1.5 1.5v1A1\ +.5 1.5 0 0 1 8.5\ + 14h-1A1.5 1.5 0\ + 0 1 6 12.5zm1.5\ +-.5a.5.5 0 0 0-.\ +5.5v1a.5.5 0 0 0\ + .5.5h1a.5.5 0 0\ + 0 .5-.5v-1a.5.5\ + 0 0 0-.5-.5zm4.\ +5.5a1.5 1.5 0 0 \ +1 1.5-1.5h1a1.5 \ +1.5 0 0 1 1.5 1.\ +5v1a1.5 1.5 0 0 \ +1-1.5 1.5h-1a1.5\ + 1.5 0 0 1-1.5-1\ +.5zm1.5-.5a.5.5 \ +0 0 0-.5.5v1a.5.\ +5 0 0 0 .5.5h1a.\ +5.5 0 0 0 .5-.5v\ +-1a.5.5 0 0 0-.5\ +-.5z\x22/>\x0d\x0a\ \x00\x00\x02_\ <\ svg xmlns=\x22http:\ @@ -3839,6 +4081,10 @@ qt_resource_name = b"\ \x00l\ \x00i\x00g\x00h\x00t\x00n\x00i\x00n\x00g\x00-\x00c\x00h\x00a\x00r\x00g\x00e\x00.\ \x00s\x00v\x00g\ +\x00\x0f\ +\x08\xc8\xa6G\ +\x00p\ +\x00e\x00r\x00s\x00o\x00n\x00-\x00g\x00e\x00a\x00r\x00.\x00s\x00v\x00g\ \x00\x1f\ \x08\x8eR\x07\ \x00l\ @@ -3879,6 +4125,10 @@ qt_resource_name = b"\ \x00f\ \x00i\x00l\x00e\x00s\x00.\x00s\x00v\x00g\ \x00\x0b\ +\x0c\x8f\x9f\x87\ +\x00f\ +\x00o\x00l\x00d\x00e\x00r\x002\x00.\x00s\x00v\x00g\ +\x00\x0b\ \x05X\xfd\x87\ \x00q\ \x00r\x00-\x00c\x00o\x00d\x00e\x00.\x00s\x00v\x00g\ @@ -3910,6 +4160,11 @@ qt_resource_name = b"\ \x00o\x00c\x00k\x00e\x00t\x00-\x00t\x00a\x00k\x00e\x00o\x00f\x00f\x00-\x00c\x00o\ \x00n\x00n\x00e\x00c\x00t\x00e\x00d\x00-\x00d\x00a\x00r\x00k\x00.\x00s\x00v\x00g\ \ +\x00\x13\ +\x06\x9a\xb4\xa7\ +\x00a\ +\x00r\x00r\x00o\x00w\x00-\x00c\x00l\x00o\x00c\x00k\x00w\x00i\x00s\x00e\x00.\x00s\ +\x00v\x00g\ \x00\x0b\ \x02^N'\ \x00d\ @@ -3996,149 +4251,161 @@ qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x10\x00\x02\x00\x00\x00'\x00\x00\x00\x03\ +\x00\x00\x00\x10\x00\x02\x00\x00\x00*\x00\x00\x00\x03\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x01\xcc\x00\x00\x00\x00\x00\x01\x00\x00'\xfb\ +\x00\x00\x01\xf0\x00\x00\x00\x00\x00\x01\x00\x00+\xd6\ \x00\x00\x01\x93\xdal,\x95\ -\x00\x00\x044\x00\x02\x00\x00\x00 \x00\x00\x00*\ +\x00\x00\x04\xa0\x00\x02\x00\x00\x00#\x00\x00\x00-\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x02\xe0\x00\x00\x00\x00\x00\x01\x00\x00C\xb4\ +\x00\x00\x03 \x00\x00\x00\x00\x00\x01\x00\x00I_\ \x00\x00\x01\x93\xdal,\x96\ -\x00\x00\x03 \x00\x00\x00\x00\x00\x01\x00\x00J\x09\ +\x00\x00\x03`\x00\x00\x00\x00\x00\x01\x00\x00O\xb4\ \x00\x00\x01\x93\xdal,\x97\ -\x00\x00\x03\xce\x00\x00\x00\x00\x00\x01\x00\x00V\x9b\ +\x00\x00\x04:\x00\x00\x00\x00\x00\x01\x00\x00]\xa7\ \x00\x00\x01\x93\xdal,\x98\ -\x00\x00\x03h\x00\x00\x00\x00\x00\x01\x00\x00R\x01\ +\x00\x00\x03\xd4\x00\x00\x00\x00\x00\x01\x00\x00Y\x0d\ \x00\x00\x01\x93\xdal,\x93\ -\x00\x00\x02$\x00\x00\x00\x00\x00\x01\x00\x001,\ +\x00\x00\x02H\x00\x00\x00\x00\x00\x01\x00\x005\x07\ \x00\x00\x01\x93\xdal,\x94\ -\x00\x00\x02\xba\x00\x00\x00\x00\x00\x01\x00\x00A7\ +\x00\x00\x02\xfa\x00\x00\x00\x00\x00\x01\x00\x00F\xe2\ \x00\x00\x01\x93\xdal,\x94\ \x00\x00\x00\x98\x00\x00\x00\x00\x00\x01\x00\x00\x0a\xea\ \x00\x00\x01\x93\xdal,\x96\ -\x00\x00\x02\x02\x00\x00\x00\x00\x00\x01\x00\x00/\x91\ +\x00\x00\x02&\x00\x00\x00\x00\x00\x01\x00\x003l\ \x00\x00\x01\x93\xdal,\x93\ -\x00\x00\x04\x8c\x00\x00\x00\x00\x00\x01\x00\x00j\xd3\ +\x00\x00\x04\xf8\x00\x00\x00\x00\x00\x01\x00\x00q\xe1\ \x00\x00\x01\x93\xdal,\x95\ -\x00\x00\x05b\x00\x00\x00\x00\x00\x01\x00\x00{\x89\ +\x00\x00\x05\xce\x00\x00\x00\x00\x00\x01\x00\x00\x82\x97\ \x00\x00\x01\x93\xdal,\x98\ -\x00\x00\x02X\x00\x00\x00\x00\x00\x01\x00\x005\x0c\ +\x00\x00\x02\x98\x00\x00\x00\x00\x00\x01\x00\x00:\xb7\ \x00\x00\x01\x93\xdal,\x98\ -\x00\x00\x02<\x00\x00\x00\x00\x00\x01\x00\x002\xb3\ +\x00\x00\x02|\x00\x00\x00\x00\x00\x01\x00\x008^\ \x00\x00\x01\x93\xdal,\x96\ -\x00\x00\x01\xae\x00\x00\x00\x00\x00\x01\x00\x00#:\ +\x00\x00\x01\xd2\x00\x00\x00\x00\x00\x01\x00\x00'\x15\ \x00\x00\x01\x93\xdal,\x93\ -\x00\x00\x01\x96\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x9a\ +\x00\x00\x01\xba\x00\x00\x00\x00\x00\x01\x00\x00#u\ \x00\x00\x01\x93\xdal,\x99\ -\x00\x00\x04d\x00\x00\x00\x00\x00\x01\x00\x00h\x8a\ +\x00\x00\x03\xa8\x00\x00\x00\x00\x00\x01\x00\x00W\xac\ +\x00\x00\x01\x9a\xd9\x08\xa4\xd1\ +\x00\x00\x04\xd0\x00\x00\x00\x00\x00\x01\x00\x00o\x98\ \x00\x00\x01\x93\xdal,\x96\ \x00\x00\x00t\x00\x00\x00\x00\x00\x01\x00\x00\x08\x90\ \x00\x00\x01\x93\xdal,\x95\ -\x00\x00\x04\xb0\x00\x00\x00\x00\x00\x01\x00\x00l\xa6\ +\x00\x00\x05\x1c\x00\x00\x00\x00\x00\x01\x00\x00s\xb4\ \x00\x00\x01\x93\xdal,\x94\ \x00\x00\x00Z\x00\x00\x00\x00\x00\x01\x00\x00\x01z\ \x00\x00\x01\x93\xdal,\x95\ -\x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x10d\ +\x00\x00\x01\x0a\x00\x00\x00\x00\x00\x01\x00\x00\x14?\ \x00\x00\x01\x93\xdal,\x95\ -\x00\x00\x05\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x86\xc7\ +\x00\x00\x06\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x8d\xd5\ \x00\x00\x01\x93\xdal,\x98\ -\x00\x00\x03\x84\x00\x00\x00\x00\x00\x01\x00\x00TA\ +\x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x10d\ +\x00\x00\x01\x9a\xd5bh\x19\ +\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x00[M\ \x00\x00\x01\x93\xdal,\x94\ -\x00\x00\x02\x82\x00\x00\x00\x00\x00\x01\x00\x00=\x06\ +\x00\x00\x02\xc2\x00\x00\x00\x00\x00\x01\x00\x00B\xb1\ \x00\x00\x01\x93\xdal,\x99\ -\x00\x00\x05\x18\x00\x00\x00\x00\x00\x01\x00\x00vS\ +\x00\x00\x05\x84\x00\x00\x00\x00\x00\x01\x00\x00}a\ \x00\x00\x01\x93\xdal,\x93\ -\x00\x00\x01*\x00\x00\x00\x00\x00\x01\x00\x00\x12z\ +\x00\x00\x01N\x00\x00\x00\x00\x00\x01\x00\x00\x16U\ \x00\x00\x01\x93\xdal,\x98\ -\x00\x00\x04\x1e\x00\x00\x00\x00\x00\x01\x00\x00b$\ +\x00\x00\x04\x8a\x00\x00\x00\x00\x00\x01\x00\x00i0\ \x00\x00\x01\x93\xdal,\x99\ -\x00\x00\x05\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x85\xb0\ +\x00\x00\x06<\x00\x00\x00\x00\x00\x01\x00\x00\x8c\xbe\ \x00\x00\x01\x93\xdal,\x96\ -\x00\x00\x03\xaa\x00\x00\x00\x00\x00\x01\x00\x00Uw\ +\x00\x00\x04\x16\x00\x00\x00\x00\x00\x01\x00\x00\x5c\x83\ \x00\x00\x01\x93\xdal,\x99\ -\x00\x00\x05H\x00\x00\x00\x00\x00\x01\x00\x00w\xce\ +\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x00~\xdc\ \x00\x00\x01\x93\xdal,\x98\ -\x00\x00\x05\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x83\x81\ +\x00\x00\x06\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x8a\x8f\ \x00\x00\x01\x93\xdal,\x93\ -\x00\x00\x04\xce\x00\x00\x00\x00\x00\x01\x00\x00nX\ +\x00\x00\x05:\x00\x00\x00\x00\x00\x01\x00\x00uf\ \x00\x00\x01\x93\xdal,\x97\ -\x00\x00\x02\xa0\x00\x00\x00\x00\x00\x01\x00\x00>\xb5\ +\x00\x00\x02`\x00\x00\x00\x00\x00\x01\x00\x006\x8e\ +\x00\x00\x01\x9a\xd9\x08\xac.\ +\x00\x00\x02\xe0\x00\x00\x00\x00\x00\x01\x00\x00D`\ \x00\x00\x01\x93\xdal,\x99\ -\x00\x00\x04\x02\x00\x00\x00\x00\x00\x01\x00\x00^\x95\ +\x00\x00\x04n\x00\x00\x00\x00\x00\x01\x00\x00e\xa1\ \x00\x00\x01\x93\xdal,\x99\ -\x00\x00\x04D\x00\x00\x00\x00\x00\x01\x00\x00d\xa5\ -\x00\x00\x01\x96\xde\xd9\xe7G\ -\x00\x00\x01b\x00\x00\x00\x00\x00\x01\x00\x00\x1at\ +\x00\x00\x04\xb0\x00\x00\x00\x00\x00\x01\x00\x00k\xb1\ +\x00\x00\x01\x96\xe7\xdc\x22W\ +\x00\x00\x01\x86\x00\x00\x00\x00\x00\x01\x00\x00\x1eO\ \x00\x00\x01\x93\xdal,\x94\ \x00\x00\x00\xb8\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xca\ \x00\x00\x01\x93\xdal,\x95\ \x00\x00\x00(\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ \x00\x00\x01\x93\xdal,\x93\ -\x00\x00\x01\xec\x00\x00\x00\x00\x00\x01\x00\x00+\xfb\ +\x00\x00\x02\x10\x00\x00\x00\x00\x00\x01\x00\x00/\xd6\ \x00\x00\x01\x93\xdal,\x9f\ -\x00\x00\x01\xcc\x00\x00\x00\x00\x00\x01\x00\x00\xa9\x14\ +\x00\x00\x01\xf0\x00\x00\x00\x00\x00\x01\x00\x00\xb4\x0a\ \x00\x00\x01\x93\xdal,\x9c\ -\x00\x00\x02\xe0\x00\x00\x00\x00\x00\x01\x00\x00\xbd\x96\ +\x00\x00\x03 \x00\x00\x00\x00\x00\x01\x00\x00\xcai\ \x00\x00\x01\x93\xdal,\x9d\ -\x00\x00\x03h\x00\x00\x00\x00\x00\x01\x00\x00\xc4\x12\ +\x00\x00\x03\xd4\x00\x00\x00\x00\x00\x01\x00\x00\xd2`\ \x00\x00\x01\x93\xdal,\x9a\ -\x00\x00\x02$\x00\x00\x00\x00\x00\x01\x00\x00\xb2y\ +\x00\x00\x02H\x00\x00\x00\x00\x00\x01\x00\x00\xbdo\ \x00\x00\x01\x93\xdal,\x9b\ -\x00\x00\x02\xba\x00\x00\x00\x00\x00\x01\x00\x00\xbb\x0c\ +\x00\x00\x02\xfa\x00\x00\x00\x00\x00\x01\x00\x00\xc7\xdf\ \x00\x00\x01\x93\xdal,\x9b\ -\x00\x00\x00\x98\x00\x00\x00\x00\x00\x01\x00\x00\x93\xa2\ +\x00\x00\x00\x98\x00\x00\x00\x00\x00\x01\x00\x00\x9a\xb0\ \x00\x00\x01\x93\xdal,\x9d\ -\x00\x00\x02\x02\x00\x00\x00\x00\x00\x01\x00\x00\xb0\xd1\ +\x00\x00\x02&\x00\x00\x00\x00\x00\x01\x00\x00\xbb\xc7\ \x00\x00\x01\x93\xdal,\x9a\ -\x00\x00\x04\x8c\x00\x00\x00\x00\x00\x01\x00\x00\xd5_\ +\x00\x00\x04\xf8\x00\x00\x00\x00\x00\x01\x00\x00\xe3\xaf\ \x00\x00\x01\x93\xdal,\x9c\ -\x00\x00\x02<\x00\x00\x00\x00\x00\x01\x00\x00\xb4\x0d\ +\x00\x00\x02|\x00\x00\x00\x00\x00\x01\x00\x00\xc0\xe0\ \x00\x00\x01\x93\xdal,\x9d\ -\x00\x00\x01\xae\x00\x00\x00\x00\x00\x01\x00\x00\xa4F\ +\x00\x00\x01\xd2\x00\x00\x00\x00\x00\x01\x00\x00\xaf<\ \x00\x00\x01\x93\xdal,\x9a\ -\x00\x00\x01\x96\x00\x00\x00\x00\x00\x01\x00\x00\xa0\x99\ +\x00\x00\x01\xba\x00\x00\x00\x00\x00\x01\x00\x00\xab\x8f\ \x00\x00\x01\x93\xdal,\x9e\ -\x00\x00\x04d\x00\x00\x00\x00\x00\x01\x00\x00\xd2\xfc\ +\x00\x00\x03\xa8\x00\x00\x00\x00\x00\x01\x00\x00\xd0\xe5\ +\x00\x00\x01\x9a\xd9\x09m\x86\ +\x00\x00\x04\xd0\x00\x00\x00\x00\x00\x01\x00\x00\xe1L\ \x00\x00\x01\x93\xdal,\x9d\ -\x00\x00\x00t\x00\x00\x00\x00\x00\x01\x00\x00\x91.\ +\x00\x00\x00t\x00\x00\x00\x00\x00\x01\x00\x00\x98<\ \x00\x00\x01\x93\xdal,\x9c\ -\x00\x00\x04\xb0\x00\x00\x00\x00\x00\x01\x00\x00\xd7L\ +\x00\x00\x05\x1c\x00\x00\x00\x00\x00\x01\x00\x00\xe5\x9c\ \x00\x00\x01\x93\xdal,\x9b\ -\x00\x00\x00Z\x00\x00\x00\x00\x00\x01\x00\x00\x8a\x0b\ +\x00\x00\x00Z\x00\x00\x00\x00\x00\x01\x00\x00\x91\x19\ \x00\x00\x01\x93\xdal,\x9b\ -\x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x996\ +\x00\x00\x01\x0a\x00\x00\x00\x00\x00\x01\x00\x00\xa4,\ \x00\x00\x01\x93\xdal,\x9c\ -\x00\x00\x05\xf0\x00\x00\x00\x00\x00\x01\x00\x00\xe1\xfc\ +\x00\x00\x06\x5c\x00\x00\x00\x00\x00\x01\x00\x00\xf0L\ \x00\x00\x01\x93\xdal,\x9d\ -\x00\x00\x03\x84\x00\x00\x00\x00\x00\x01\x00\x00\xc6_\ +\x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\xa0D\ +\x00\x00\x01\x9a\xd5c1\xd5\ +\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x00\xd4\xad\ \x00\x00\x01\x93\xdal,\x9b\ -\x00\x00\x02\x82\x00\x00\x00\x00\x00\x01\x00\x00\xb6\xa7\ +\x00\x00\x02\xc2\x00\x00\x00\x00\x00\x01\x00\x00\xc3z\ \x00\x00\x01\x93\xdal,\x9e\ -\x00\x00\x05\x18\x00\x00\x00\x00\x00\x01\x00\x00\xd9\x18\ +\x00\x00\x05\x84\x00\x00\x00\x00\x00\x01\x00\x00\xe7h\ \x00\x00\x01\x93\xdal,\x9a\ -\x00\x00\x04\x1e\x00\x00\x00\x00\x00\x01\x00\x00\xcc|\ +\x00\x00\x04\x8a\x00\x00\x00\x00\x00\x01\x00\x00\xda\xca\ \x00\x00\x01\x93\xdal,\x9e\ -\x00\x00\x05\xd0\x00\x00\x00\x00\x00\x01\x00\x00\xe0\xd8\ +\x00\x00\x06<\x00\x00\x00\x00\x00\x01\x00\x00\xef(\ \x00\x00\x01\x93\xdal,\x9d\ -\x00\x00\x03\xaa\x00\x00\x00\x00\x00\x01\x00\x00\xc7\xa2\ +\x00\x00\x04\x16\x00\x00\x00\x00\x00\x01\x00\x00\xd5\xf0\ \x00\x00\x01\x93\xdal,\x9f\ -\x00\x00\x05H\x00\x00\x00\x00\x00\x01\x00\x00\xda\xa0\ +\x00\x00\x05\xb4\x00\x00\x00\x00\x00\x01\x00\x00\xe8\xf0\ \x00\x00\x01\x93\xdal,\x9d\ -\x00\x00\x05\xa0\x00\x00\x00\x00\x00\x01\x00\x00\xde\x8f\ +\x00\x00\x06\x0c\x00\x00\x00\x00\x00\x01\x00\x00\xec\xdf\ \x00\x00\x01\x93\xdal,\x9a\ -\x00\x00\x02\xa0\x00\x00\x00\x00\x00\x01\x00\x00\xb8c\ +\x00\x00\x02`\x00\x00\x00\x00\x00\x01\x00\x00\xbf\x03\ +\x00\x00\x01\x9a\xd9\x09\x9e\xcd\ +\x00\x00\x02\xe0\x00\x00\x00\x00\x00\x01\x00\x00\xc56\ \x00\x00\x01\x93\xdal,\x9e\ -\x00\x00\x04\x02\x00\x00\x00\x00\x00\x01\x00\x00\xc8\xd3\ +\x00\x00\x04n\x00\x00\x00\x00\x00\x01\x00\x00\xd7!\ \x00\x00\x01\x93\xdal,\x9e\ -\x00\x00\x04D\x00\x00\x00\x00\x00\x01\x00\x00\xcf\x0a\ -\x00\x00\x01\x96\xde\xdb.r\ -\x00\x00\x01b\x00\x00\x00\x00\x00\x01\x00\x00\x9bf\ +\x00\x00\x04\xb0\x00\x00\x00\x00\x00\x01\x00\x00\xddX\ +\x00\x00\x01\x96\xe7\xdc\x22W\ +\x00\x00\x01\x86\x00\x00\x00\x00\x00\x01\x00\x00\xa6\x5c\ \x00\x00\x01\x93\xdal,\x9b\ -\x00\x00\x00\xb8\x00\x00\x00\x00\x00\x01\x00\x00\x97\x8f\ +\x00\x00\x00\xb8\x00\x00\x00\x00\x00\x01\x00\x00\x9e\x9d\ \x00\x00\x01\x93\xdal,\x9c\ -\x00\x00\x00(\x00\x00\x00\x00\x00\x01\x00\x00\x88\x84\ +\x00\x00\x00(\x00\x00\x00\x00\x00\x01\x00\x00\x8f\x92\ \x00\x00\x01\x93\xdal,\x9a\ -\x00\x00\x01\xec\x00\x00\x00\x00\x00\x01\x00\x00\xad!\ +\x00\x00\x02\x10\x00\x00\x00\x00\x00\x01\x00\x00\xb8\x17\ \x00\x00\x01\x93\xdal,\x9f\ " diff --git a/Furious/Frozenlib/Constants.py b/Furious/Frozenlib/Constants.py index 86f840b..7aee2d8 100644 --- a/Furious/Frozenlib/Constants.py +++ b/Furious/Frozenlib/Constants.py @@ -101,12 +101,12 @@ else: APPLICATION_TUN_INTERFACE_DNS_ADDRESS = '1.1.1.1' -ADMINISTRATOR_NAME = 'Administrator' if PLATFORM == 'Windows' else 'root' +ADMINISTRATOR_NAME = 'Administrator' if PLATFORM == 'Windows' else 'Superuser' NETWORK_STATE_TEST_URL = 'http://cp.cloudflare.com' NETWORK_SPEED_TEST_URL = ( 'http://speed.cloudflare.com/__down?during=download&bytes=104857600' ) -UNICODE_LARGE_RED_CIRCLE = u'\U0001F534' -UNICODE_LARGE_GREEN_CIRCLE = u'\U0001F7E2' +UNICODE_LARGE_RED_CIRCLE = u'\U0001f534' +UNICODE_LARGE_GREEN_CIRCLE = u'\U0001f7e2' diff --git a/Furious/Frozenlib/PySide6Legacy.py b/Furious/Frozenlib/PySide6Legacy.py index 55ba918..2190253 100644 --- a/Furious/Frozenlib/PySide6Legacy.py +++ b/Furious/Frozenlib/PySide6Legacy.py @@ -15,6 +15,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import annotations + from Furious.Frozenlib.Constants import * from Furious.Frozenlib.Globals import * from Furious.Frozenlib.Utility import * @@ -26,7 +28,7 @@ __all__ = ['PySide6Legacy'] class PySide6Legacy: @staticmethod - def enumValueWrapper(enum): + def enumValueWrapper(enum) -> int: # Protect PySide6 enum wrapper behavior changes if versionToValue(PYSIDE6_VERSION) < versionToValue('6.2.2'): return enum @@ -34,7 +36,7 @@ class PySide6Legacy: return enum.value @staticmethod - def eventLoopWait(ms): + def eventLoopWait(ms) -> None: # Protect qWait method does not exist in some # old PySide6 version if versionToValue(PYSIDE6_VERSION) < versionToValue('6.3.1'): diff --git a/Furious/Frozenlib/__init__.py b/Furious/Frozenlib/__init__.py index 882505e..b0b85bf 100644 --- a/Furious/Frozenlib/__init__.py +++ b/Furious/Frozenlib/__init__.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from .AppCommands import * from .AppSettings import * from .Constants import * from .Globals import * diff --git a/Furious/Qt/QtWidgets.py b/Furious/Qt/QtWidgets.py index c59425a..8a07f32 100644 --- a/Furious/Qt/QtWidgets.py +++ b/Furious/Qt/QtWidgets.py @@ -639,11 +639,38 @@ class NewChangesNextTimeMBox(AppQMessageBox): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.setWindowTitle(_(APPLICATION_NAME)) self.setIcon(AppQMessageBox.Icon.Information) - self.setText(_('New changes will take effect next time')) + self.setStandardButtons( + AppQMessageBox.StandardButton.Yes | AppQMessageBox.StandardButton.No + ) + self.setText(self.customText()) + + @staticmethod + def customText() -> str: + return ( + _('New changes will take effect next time') + '\n\n' + _('Reconnect now?') + ) + + def retranslate(self): + self.setWindowTitle(_(self.windowTitle())) + self.setText(self.customText()) + + # Ignore informative text, buttons + + self.moveToCenter() def showNewChangesNextTimeMBox(**kwargs): + + @QtCore.Slot(int) + def handleResultCode(code): + if code == PySide6Legacy.enumValueWrapper(AppQMessageBox.StandardButton.Yes): + APP().systemTray.ConnectAction.doReconnect() + else: + # Do nothing + pass + try: method = kwargs.pop('method', 'open') @@ -656,11 +683,12 @@ def showNewChangesNextTimeMBox(**kwargs): mbox.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) if method == 'open': + mbox.finished.connect(handleResultCode) # Show the MessageBox asynchronously mbox.open() else: # Show the MessageBox and wait for the user to close it - mbox.exec() + handleResultCode(mbox.exec()) except Exception: # Any non-exit exceptions diff --git a/Furious/TrayActions/Connect.py b/Furious/TrayActions/Connect.py index 469d3fd..e6cbe98 100644 --- a/Furious/TrayActions/Connect.py +++ b/Furious/TrayActions/Connect.py @@ -161,6 +161,10 @@ class ConnectAction(AppQAction): APP().systemTray.showMessage(message) + def doReconnect(self, message=''): + self.doDisconnectWithTrayMessage(message) + self.trigger() + def doConnect(self): # Connect action assert self.textCompare('Connect') @@ -289,9 +293,12 @@ class ConnectAction(AppQAction): hasNewVersionCallback=newVersionCallback, ) - # Automatically update assets - self.assetDownloadManager.configureHttpProxy(connectedHttpProxy) - self.assetDownloadManager.download() + if SystemRuntime.appImagePath(): + logger.info('skipped auto assets update due to running from Linux AppImage') + else: + # Automatically update assets + self.assetDownloadManager.configureHttpProxy(connectedHttpProxy) + self.assetDownloadManager.download() def callActionFromQueue(self): try: diff --git a/Furious/TrayActions/Routing.py b/Furious/TrayActions/Routing.py index 783b523..1094973 100644 --- a/Furious/TrayActions/Routing.py +++ b/Furious/TrayActions/Routing.py @@ -26,7 +26,7 @@ BUILTIN_ROUTING = ['Bypass Mainland China', 'Global', 'Custom'] registerAppSettings('Routing', validRange=BUILTIN_ROUTING) # ALL BUILTIN ROUTING VALUE -TRANSLATABLE_BUILTIN_ROUTING = [ +_TRANSLATABLE_BUILTIN_ROUTING = [ _('Bypass Mainland China'), _('Global'), _('Custom'), @@ -44,8 +44,7 @@ class RoutingChildAction(AppQAction): AppSettings.set('Routing', textEnglish) if APP().isSystemTrayConnected(): - APP().systemTray.ConnectAction.doDisconnect() - APP().systemTray.ConnectAction.trigger() + APP().systemTray.ConnectAction.doReconnect() class RoutingAction(AppQAction): diff --git a/Furious/TrayActions/Settings.py b/Furious/TrayActions/Settings.py index 9c64393..d27b123 100644 --- a/Furious/TrayActions/Settings.py +++ b/Furious/TrayActions/Settings.py @@ -38,10 +38,10 @@ registerAppSettings( ) registerAppSettings('ShowTabAndSpacesInEditor', isBinary=True) -# Administrator, root -TRANSLATABLE_TUN_MODE = [ +# Administrator, Superuser +_TRANSLATABLE_TUN_MODE = [ _('TUN Mode Disabled (Administrator)'), - _('TUN Mode Disabled (root)'), + _('TUN Mode Disabled (Superuser)'), ] diff --git a/Furious/Widget/Application.py b/Furious/Widget/Application.py index a0f62d9..d79f188 100644 --- a/Furious/Widget/Application.py +++ b/Furious/Widget/Application.py @@ -87,11 +87,28 @@ class SingletonApplication(ApplicationExitHelper): self.socket.connectToServer(self.serverName) if self.socket.waitForConnected(1000): - # Show tray message in the started instance - self.socket.close() + if len(sys.argv) == 1: + command = AppCommands.Empty.value + else: + command = sys.argv[1] - # Do not start - return True + self.socket.write(command.encode()) + self.socket.flush() + + if command == AppCommands.Empty.value: + # Show tray message in the started instance. Do not start + return True + elif command == AppCommands.RunAs.value: + if self.socket.waitForDisconnected(3000): + # The other instance have been exited. Start + return False + else: + # Do not start + return True + else: + # TODO: Not implemented + # Do not start + return True else: # Remove the old socket file if it exists socket_path = QLocalServer.removeServer(self.serverName) @@ -102,7 +119,7 @@ class SingletonApplication(ApplicationExitHelper): logger.info(f'no existing socket file found for: {self.serverName}') # New instance - self.server.newConnection.connect(self.showExistingApp) + self.server.newConnection.connect(self.handleNewConnection) if not self.server.listen(self.serverName): # Do not start @@ -114,7 +131,7 @@ class SingletonApplication(ApplicationExitHelper): return False @QtCore.Slot() - def showExistingApp(self): + def handleNewConnection(self): raise NotImplementedError @@ -156,13 +173,33 @@ class Application(ApplicationFactory, SingletonApplication): @callRateLimited(maxCallPerSecond=2) @QtCore.Slot() - def showExistingApp(self): - if isinstance(self.systemTray, SystemTrayIcon): - logger.info('attempting to start multiple instance. Show tray message') + def handleNewConnection(self): + socket = self.server.nextPendingConnection() + socket.readyRead.connect(functools.partial(self.handleNewData, socket)) - self.systemTray.showMessage(_('Already started')) + @QtCore.Slot(QLocalSocket) + def handleNewData(self, socket: QLocalSocket): + data = socket.readAll().data() + + if isinstance(data, bytes): + datastr = data.decode('utf-8', 'replace') else: - # The tray hasn't been initialized. Do nothing + datastr = str(data) + + if datastr == AppCommands.Empty.value: + if isinstance(self.systemTray, SystemTrayIcon): + logger.info('attempting to start multiple instance. Show tray message') + + self.systemTray.showMessage(_('Already started')) + else: + # The tray hasn't been initialized. Do nothing + pass + elif datastr == AppCommands.RunAs.value: + logger.info('detected requests to start as admin in new instance. Exiting') + + self.exit() + else: + # TODO: Not implemented pass def configureLogging(self): @@ -248,11 +285,7 @@ class Application(ApplicationFactory, SingletonApplication): SystemProxy.off() SystemProxy.daemonOff() - if PLATFORM == 'Darwin': - AppThreadPool().clear() - - for timeout in [1000, 2000, 3000]: - QtCore.QTimer.singleShot(timeout, APP().exit) + AppThreadPool().clear() logger.info('final cleanup done') @@ -295,6 +328,10 @@ class Application(ApplicationFactory, SingletonApplication): self.threadPool.clear() + # Dirty exit + for timeout in [1000, 2000, 3000]: + QtCore.QTimer.singleShot(timeout, APP().exit) + super().exit(exitcode) def run(self): diff --git a/Furious/Widget/SystemTrayIcon.py b/Furious/Widget/SystemTrayIcon.py index 78c1434..80e6caf 100644 --- a/Furious/Widget/SystemTrayIcon.py +++ b/Furious/Widget/SystemTrayIcon.py @@ -32,6 +32,10 @@ logger = logging.getLogger(__name__) __all__ = ['SystemTrayIcon'] +_TRANSLATABLE_ADMIN = [ + _('Administrator'), +] + class SystemTrayIcon( Mixins.QTranslatable, @@ -183,7 +187,12 @@ class SystemTrayIcon( APP().mainWindow.show() def setCustomToolTip(self): - self.setToolTip(f'{_(APPLICATION_NAME)} {APPLICATION_VERSION}') + if SystemRuntime.isAdmin(): + self.setToolTip( + f'{_(APPLICATION_NAME)} {APPLICATION_VERSION} ({_(ADMINISTRATOR_NAME)})' + ) + else: + self.setToolTip(f'{_(APPLICATION_NAME)} {APPLICATION_VERSION}') def disconnectedCallback(self): self.setDisconnectedIcon() diff --git a/Furious/Widget/UserServersQTableWidget.py b/Furious/Widget/UserServersQTableWidget.py index 5cf0ef5..5021f78 100644 --- a/Furious/Widget/UserServersQTableWidget.py +++ b/Furious/Widget/UserServersQTableWidget.py @@ -766,7 +766,7 @@ class UserServersQTableWidgetHeaders: # ALL Headers VALUE -TRANSLATABLE_HEADERS = [ +_TRANSLATABLE_HEADERS = [ _('Remark'), _('Protocol'), _('Address'), @@ -1108,8 +1108,7 @@ class UserServersQTableWidget(Mixins.QTranslatable, AppQTableWidget): self.activateItemByIndex(newIndex, True) if APP().isSystemTrayConnected(): - APP().systemTray.ConnectAction.doDisconnect() - APP().systemTray.ConnectAction.trigger() + APP().systemTray.ConnectAction.doReconnect() @functools.lru_cache(None) def getGuiEditorByProtocol(self, protocol: Protocol, **kwargs): diff --git a/Furious/Widget/UserSubsQTableWidget.py b/Furious/Widget/UserSubsQTableWidget.py index 770b5e0..f42f95d 100644 --- a/Furious/Widget/UserSubsQTableWidget.py +++ b/Furious/Widget/UserSubsQTableWidget.py @@ -79,7 +79,7 @@ class UserSubsAppQComboBox(AppQComboBox): # Headers VALUE -TRANSLATABLE_HEADERS = [ +_TRANSLATABLE_HEADERS = [ _('Never'), _('Every 5 mins'), _('Every 10 mins'), diff --git a/Furious/Window/AppMainWindow.py b/Furious/Window/AppMainWindow.py index 9ef9919..388fb90 100644 --- a/Furious/Window/AppMainWindow.py +++ b/Furious/Window/AppMainWindow.py @@ -22,6 +22,7 @@ from Furious.Interface import * from Furious.Library import * from Furious.Qt import * from Furious.Qt import gettext as _ +from Furious.Utility import * from Furious.Widget.UserServersQTableWidget import * from Furious.Widget.GuiTUNSettings import * from Furious.Window.UserSubsWindow import * @@ -106,7 +107,10 @@ class AppMainWindow(AppQMainWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.setWindowTitle(_(APPLICATION_NAME)) + if SystemRuntime.isAdmin(): + self.setWindowTitle(f'{_(APPLICATION_NAME)} ({_(ADMINISTRATOR_NAME)})') + else: + self.setWindowTitle(f'{_(APPLICATION_NAME)}') # TODO: Need this? # self.setAttribute(QtCore.Qt.WidgetAttribute.WA_ShowWithoutActivating) @@ -235,14 +239,16 @@ class AppMainWindow(AppQMainWindow): ] if PLATFORM == 'Darwin': - openAppFolderAction = [None] + openAppFolderAction = [] else: openAppFolderAction = [ - AppQSeperator(), AppQAction( _('Open Application Folder'), + icon=bootstrapIcon('folder2.svg'), + checkable=False, callback=lambda: self.openApplicationFolder(), ), + AppQSeperator(), ] if PLATFORM == 'Windows' or PLATFORM == 'Darwin': @@ -258,13 +264,31 @@ class AppMainWindow(AppQMainWindow): else: customizeTUNSettingsAction = [] + if PLATFORM == 'Windows' or PLATFORM == 'Darwin': + _TRANSLATABLE_RESTART_AS_ADMIN = [ + _('Restart The Application As Administrator'), + _('Restart The Application As Superuser'), + ] + + restartAsAdminAction = [ + AppQAction( + _(f'Restart The Application As {ADMINISTRATOR_NAME}'), + icon=bootstrapIcon('arrow-clockwise.svg'), + checkable=False, + callback=lambda: self.restartAsAdmin(), + ), + ] + else: + restartAsAdminAction = [] + toolsActions = [ *customizeTUNSettingsAction, + *restartAsAdminAction, + *openAppFolderAction, AppQAction( _('Manage Xray-core Asset File...'), callback=lambda: self.xrayAssetViewerWindow.show(), ), - *openAppFolderAction, ] if hasattr(AppQAction, 'setMenu'): @@ -367,7 +391,7 @@ class AppMainWindow(AppQMainWindow): } # Corresponds to menus defined above - TRANSLATABLE_MENU_NAME = [ + _TRANSLATABLE_MENU_NAME = [ _('Log'), _('Server'), _('Subscription'), @@ -464,6 +488,33 @@ class AppMainWindow(AppQMainWindow): else: logger.error(f'open application folder \'{appFolder}\' failed') + @staticmethod + def restartAsAdmin(): + if not SystemRuntime.isScriptMode(): + if not SystemRuntime.isAdmin(): + process = QtCore.QProcess() + + if PLATFORM == 'Windows': + process.startDetached( + 'powershell', + arguments=[ + '-Command', + f'Start-Process \'{APP().applicationFilePath()}\' ' + f'\'{AppCommands.RunAs.value}\' -Verb runAs', + ], + ) + else: + mbox = AppQMessageBox(icon=AppQMessageBox.Icon.Information) + mbox.setWindowTitle(_(APPLICATION_NAME)) + mbox.setText(_('I am, the supreme authority.')) + + # Show the MessageBox asynchronously + mbox.open() + + logger.info('ignored request to restart as admin as already is') + else: + logger.info(f'ignored request to restart as admin in script mode') + @staticmethod def openAboutPage(): if QDesktopServices.openUrl(QtCore.QUrl(APPLICATION_ABOUT_PAGE)): diff --git a/Icons/bootstrap/arrow-clockwise.svg b/Icons/bootstrap/arrow-clockwise.svg new file mode 100644 index 0000000..324d5af --- /dev/null +++ b/Icons/bootstrap/arrow-clockwise.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Icons/bootstrap/folder2.svg b/Icons/bootstrap/folder2.svg new file mode 100644 index 0000000..ce6a1af --- /dev/null +++ b/Icons/bootstrap/folder2.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Icons/bootstrap/person-gear.svg b/Icons/bootstrap/person-gear.svg new file mode 100644 index 0000000..93ec4da --- /dev/null +++ b/Icons/bootstrap/person-gear.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Icons/bootstrap/white/arrow-clockwise.svg b/Icons/bootstrap/white/arrow-clockwise.svg new file mode 100644 index 0000000..8c5c056 --- /dev/null +++ b/Icons/bootstrap/white/arrow-clockwise.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Icons/bootstrap/white/folder2.svg b/Icons/bootstrap/white/folder2.svg new file mode 100644 index 0000000..503858e --- /dev/null +++ b/Icons/bootstrap/white/folder2.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Icons/bootstrap/white/person-gear.svg b/Icons/bootstrap/white/person-gear.svg new file mode 100644 index 0000000..add8ea1 --- /dev/null +++ b/Icons/bootstrap/white/person-gear.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Resources.qrc b/Resources.qrc index e59cf18..93ad760 100644 --- a/Resources.qrc +++ b/Resources.qrc @@ -1,6 +1,7 @@ + Icons/bootstrap/arrow-clockwise.svg Icons/bootstrap/arrow-return-left.svg Icons/bootstrap/arrow-return-right.svg Icons/bootstrap/box-arrow-in-left.svg @@ -11,6 +12,7 @@ Icons/bootstrap/download.svg Icons/bootstrap/file-earmark.svg Icons/bootstrap/files.svg + Icons/bootstrap/folder2.svg Icons/bootstrap/folder2-open.svg Icons/bootstrap/gear-wide-connected.svg Icons/bootstrap/globe2.svg @@ -22,6 +24,7 @@ Icons/bootstrap/lock-fill.svg Icons/bootstrap/monochrome-rocket-takeoff.svg Icons/bootstrap/pencil-square.svg + Icons/bootstrap/person-gear.svg Icons/bootstrap/pin-angle.svg Icons/bootstrap/qr-code.svg Icons/bootstrap/rocket-takeoff.svg @@ -41,6 +44,7 @@ Icons/bootstrap/wifi.svg + Icons/bootstrap/white/arrow-clockwise.svg Icons/bootstrap/white/arrow-return-left.svg Icons/bootstrap/white/arrow-return-right.svg Icons/bootstrap/white/box-arrow-in-left.svg @@ -51,6 +55,7 @@ Icons/bootstrap/white/download.svg Icons/bootstrap/white/file-earmark.svg Icons/bootstrap/white/files.svg + Icons/bootstrap/white/folder2.svg Icons/bootstrap/white/folder2-open.svg Icons/bootstrap/white/gear-wide-connected.svg Icons/bootstrap/white/globe2.svg @@ -62,6 +67,7 @@ Icons/bootstrap/white/lock-fill.svg Icons/bootstrap/white/monochrome-rocket-takeoff.svg Icons/bootstrap/white/pencil-square.svg + Icons/bootstrap/white/person-gear.svg Icons/bootstrap/white/pin-angle.svg Icons/bootstrap/white/qr-code.svg Icons/bootstrap/white/router.svg