mirror of
https://github.com/flashwave/topmostfriend.git
synced 2024-11-21 17:43:08 +00:00
v1.6.0 - 2021-07-09
This commit is contained in:
parent
103d3d4bff
commit
19f16b4f64
23 changed files with 1342 additions and 290 deletions
|
@ -3,3 +3,5 @@
|
||||||
utility that lets you quickly force any program to be always on top
|
utility that lets you quickly force any program to be always on top
|
||||||
|
|
||||||
should work on any version of windows that supports .net framework 4.0
|
should work on any version of windows that supports .net framework 4.0
|
||||||
|
|
||||||
|
[Click here to download!](https://github.com/flashwave/topmostfriend/releases/latest)
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace TopMostFriend {
|
||||||
}
|
}
|
||||||
|
|
||||||
public AboutWindow() {
|
public AboutWindow() {
|
||||||
Text = @"About Top Most Friend";
|
Text = Locale.String(@"AboutTitle");
|
||||||
Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||||
BackgroundImage = Properties.Resources.about;
|
BackgroundImage = Properties.Resources.about;
|
||||||
StartPosition = FormStartPosition.CenterScreen;
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
@ -24,11 +24,12 @@ namespace TopMostFriend {
|
||||||
ClientSize = Properties.Resources.about.Size;
|
ClientSize = Properties.Resources.about.Size;
|
||||||
MaximizeBox = MinimizeBox = false;
|
MaximizeBox = MinimizeBox = false;
|
||||||
MaximumSize = MinimumSize = Size;
|
MaximumSize = MinimumSize = Size;
|
||||||
|
TopMost = true;
|
||||||
|
|
||||||
int tabIndex = 0;
|
int tabIndex = 0;
|
||||||
|
|
||||||
Button closeButton = new Button {
|
Button closeButton = new Button {
|
||||||
Text = @"Close",
|
Text = Locale.String(@"AboutClose"),
|
||||||
Size = new Size(BUTTON_WIDTH, BUTTON_HEIGHT),
|
Size = new Size(BUTTON_WIDTH, BUTTON_HEIGHT),
|
||||||
TabIndex = ++tabIndex,
|
TabIndex = ++tabIndex,
|
||||||
};
|
};
|
||||||
|
@ -37,7 +38,7 @@ namespace TopMostFriend {
|
||||||
Controls.Add(closeButton);
|
Controls.Add(closeButton);
|
||||||
|
|
||||||
Button websiteButton = new Button {
|
Button websiteButton = new Button {
|
||||||
Text = @"Website",
|
Text = Locale.String(@"AboutWebsite"),
|
||||||
Size = new Size(BUTTON_WIDTH, BUTTON_HEIGHT),
|
Size = new Size(BUTTON_WIDTH, BUTTON_HEIGHT),
|
||||||
TabIndex = ++tabIndex,
|
TabIndex = ++tabIndex,
|
||||||
};
|
};
|
||||||
|
@ -46,7 +47,7 @@ namespace TopMostFriend {
|
||||||
Controls.Add(websiteButton);
|
Controls.Add(websiteButton);
|
||||||
|
|
||||||
Button donateButton = new Button {
|
Button donateButton = new Button {
|
||||||
Text = @"Donate",
|
Text = Locale.String(@"AboutDonate"),
|
||||||
Size = new Size(BUTTON_WIDTH, BUTTON_HEIGHT),
|
Size = new Size(BUTTON_WIDTH, BUTTON_HEIGHT),
|
||||||
TabIndex = ++tabIndex,
|
TabIndex = ++tabIndex,
|
||||||
};
|
};
|
||||||
|
|
35
TopMostFriend/ActionTimeout.cs
Normal file
35
TopMostFriend/ActionTimeout.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace TopMostFriend {
|
||||||
|
public class ActionTimeout {
|
||||||
|
private readonly Action Action;
|
||||||
|
private bool Continue = true;
|
||||||
|
private int Remaining = 0;
|
||||||
|
private const int STEP = 500;
|
||||||
|
|
||||||
|
public ActionTimeout(Action action, int timeout) {
|
||||||
|
Action = action ?? throw new ArgumentNullException(nameof(action));
|
||||||
|
if(timeout < 1)
|
||||||
|
throw new ArgumentException(@"Timeout must be a positive integer.", nameof(timeout));
|
||||||
|
Remaining = timeout;
|
||||||
|
new Thread(ThreadBody) { IsBackground = true }.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThreadBody() {
|
||||||
|
do {
|
||||||
|
Thread.Sleep(STEP);
|
||||||
|
Remaining -= STEP;
|
||||||
|
|
||||||
|
if(!Continue)
|
||||||
|
return;
|
||||||
|
} while(Remaining > 0);
|
||||||
|
|
||||||
|
Action.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Cancel() {
|
||||||
|
Continue = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,26 +35,27 @@ namespace TopMostFriend {
|
||||||
MinimizeBox = MaximizeBox = false;
|
MinimizeBox = MaximizeBox = false;
|
||||||
MinimumSize = Size;
|
MinimumSize = Size;
|
||||||
DialogResult = DialogResult.Cancel;
|
DialogResult = DialogResult.Cancel;
|
||||||
|
TopMost = true;
|
||||||
|
|
||||||
BlacklistView = new ListBox {
|
BlacklistView = new ListBox {
|
||||||
TabIndex = 101,
|
TabIndex = 101,
|
||||||
IntegralHeight = false,
|
IntegralHeight = false,
|
||||||
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right,
|
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right,
|
||||||
Location = new Point(BUTTON_WIDTH + (SPACING * 2), SPACING),
|
Location = new Point(SPACING, SPACING),
|
||||||
ClientSize = new Size(ClientSize.Width - BUTTON_WIDTH - (int)(SPACING * 3.5), ClientSize.Height - (int)(SPACING * 2.5)),
|
ClientSize = new Size(ClientSize.Width - BUTTON_WIDTH - (int)(SPACING * 3.5), ClientSize.Height - (int)(SPACING * 2.5)),
|
||||||
};
|
};
|
||||||
BlacklistView.SelectedIndexChanged += BlacklistView_SelectedIndexChanged;
|
BlacklistView.SelectedIndexChanged += BlacklistView_SelectedIndexChanged;
|
||||||
BlacklistView.MouseDoubleClick += BlacklistView_MouseDoubleClick;
|
BlacklistView.MouseDoubleClick += BlacklistView_MouseDoubleClick;
|
||||||
|
|
||||||
AddButton = new Button {
|
AddButton = new Button {
|
||||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
Anchor = AnchorStyles.Top | AnchorStyles.Right,
|
||||||
Text = @"Add",
|
Text = Locale.String(@"BlacklistAdd"),
|
||||||
ClientSize = new Size(BUTTON_WIDTH, BUTTON_HEIGHT),
|
ClientSize = new Size(BUTTON_WIDTH, BUTTON_HEIGHT),
|
||||||
Location = new Point(SPACING, SPACING),
|
Location = new Point(BlacklistView.Width + (SPACING * 2), SPACING),
|
||||||
TabIndex = 201,
|
TabIndex = 201,
|
||||||
};
|
};
|
||||||
EditButton = new Button {
|
EditButton = new Button {
|
||||||
Text = @"Edit",
|
Text = Locale.String(@"BlacklistEdit"),
|
||||||
Location = new Point(AddButton.Location.X, AddButton.Location.Y + AddButton.Height + SPACING),
|
Location = new Point(AddButton.Location.X, AddButton.Location.Y + AddButton.Height + SPACING),
|
||||||
Enabled = false,
|
Enabled = false,
|
||||||
Anchor = AddButton.Anchor,
|
Anchor = AddButton.Anchor,
|
||||||
|
@ -62,7 +63,7 @@ namespace TopMostFriend {
|
||||||
TabIndex = 202,
|
TabIndex = 202,
|
||||||
};
|
};
|
||||||
RemoveButton = new Button {
|
RemoveButton = new Button {
|
||||||
Text = @"Remove",
|
Text = Locale.String(@"BlacklistRemove"),
|
||||||
Location = new Point(AddButton.Location.X, EditButton.Location.Y + AddButton.Height + SPACING),
|
Location = new Point(AddButton.Location.X, EditButton.Location.Y + AddButton.Height + SPACING),
|
||||||
Enabled = false,
|
Enabled = false,
|
||||||
Anchor = AddButton.Anchor,
|
Anchor = AddButton.Anchor,
|
||||||
|
@ -75,16 +76,16 @@ namespace TopMostFriend {
|
||||||
RemoveButton.Click += RemoveButton_Click;
|
RemoveButton.Click += RemoveButton_Click;
|
||||||
|
|
||||||
CancelButton = new Button {
|
CancelButton = new Button {
|
||||||
Anchor = AnchorStyles.Bottom | AnchorStyles.Left,
|
Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
|
||||||
Text = @"Cancel",
|
Text = Locale.String(@"BlacklistCancel"),
|
||||||
Location = new Point(SPACING, ClientSize.Height - AddButton.ClientSize.Height - SPACING),
|
Location = new Point(AddButton.Location.X, ClientSize.Height - AddButton.ClientSize.Height - SPACING),
|
||||||
ClientSize = AddButton.ClientSize,
|
ClientSize = AddButton.ClientSize,
|
||||||
TabIndex = 10001,
|
TabIndex = 10001,
|
||||||
};
|
};
|
||||||
Button acceptButton = new Button {
|
Button acceptButton = new Button {
|
||||||
Anchor = AnchorStyles.Bottom | AnchorStyles.Left,
|
Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
|
||||||
Text = @"Done",
|
Text = Locale.String(@"BlacklistDone"),
|
||||||
Location = new Point(SPACING, ClientSize.Height - ((AddButton.ClientSize.Height + SPACING) * 2)),
|
Location = new Point(AddButton.Location.X, ClientSize.Height - ((AddButton.ClientSize.Height + SPACING) * 2)),
|
||||||
ClientSize = AddButton.ClientSize,
|
ClientSize = AddButton.ClientSize,
|
||||||
TabIndex = 10002,
|
TabIndex = 10002,
|
||||||
};
|
};
|
||||||
|
@ -106,16 +107,18 @@ namespace TopMostFriend {
|
||||||
public string Original { get; }
|
public string Original { get; }
|
||||||
public string String { get => TextBox.Text; }
|
public string String { get => TextBox.Text; }
|
||||||
|
|
||||||
private TextBox TextBox;
|
private readonly TextBox TextBox;
|
||||||
|
|
||||||
public BlacklistEditorWindow(string original = null) {
|
public BlacklistEditorWindow(string original = null) {
|
||||||
Original = original ?? string.Empty;
|
Original = original ?? string.Empty;
|
||||||
Text = original == null ? @"Adding new entry..." : $@"Editing {original}...";
|
Text = Locale.String(original == null ? @"BlacklistEditorAdding" : @"BlacklistEditorEditing", original);
|
||||||
|
Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||||
StartPosition = FormStartPosition.CenterParent;
|
StartPosition = FormStartPosition.CenterParent;
|
||||||
FormBorderStyle = FormBorderStyle.FixedToolWindow;
|
FormBorderStyle = FormBorderStyle.FixedSingle;
|
||||||
ClientSize = new Size(500, 39);
|
ClientSize = new Size(500, 39);
|
||||||
MaximizeBox = MinimizeBox = false;
|
MaximizeBox = MinimizeBox = false;
|
||||||
MaximumSize = MinimumSize = Size;
|
MaximumSize = MinimumSize = Size;
|
||||||
|
TopMost = true;
|
||||||
|
|
||||||
Button cancelButton = new Button {
|
Button cancelButton = new Button {
|
||||||
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right,
|
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right,
|
||||||
|
@ -123,7 +126,7 @@ namespace TopMostFriend {
|
||||||
Name = @"cancelButton",
|
Name = @"cancelButton",
|
||||||
Size = new Size(75, 23),
|
Size = new Size(75, 23),
|
||||||
TabIndex = 102,
|
TabIndex = 102,
|
||||||
Text = @"Cancel",
|
Text = Locale.String(@"BlacklistEditorCancel"),
|
||||||
};
|
};
|
||||||
cancelButton.Click += (s, e) => { DialogResult = DialogResult.Cancel; Close(); };
|
cancelButton.Click += (s, e) => { DialogResult = DialogResult.Cancel; Close(); };
|
||||||
|
|
||||||
|
@ -133,14 +136,14 @@ namespace TopMostFriend {
|
||||||
Name = @"saveButton",
|
Name = @"saveButton",
|
||||||
Size = new Size(75, 23),
|
Size = new Size(75, 23),
|
||||||
TabIndex = 101,
|
TabIndex = 101,
|
||||||
Text = @"Save",
|
Text = Locale.String(@"BlacklistEditorSave"),
|
||||||
};
|
};
|
||||||
saveButton.Click += (s, e) => { DialogResult = DialogResult.OK; Close(); };
|
saveButton.Click += (s, e) => { DialogResult = DialogResult.OK; Close(); };
|
||||||
|
|
||||||
TextBox = new TextBox {
|
TextBox = new TextBox {
|
||||||
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right,
|
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right,
|
||||||
Location = new Point(8, 9),
|
Location = new Point(8, 9),
|
||||||
Name = @"deviceSelection",
|
Name = @"deviceSelection", // ??????
|
||||||
Size = new Size(ClientSize.Width - 8 - cancelButton.Width - saveButton.Width - 19, 23),
|
Size = new Size(ClientSize.Width - 8 - cancelButton.Width - saveButton.Width - 19, 23),
|
||||||
TabIndex = 100,
|
TabIndex = 100,
|
||||||
Text = Original,
|
Text = Original,
|
||||||
|
|
357
TopMostFriend/FirstRunWindow.cs
Normal file
357
TopMostFriend/FirstRunWindow.cs
Normal file
|
@ -0,0 +1,357 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace TopMostFriend {
|
||||||
|
public class FirstRunWindow : Form {
|
||||||
|
public static void Display() {
|
||||||
|
using(FirstRunWindow firstRun = new FirstRunWindow())
|
||||||
|
firstRun.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CanClose = false;
|
||||||
|
private bool IsClosing = false;
|
||||||
|
private bool IsSizing = false;
|
||||||
|
|
||||||
|
private Button NextBtn { get; }
|
||||||
|
private Button PrevBtn { get; }
|
||||||
|
|
||||||
|
private Action NextAct = null;
|
||||||
|
private Action PrevAct = null;
|
||||||
|
|
||||||
|
private bool NextVisible { get => NextBtn.Visible; set => NextBtn.Visible = value; }
|
||||||
|
private bool PrevVisible { get => PrevBtn.Visible; set => PrevBtn.Visible = value; }
|
||||||
|
|
||||||
|
private Panel WorkArea { get; }
|
||||||
|
|
||||||
|
public FirstRunWindow() {
|
||||||
|
Text = Program.TITLE + @" v" + Application.ProductVersion.Substring(0, Application.ProductVersion.Length - 2);
|
||||||
|
Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||||
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
FormBorderStyle = FormBorderStyle.FixedSingle;
|
||||||
|
AutoScaleMode = AutoScaleMode.Dpi;
|
||||||
|
MaximizeBox = MinimizeBox = false;
|
||||||
|
TopMost = true;
|
||||||
|
ClientSize = new Size(410, 80);
|
||||||
|
|
||||||
|
Controls.Add(new PictureBox {
|
||||||
|
Image = Properties.Resources.firstrun,
|
||||||
|
Size = Properties.Resources.firstrun.Size,
|
||||||
|
Location = new Point(0, 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
NextBtn = new Button {
|
||||||
|
Text = Locale.String(@"FirstRunNext"),
|
||||||
|
Anchor = AnchorStyles.Right | AnchorStyles.Bottom,
|
||||||
|
Visible = false,
|
||||||
|
Location = new Point(ClientSize.Width - 81, ClientSize.Height - 29),
|
||||||
|
};
|
||||||
|
NextBtn.Click += NextBtn_Click;
|
||||||
|
Controls.Add(NextBtn);
|
||||||
|
|
||||||
|
PrevBtn = new Button {
|
||||||
|
Text = Locale.String(@"FirstRunPrev"),
|
||||||
|
Anchor = AnchorStyles.Left | AnchorStyles.Bottom,
|
||||||
|
Visible = false,
|
||||||
|
Location = new Point(6, ClientSize.Height - 29),
|
||||||
|
};
|
||||||
|
PrevBtn.Click += PrevBtn_Click;
|
||||||
|
Controls.Add(PrevBtn);
|
||||||
|
|
||||||
|
WorkArea = new Panel {
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
};
|
||||||
|
Controls.Add(WorkArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrevBtn_Click(object sender, EventArgs e) {
|
||||||
|
if(!PrevVisible)
|
||||||
|
return;
|
||||||
|
WorkArea.Controls.Clear();
|
||||||
|
if(PrevAct == null)
|
||||||
|
Close();
|
||||||
|
else
|
||||||
|
Invoke(PrevAct);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NextBtn_Click(object sender, EventArgs e) {
|
||||||
|
if(!NextVisible)
|
||||||
|
return;
|
||||||
|
WorkArea.Controls.Clear();
|
||||||
|
if(NextAct == null)
|
||||||
|
Close();
|
||||||
|
else
|
||||||
|
Invoke(NextAct);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnShown(EventArgs e) {
|
||||||
|
base.OnShown(e);
|
||||||
|
Update();
|
||||||
|
Thread.Sleep(500);
|
||||||
|
ShowPageIntro();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFormClosing(FormClosingEventArgs e) {
|
||||||
|
if(e.CloseReason == CloseReason.UserClosing && !CanClose) {
|
||||||
|
e.Cancel = true;
|
||||||
|
|
||||||
|
if(!IsClosing) {
|
||||||
|
IsClosing = true;
|
||||||
|
|
||||||
|
SetHeight(80, new Action(() => {
|
||||||
|
CanClose = true;
|
||||||
|
Thread.Sleep(100);
|
||||||
|
Close();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnFormClosing(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetHeight(int height, Action onFinish = null) {
|
||||||
|
if(height < 80)
|
||||||
|
throw new ArgumentException(@"target height must be more than or equal to 80.", nameof(height));
|
||||||
|
|
||||||
|
if(IsSizing)
|
||||||
|
return;
|
||||||
|
IsSizing = true;
|
||||||
|
|
||||||
|
const int timeout = 1000 / 60;
|
||||||
|
double time = 0;
|
||||||
|
double period = timeout / 400d;
|
||||||
|
|
||||||
|
int currentHeight = ClientSize.Height;
|
||||||
|
int currentY = Location.Y;
|
||||||
|
int diffHeight = height - currentHeight;
|
||||||
|
int diffY = diffHeight / 2;
|
||||||
|
|
||||||
|
Action setHeight = new Action(() => {
|
||||||
|
int newHeight = currentHeight + (int)Math.Ceiling(time * diffHeight);
|
||||||
|
int newY = currentY - (int)Math.Ceiling(time * diffY);
|
||||||
|
ClientSize = new Size(ClientSize.Width, newHeight);
|
||||||
|
Location = new Point(Location.X, newY);
|
||||||
|
});
|
||||||
|
|
||||||
|
new Thread(() => {
|
||||||
|
Stopwatch sw = new Stopwatch();
|
||||||
|
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
sw.Restart();
|
||||||
|
|
||||||
|
Invoke(setHeight);
|
||||||
|
time += period;
|
||||||
|
|
||||||
|
int delay = timeout - (int)sw.ElapsedMilliseconds;
|
||||||
|
if(delay > 1)
|
||||||
|
Thread.Sleep(delay);
|
||||||
|
} while(time < 1d + period);
|
||||||
|
} finally {
|
||||||
|
sw.Stop();
|
||||||
|
if(onFinish != null)
|
||||||
|
Invoke(onFinish);
|
||||||
|
IsSizing = false;
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
IsBackground = true,
|
||||||
|
Priority = ThreadPriority.AboveNormal,
|
||||||
|
}.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowPageIntro() {
|
||||||
|
Text = Locale.String(@"FirstRunWelcomeTitle");
|
||||||
|
PrevVisible = false;
|
||||||
|
NextVisible = true;
|
||||||
|
NextAct = ShowPageHotKey;
|
||||||
|
|
||||||
|
SetHeight(190, new Action(() => {
|
||||||
|
WorkArea.Controls.Add(new Label {
|
||||||
|
Text = Locale.String(@"FirstRunWelcomeIntro"),
|
||||||
|
Location = new Point(10, 90),
|
||||||
|
Size = new Size(ClientSize.Width - 20, 200),
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowPageHotKey() {
|
||||||
|
Text = Locale.String(@"FirstRunHotKeyTitle");
|
||||||
|
PrevVisible = NextVisible = true;
|
||||||
|
PrevAct = ShowPageIntro;
|
||||||
|
NextAct = () => {
|
||||||
|
Program.SetForegroundHotKey(Settings.Get(Program.FOREGROUND_HOTKEY_SETTING, 0));
|
||||||
|
ShowPageElevation();
|
||||||
|
};
|
||||||
|
|
||||||
|
SetHeight(230, new Action(() => {
|
||||||
|
WorkArea.Controls.Add(new Label {
|
||||||
|
Text = Locale.String(@"FirstRunHotKeyExplain"),
|
||||||
|
Location = new Point(10, 90),
|
||||||
|
Size = new Size(ClientSize.Width - 20, 40),
|
||||||
|
});
|
||||||
|
|
||||||
|
SettingsWindow.CreateHotKeyInput(
|
||||||
|
WorkArea,
|
||||||
|
() => Settings.Get(Program.FOREGROUND_HOTKEY_SETTING, 0),
|
||||||
|
keyCode => Settings.Set(Program.FOREGROUND_HOTKEY_SETTING, keyCode),
|
||||||
|
0,
|
||||||
|
110
|
||||||
|
);
|
||||||
|
|
||||||
|
CheckBox flShowNotification = new CheckBox {
|
||||||
|
Text = Locale.String(@"FirstRunHotKeyNotify"),
|
||||||
|
Location = new Point(12, 170),
|
||||||
|
Checked = Settings.Get(Program.TOGGLE_BALLOON_SETTING, Program.ToggleBalloonDefault),
|
||||||
|
AutoSize = true,
|
||||||
|
TabIndex = 201,
|
||||||
|
};
|
||||||
|
flShowNotification.CheckedChanged += (s, e) => {
|
||||||
|
Settings.Set(Program.TOGGLE_BALLOON_SETTING, flShowNotification.Checked);
|
||||||
|
};
|
||||||
|
WorkArea.Controls.Add(flShowNotification);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowPageElevation() {
|
||||||
|
Text = Locale.String(@"FirstRunAdminTitle");
|
||||||
|
PrevVisible = NextVisible = true;
|
||||||
|
PrevAct = ShowPageHotKey;
|
||||||
|
NextAct = ShowPageThanks;
|
||||||
|
|
||||||
|
SetHeight(280, () => {
|
||||||
|
WorkArea.Controls.Add(new Label {
|
||||||
|
Text = Locale.String(@"FirstRunAdminExplain"),
|
||||||
|
Location = new Point(10, 90),
|
||||||
|
Size = new Size(ClientSize.Width - 20, 40),
|
||||||
|
});
|
||||||
|
|
||||||
|
bool alwaysAdmin = Settings.Get(Program.ALWAYS_ADMIN_SETTING, false);
|
||||||
|
bool implicitAdmin = Settings.Get(Program.ALWAYS_RETRY_ELEVATED, false);
|
||||||
|
|
||||||
|
RadioButton rdAsk = new RadioButton {
|
||||||
|
Text = Locale.String(@"FirstRunAdminOptionAsk"),
|
||||||
|
Location = new Point(10, 140),
|
||||||
|
Size = new Size(ClientSize.Width - 20, 30),
|
||||||
|
Appearance = Appearance.Button,
|
||||||
|
Checked = !alwaysAdmin && !implicitAdmin,
|
||||||
|
};
|
||||||
|
rdAsk.CheckedChanged += (s, e) => {
|
||||||
|
if(rdAsk.Checked) {
|
||||||
|
Settings.Set(Program.ALWAYS_ADMIN_SETTING, false);
|
||||||
|
Settings.Set(Program.ALWAYS_RETRY_ELEVATED, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
WorkArea.Controls.Add(rdAsk);
|
||||||
|
|
||||||
|
RadioButton rdImplicit = new RadioButton {
|
||||||
|
Text = Locale.String(@"FirstRunAdminOptionImplicit"),
|
||||||
|
Location = new Point(rdAsk.Location.X, rdAsk.Location.Y + 36),
|
||||||
|
Size = rdAsk.Size,
|
||||||
|
Appearance = rdAsk.Appearance,
|
||||||
|
Checked = implicitAdmin && !alwaysAdmin,
|
||||||
|
};
|
||||||
|
rdImplicit.CheckedChanged += (s, e) => {
|
||||||
|
if(rdImplicit.Checked) {
|
||||||
|
Settings.Set(Program.ALWAYS_ADMIN_SETTING, false);
|
||||||
|
Settings.Set(Program.ALWAYS_RETRY_ELEVATED, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
WorkArea.Controls.Add(rdImplicit);
|
||||||
|
|
||||||
|
RadioButton rdAlways = new RadioButton {
|
||||||
|
Text = Locale.String(@"FirstRunAdminOptionAlways"),
|
||||||
|
Location = new Point(rdAsk.Location.X, rdImplicit.Location.Y + 36),
|
||||||
|
Size = rdAsk.Size,
|
||||||
|
Appearance = rdAsk.Appearance,
|
||||||
|
Checked = alwaysAdmin,
|
||||||
|
};
|
||||||
|
rdAlways.CheckedChanged += (s, e) => {
|
||||||
|
if(rdAlways.Checked) {
|
||||||
|
Settings.Set(Program.ALWAYS_ADMIN_SETTING, true);
|
||||||
|
Settings.Set(Program.ALWAYS_RETRY_ELEVATED, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
WorkArea.Controls.Add(rdAlways);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowPageThanks() {
|
||||||
|
Text = Locale.String(@"FirstRunThanksTitle");
|
||||||
|
PrevVisible = NextVisible = true;
|
||||||
|
PrevAct = ShowPageElevation;
|
||||||
|
NextAct = CheckRestartNeeded;
|
||||||
|
|
||||||
|
SetHeight(270, () => {
|
||||||
|
Label thankYou = new Label {
|
||||||
|
Text = Locale.String(@"FirstRunThanksThank"),
|
||||||
|
Location = new Point(10, 90),
|
||||||
|
Size = new Size(ClientSize.Width - 20, 20),
|
||||||
|
};
|
||||||
|
WorkArea.Controls.Add(thankYou);
|
||||||
|
|
||||||
|
string updateLinkString = Locale.String(@"FirstRunThanksUpdate");
|
||||||
|
|
||||||
|
int websiteStart = updateLinkString.IndexOf(@"[WEB]");
|
||||||
|
updateLinkString = updateLinkString.Substring(0, websiteStart) + updateLinkString.Substring(websiteStart + 5);
|
||||||
|
int websiteEnd = updateLinkString.IndexOf(@"[/WEB]");
|
||||||
|
updateLinkString = updateLinkString.Substring(0, websiteEnd) + updateLinkString.Substring(websiteEnd + 6);
|
||||||
|
|
||||||
|
int changelogStart = updateLinkString.IndexOf(@"[CHANGELOG]");
|
||||||
|
updateLinkString = updateLinkString.Substring(0, changelogStart) + updateLinkString.Substring(changelogStart + 11);
|
||||||
|
int changelogEnd = updateLinkString.IndexOf(@"[/CHANGELOG]");
|
||||||
|
updateLinkString = updateLinkString.Substring(0, changelogEnd) + updateLinkString.Substring(changelogEnd + 12);
|
||||||
|
|
||||||
|
LinkLabel updateLink;
|
||||||
|
WorkArea.Controls.Add(updateLink = new LinkLabel {
|
||||||
|
Text = updateLinkString,
|
||||||
|
Location = new Point(10, 120),
|
||||||
|
Size = new Size(ClientSize.Width - 20, 34),
|
||||||
|
Font = thankYou.Font,
|
||||||
|
Links = {
|
||||||
|
new LinkLabel.Link(websiteStart, websiteEnd - websiteStart, @"https://flash.moe/topmostfriend"),
|
||||||
|
new LinkLabel.Link(changelogStart, changelogEnd - changelogStart, @"https://flash.moe/topmostfriend/changelog.php"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
updateLink.LinkClicked += (s, e) => {
|
||||||
|
Process.Start((string)e.Link.LinkData);
|
||||||
|
};
|
||||||
|
|
||||||
|
string settingsLinkString = Locale.String(@"FirstRunThanksSettings");
|
||||||
|
|
||||||
|
int settingsStart = settingsLinkString.IndexOf(@"[SETTINGS]");
|
||||||
|
settingsLinkString = settingsLinkString.Substring(0, settingsStart) + settingsLinkString.Substring(settingsStart + 10);
|
||||||
|
int settingsEnd = settingsLinkString.IndexOf(@"[/SETTINGS]");
|
||||||
|
settingsLinkString = settingsLinkString.Substring(0, settingsEnd) + settingsLinkString.Substring(settingsEnd + 11);
|
||||||
|
|
||||||
|
LinkLabel settingsLink;
|
||||||
|
WorkArea.Controls.Add(settingsLink = new LinkLabel {
|
||||||
|
Text = settingsLinkString,
|
||||||
|
Location = new Point(10, 160),
|
||||||
|
Size = new Size(ClientSize.Width - 20, 30),
|
||||||
|
Font = thankYou.Font,
|
||||||
|
Links = {
|
||||||
|
new LinkLabel.Link(settingsStart, settingsEnd - settingsStart),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
settingsLink.LinkClicked += (s, e) => {
|
||||||
|
SettingsWindow.Display();
|
||||||
|
};
|
||||||
|
|
||||||
|
WorkArea.Controls.Add(new Label {
|
||||||
|
Text = Locale.String(@"FirstRunThanksAdmin"),
|
||||||
|
Location = new Point(10, 200),
|
||||||
|
Size = new Size(ClientSize.Width - 20, 80),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CheckRestartNeeded() {
|
||||||
|
if(Settings.Get(Program.ALWAYS_ADMIN_SETTING, false))
|
||||||
|
UAC.RestartElevated();
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
TopMostFriend/Languages/Language.cs
Normal file
22
TopMostFriend/Languages/Language.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace TopMostFriend.Languages {
|
||||||
|
[XmlRoot(@"Language")]
|
||||||
|
public class Language {
|
||||||
|
[XmlElement(@"Info")]
|
||||||
|
public LanguageInfo Info { get; set; }
|
||||||
|
|
||||||
|
[XmlArray(@"Strings")]
|
||||||
|
[XmlArrayItem(@"String", Type = typeof(LanguageString))]
|
||||||
|
public LanguageString[] Strings { get; set; }
|
||||||
|
|
||||||
|
public LanguageString GetString(string name) {
|
||||||
|
if(name == null)
|
||||||
|
throw new ArgumentNullException(nameof(name));
|
||||||
|
return Strings.FirstOrDefault(s => name.Equals(s.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
TopMostFriend/Languages/LanguageInfo.cs
Normal file
21
TopMostFriend/Languages/LanguageInfo.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace TopMostFriend.Languages {
|
||||||
|
public class LanguageInfo {
|
||||||
|
[XmlElement(@"Id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[XmlElement(@"NameNative")]
|
||||||
|
public string NameNative { get; set; }
|
||||||
|
|
||||||
|
[XmlElement(@"NameEnglish")]
|
||||||
|
public string NameEnglish { get; set; }
|
||||||
|
|
||||||
|
[XmlElement(@"TargetVersion")]
|
||||||
|
public string TargetVersion { get; set; }
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return $@"{NameNative} / {NameEnglish} ({Id})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
TopMostFriend/Languages/LanguageString.cs
Normal file
19
TopMostFriend/Languages/LanguageString.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace TopMostFriend.Languages {
|
||||||
|
public class LanguageString {
|
||||||
|
[XmlAttribute(@"name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[XmlText]
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
public string Format(params object[] args) {
|
||||||
|
return string.Format(Value, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return $@"{Name}: {Value}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
109
TopMostFriend/Languages/en-GB.xml
Normal file
109
TopMostFriend/Languages/en-GB.xml
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Language>
|
||||||
|
<Info>
|
||||||
|
<Id>en-GB</Id>
|
||||||
|
<NameNative>British English</NameNative>
|
||||||
|
<NameEnglish>British English</NameEnglish>
|
||||||
|
<TargetVersion>1.6.0</TargetVersion>
|
||||||
|
</Info>
|
||||||
|
<Strings>
|
||||||
|
<String name="AlreadyRunning">An instance of {0} is already running.</String>
|
||||||
|
|
||||||
|
<String name="TrayRefresh">&Refresh</String>
|
||||||
|
<String name="TraySettings">&Settings</String>
|
||||||
|
<String name="TrayAbout">&About</String>
|
||||||
|
<String name="TrayQuit">&Quit</String>
|
||||||
|
|
||||||
|
<String name="NotifyOnTop">Now always on top</String>
|
||||||
|
<String name="NotifyNoLonger">No longer always on top</String>
|
||||||
|
<String name="NotifyNoTitle">Window has no title.</String>
|
||||||
|
|
||||||
|
<String name="ErrUnableAlterStatus1">Wasn't able to change always on top status on this window.</String>
|
||||||
|
<String name="ErrUnableAlterStatus2">Do you want to try again as an Administrator? A User Account Control dialog will pop up after selecting Yes.</String>
|
||||||
|
<String name="ErrUnableAlterStatusProtected">{0} was still unable to change always on top status for the window. It might be protected by Windows.</String>
|
||||||
|
|
||||||
|
<String name="AboutTitle">About {0}</String>
|
||||||
|
<String name="AboutClose">Close</String>
|
||||||
|
<String name="AboutWebsite">Website</String>
|
||||||
|
<String name="AboutDonate">Donate</String>
|
||||||
|
|
||||||
|
<String name="SettingsTitle">{0} Settings</String>
|
||||||
|
<String name="SettingsApply">Apply</String>
|
||||||
|
<String name="SettingsCancel">Cancel</String>
|
||||||
|
<String name="SettingsOk">OK</String>
|
||||||
|
|
||||||
|
<String name="SettingsHotKeysTitle">Hot Keys</String>
|
||||||
|
<String name="SettingsHotKeysReset">Reset</String>
|
||||||
|
<String name="SettingsHotKeysToggle">Toggle always on top status on active window</String>
|
||||||
|
|
||||||
|
<String name="SettingsOptionsTitle">Options</String>
|
||||||
|
<String name="SettingsOptionsToggleNotify">Show notification when using toggle hot key</String>
|
||||||
|
<String name="SettingsOptionsToggleNotifyIcon">Show icon of window affected by hot key</String>
|
||||||
|
<String name="SettingsOptionsElevatedRetry">Always retry changing always on top status as Administrator on first failure</String>
|
||||||
|
<String name="SettingsOptionsShiftBlacklist">SHIFT+CLICK items in the tray area list to add to the title blacklist</String>
|
||||||
|
<String name="SettingsOptionsRevertOnExit">Revert status to before {0} altered them on exit</String>
|
||||||
|
<String name="SettingsOptionsShowTrayList">Show list of open windows in the tray area menu</String>
|
||||||
|
<String name="SettingsOptionsAlwaysAdmin">Always run as Administrator</String>
|
||||||
|
|
||||||
|
<String name="SettingsLanguageTitle">Language</String>
|
||||||
|
<String name="SettingsLanguageChangedInfo">You should restart {0} for the language change to fully take effect. A lot of text will still appear in the previously selected language.</String>
|
||||||
|
|
||||||
|
<String name="SettingsOtherTitle">Other</String>
|
||||||
|
<String name="SettingsOtherBlacklistButton">Manage Blacklist...</String>
|
||||||
|
<String name="SettingsOtherBlacklistWindowTitle">Title Blacklist</String>
|
||||||
|
<String name="SettingsOtherStartupButton">Start with Windows...</String>
|
||||||
|
<String name="SettingsOtherStartupConfirm">
|
||||||
|
Should {0} start with Windows?
|
||||||
|
Clicking Yes will create a shortcut to the {0} in your Start-up folder, clicking No will delete the shortcut.
|
||||||
|
Make sure you've placed your {0} executable in a permanent location before clicking Yes.
|
||||||
|
</String>
|
||||||
|
<String name="SettingsOtherResetButton">Reset All Settings...</String>
|
||||||
|
<String name="SettingsOtherResetConfirm">
|
||||||
|
This will reset all {0} settings and restart the application.
|
||||||
|
Are you absolutely sure?
|
||||||
|
</String>
|
||||||
|
|
||||||
|
<String name="BlacklistAdd">Add</String>
|
||||||
|
<String name="BlacklistEdit">Edit</String>
|
||||||
|
<String name="BlacklistRemove">Remove</String>
|
||||||
|
<String name="BlacklistCancel">Cancel</String>
|
||||||
|
<String name="BlacklistDone">Done</String>
|
||||||
|
|
||||||
|
<String name="BlacklistEditorAdding">Adding new entry...</String>
|
||||||
|
<String name="BlacklistEditorEditing">Editing {0}...</String>
|
||||||
|
<String name="BlacklistEditorCancel">Cancel</String>
|
||||||
|
<String name="BlacklistEditorSave">Save</String>
|
||||||
|
|
||||||
|
<String name="FirstRunNext">Next</String>
|
||||||
|
<String name="FirstRunPrev">Previous</String>
|
||||||
|
|
||||||
|
<String name="FirstRunWelcomeTitle">Welcome to {0}!</String>
|
||||||
|
<String name="FirstRunWelcomeIntro">
|
||||||
|
{0} is a utility that lets you manage the always-on-top state of windows from programs you have open.
|
||||||
|
|
||||||
|
You will now be taken through a few steps to configure {0} to your liking!
|
||||||
|
</String>
|
||||||
|
|
||||||
|
<String name="FirstRunHotKeyTitle">Selecting a hot key</String>
|
||||||
|
<String name="FirstRunHotKeyExplain">
|
||||||
|
Select a global hot key for toggling the always on top status of whatever window is currently in the foreground.
|
||||||
|
If you don't wish to specify one just hit Reset followed by Next.
|
||||||
|
</String>
|
||||||
|
<String name="FirstRunHotKeyNotify">Show a notification when the hot key has been used</String>
|
||||||
|
|
||||||
|
<String name="FirstRunAdminTitle">Administrator actions</String>
|
||||||
|
<String name="FirstRunAdminExplain">
|
||||||
|
Sometimes {0} is not able to change the always on top state for certain windows without having administrative privileges.
|
||||||
|
{0} provides multiple options for this situation:
|
||||||
|
</String>
|
||||||
|
<String name="FirstRunAdminOptionAsk">Ask me what to do when it's required.</String>
|
||||||
|
<String name="FirstRunAdminOptionImplicit">Ask for administrative privileges automatically when required.</String>
|
||||||
|
<String name="FirstRunAdminOptionAlways">Always run {0} as Administrator (not recommended).</String>
|
||||||
|
|
||||||
|
<String name="FirstRunThanksTitle">Thank you!</String>
|
||||||
|
<String name="FirstRunThanksThank">Thank you for using {0}!</String>
|
||||||
|
<String name="FirstRunThanksUpdate">Be sure to check the {0} [WEB]website[/WEB] and [CHANGELOG]changelog[/CHANGELOG] for updates from time to time.</String>
|
||||||
|
<String name="FirstRunThanksSettings">There are more options you may be interested in taking a look at in the [SETTINGS]Settings[/SETTINGS] window.</String>
|
||||||
|
<String name="FirstRunThanksAdmin">If you have chosen to always run {0} as Administrator, you will receive a User Account Control prompt after hitting next.</String>
|
||||||
|
</Strings>
|
||||||
|
</Language>
|
109
TopMostFriend/Languages/nl-NL.xml
Normal file
109
TopMostFriend/Languages/nl-NL.xml
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Language>
|
||||||
|
<Info>
|
||||||
|
<Id>nl-NL</Id>
|
||||||
|
<NameNative>Nederlands</NameNative>
|
||||||
|
<NameEnglish>Dutch</NameEnglish>
|
||||||
|
<TargetVersion>1.6.0</TargetVersion>
|
||||||
|
</Info>
|
||||||
|
<Strings>
|
||||||
|
<String name="AlreadyRunning">{0} is al gestart.</String>
|
||||||
|
|
||||||
|
<String name="TrayRefresh">&Verversen</String>
|
||||||
|
<String name="TraySettings">&Instellingen</String>
|
||||||
|
<String name="TrayAbout">&Over</String>
|
||||||
|
<String name="TrayQuit">&Sluiten</String>
|
||||||
|
|
||||||
|
<String name="NotifyOnTop">Nu altijd op voorgrond</String>
|
||||||
|
<String name="NotifyNoLonger">Niet langer altijd op voorgrond</String>
|
||||||
|
<String name="NotifyNoTitle">Venster heeft geen titel.</String>
|
||||||
|
|
||||||
|
<String name="ErrUnableAlterStatus1">Het was niet mogelijk om de altijd op voorgrond status van dit venster te veranderen.</String>
|
||||||
|
<String name="ErrUnableAlterStatus2">Wil je het opnieuw proberen als Administrator? Een Gebruikersaccountbeheer dialoog zal verschijnen als je op Ja klikt.</String>
|
||||||
|
<String name="ErrUnableAlterStatusProtected">{0} kon nog steeds niet de altijd op voorgrond status van dit venster veranderen. Het wordt mogelijk beschermd door Windows.</String>
|
||||||
|
|
||||||
|
<String name="AboutTitle">Over {0}</String>
|
||||||
|
<String name="AboutClose">Sluiten</String>
|
||||||
|
<String name="AboutWebsite">Website</String>
|
||||||
|
<String name="AboutDonate">Doneer</String>
|
||||||
|
|
||||||
|
<String name="SettingsTitle">{0} Instellingen</String>
|
||||||
|
<String name="SettingsApply">Toepassen</String>
|
||||||
|
<String name="SettingsCancel">Annuleren</String>
|
||||||
|
<String name="SettingsOk">OK</String>
|
||||||
|
|
||||||
|
<String name="SettingsHotKeysTitle">Sneltoetsen</String>
|
||||||
|
<String name="SettingsHotKeysReset">Herstel</String>
|
||||||
|
<String name="SettingsHotKeysToggle">Schakel altijd op voorgrond status op actief venster</String>
|
||||||
|
|
||||||
|
<String name="SettingsOptionsTitle">Opties</String>
|
||||||
|
<String name="SettingsOptionsToggleNotify">Toon notificatie als de sneltoets gebruikt is</String>
|
||||||
|
<String name="SettingsOptionsToggleNotifyIcon">Toon icoon van venster dat beïnvloed was door de sneltoets</String>
|
||||||
|
<String name="SettingsOptionsElevatedRetry">Probeer altijd opnieuw als Administrator bij de eerste mislukking van het veranderen van de status</String>
|
||||||
|
<String name="SettingsOptionsShiftBlacklist">SHIFT+CLICK items in de systeemvak lijst om ze toe te voegen aan de titel blacklist</String>
|
||||||
|
<String name="SettingsOptionsRevertOnExit">Herstel status naar voordat {0} ze heeft aangepast tijdens het sluiten</String>
|
||||||
|
<String name="SettingsOptionsShowTrayList">Geef lijst met open venster weer in het systeemvak menu</String>
|
||||||
|
<String name="SettingsOptionsAlwaysAdmin">Start altijd als Administrator</String>
|
||||||
|
|
||||||
|
<String name="SettingsLanguageTitle">Taal (Language)</String>
|
||||||
|
<String name="SettingsLanguageChangedInfo">Je moet {0} opnieuw starten om de verandering van de taal volledig effect te laten nemen. Veel tekst zal nog steeds verschijnen in de voorheen geselecteerde taal.</String>
|
||||||
|
|
||||||
|
<String name="SettingsOtherTitle">Overig</String>
|
||||||
|
<String name="SettingsOtherBlacklistButton">Beheer Blacklist...</String>
|
||||||
|
<String name="SettingsOtherBlacklistWindowTitle">Titel Blacklist</String>
|
||||||
|
<String name="SettingsOtherStartupButton">Start met Windows...</String>
|
||||||
|
<String name="SettingsOtherStartupConfirm">
|
||||||
|
Moet {0} tegelijkertijd met Windows starten?
|
||||||
|
Als je op Ja klikt zal een een snelkoppeling aangemaakt worden in de Opstarten map van het start menu, als je op Nee klikt wordt de snelkoppeling verwijderd.
|
||||||
|
Zorg ervoor dat je het EXE bestand voor {0} in een permanente locatie hebt voordat je op Ja klikt.
|
||||||
|
</String>
|
||||||
|
<String name="SettingsOtherResetButton">Herstel alle instellingen...</String>
|
||||||
|
<String name="SettingsOtherResetConfirm">
|
||||||
|
Dit zal alle instellingen verwijderen en het programma opnieuw opstarten.
|
||||||
|
Weet je het absoluut zeker?
|
||||||
|
</String>
|
||||||
|
|
||||||
|
<String name="BlacklistAdd">Toevoegen</String>
|
||||||
|
<String name="BlacklistEdit">Bewerken</String>
|
||||||
|
<String name="BlacklistRemove">Verwijderen</String>
|
||||||
|
<String name="BlacklistCancel">Annuleren</String>
|
||||||
|
<String name="BlacklistDone">Klaar</String>
|
||||||
|
|
||||||
|
<String name="BlacklistEditorAdding">Nieuw item toevoegen...</String>
|
||||||
|
<String name="BlacklistEditorEditing">{0} bewerken...</String>
|
||||||
|
<String name="BlacklistEditorCancel">Annuleren</String>
|
||||||
|
<String name="BlacklistEditorSave">Opslaan</String>
|
||||||
|
|
||||||
|
<String name="FirstRunNext">Volgende</String>
|
||||||
|
<String name="FirstRunPrev">Vorige</String>
|
||||||
|
|
||||||
|
<String name="FirstRunWelcomeTitle">Welkom bij {0}!</String>
|
||||||
|
<String name="FirstRunWelcomeIntro">
|
||||||
|
{0} is een hulpprogramma dat jou controle geeft over de altijd-op-voorgrond status van programma's die je open hebt.
|
||||||
|
|
||||||
|
Je zal nu door een aantal stappen genomen worden om {0} naar jouw wens te configureren!
|
||||||
|
</String>
|
||||||
|
|
||||||
|
<String name="FirstRunHotKeyTitle">Sneltoets selecteren</String>
|
||||||
|
<String name="FirstRunHotKeyExplain">
|
||||||
|
Selecteer een globale sneltoets voor het wijzigen van de altijd op voorgrond status van het venster dat op dat moment in de voorgrond staat.
|
||||||
|
Als je geen sneltoets toe wil wijzen, druk op Herstel en vervolgens op Volgende.
|
||||||
|
</String>
|
||||||
|
<String name="FirstRunHotKeyNotify">Toon een melding wanneer de sneltoets is gebruikt</String>
|
||||||
|
|
||||||
|
<String name="FirstRunAdminTitle">Administrator acties</String>
|
||||||
|
<String name="FirstRunAdminExplain">
|
||||||
|
Soms kan {0} niet de altijd op voorgrond status van bepaalde vensters aanpassen omdat daar administratieve rechten voor nodig zijn.
|
||||||
|
{0} geeft je de volgende opties voor deze situatie:
|
||||||
|
</String>
|
||||||
|
<String name="FirstRunAdminOptionAsk">Vraag mij wat te doen wanneer het nodig is.</String>
|
||||||
|
<String name="FirstRunAdminOptionImplicit">Vraag mij automatisch om administratieve rechten wanneer het nodig is.</String>
|
||||||
|
<String name="FirstRunAdminOptionAlways">Start {0} altijd als Administrator (niet aanbevolen).</String>
|
||||||
|
|
||||||
|
<String name="FirstRunThanksTitle">Bedankt!</String>
|
||||||
|
<String name="FirstRunThanksThank">Bedankt voor het gebruiken van {0}!</String>
|
||||||
|
<String name="FirstRunThanksUpdate">Controlleer de {0} [WEB]website[/WEB] en [CHANGELOG]changelog[/CHANGELOG] eens in de zoveel tijd om te kijken of er updates zijn.</String>
|
||||||
|
<String name="FirstRunThanksSettings">Naast de opties die je al gekregen hebt, zijn er nog meer beschikbaar in het [SETTINGS]Instellingen[/SETTINGS] venster als je daarin geïnteresseerd bent.</String>
|
||||||
|
<String name="FirstRunThanksAdmin">Als je gekozen hebt om {0} altijd als Administrator te starten, zal je een Gebruikersaccountbeheer dialoog zien nadat je op volgende klikt.</String>
|
||||||
|
</Strings>
|
||||||
|
</Language>
|
89
TopMostFriend/Locale.cs
Normal file
89
TopMostFriend/Locale.cs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using TopMostFriend.Languages;
|
||||||
|
|
||||||
|
namespace TopMostFriend {
|
||||||
|
public static class Locale {
|
||||||
|
public const string DEFAULT = @"en-GB";
|
||||||
|
private static XmlSerializer Serializer { get; }
|
||||||
|
private static Dictionary<string, Language> Languages { get; }
|
||||||
|
private static Language ActiveLanguage { get; set; }
|
||||||
|
|
||||||
|
static Locale() {
|
||||||
|
Serializer = new XmlSerializer(typeof(Language));
|
||||||
|
Languages = new Dictionary<string, Language>();
|
||||||
|
Assembly currentAsm = Assembly.GetExecutingAssembly();
|
||||||
|
string[] resources = currentAsm.GetManifestResourceNames();
|
||||||
|
|
||||||
|
foreach(string resource in resources)
|
||||||
|
if(resource.StartsWith(@"TopMostFriend.Languages.") && resource.EndsWith(@".xml"))
|
||||||
|
using(Stream resourceStream = currentAsm.GetManifestResourceStream(resource))
|
||||||
|
LoadLanguage(resourceStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string LoadLanguage(Stream stream) {
|
||||||
|
Language lang = (Language)Serializer.Deserialize(stream);
|
||||||
|
foreach(LanguageString ls in lang.Strings)
|
||||||
|
ls.Value = ls.Value.Trim();
|
||||||
|
|
||||||
|
Languages.Add(lang.Info.Id, lang);
|
||||||
|
if(ActiveLanguage == null && DEFAULT.Equals(lang.Info.Id))
|
||||||
|
ActiveLanguage = lang;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Debug.WriteLine(@" ==========");
|
||||||
|
Debug.WriteLine(lang.Info);
|
||||||
|
foreach(LanguageString str in lang.Strings)
|
||||||
|
Debug.WriteLine(str);
|
||||||
|
Debug.WriteLine(string.Empty);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return lang.Info.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LanguageInfo GetCurrentLanguage() {
|
||||||
|
return ActiveLanguage.Info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LanguageInfo[] GetAvailableLanguages() {
|
||||||
|
return Languages.Values.Select(l => l.Info).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPreferredLanguage() {
|
||||||
|
return Settings.Has(Program.LANGUAGE)
|
||||||
|
? Settings.Get(Program.LANGUAGE, DEFAULT)
|
||||||
|
: CultureInfo.InstalledUICulture.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetLanguage(string langId) {
|
||||||
|
if(!Languages.ContainsKey(langId))
|
||||||
|
langId = DEFAULT;
|
||||||
|
ActiveLanguage = Languages[langId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetLanguage(LanguageInfo langInfo) {
|
||||||
|
SetLanguage(langInfo.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string String(string name, params object[] args) {
|
||||||
|
LanguageString str = ActiveLanguage.GetString(name);
|
||||||
|
if(str == null)
|
||||||
|
return name;
|
||||||
|
|
||||||
|
List<object> rargs = new List<object> { Program.TITLE };
|
||||||
|
rargs.AddRange(args);
|
||||||
|
|
||||||
|
return str.Format(rargs.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Meow() {
|
||||||
|
Debug.WriteLine(@"meow");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Principal;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
@ -17,6 +16,8 @@ namespace TopMostFriend {
|
||||||
private static HotKeyWindow HotKeys;
|
private static HotKeyWindow HotKeys;
|
||||||
private static Icon OriginalIcon;
|
private static Icon OriginalIcon;
|
||||||
|
|
||||||
|
public const string TITLE = @"Top Most Friend";
|
||||||
|
|
||||||
private const string GUID =
|
private const string GUID =
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@"{1A22D9CA-2AA9-48F2-B007-3A48CF205CDD}";
|
@"{1A22D9CA-2AA9-48F2-B007-3A48CF205CDD}";
|
||||||
|
@ -25,6 +26,8 @@ namespace TopMostFriend {
|
||||||
#endif
|
#endif
|
||||||
private static readonly Mutex GlobalMutex = new Mutex(true, GUID);
|
private static readonly Mutex GlobalMutex = new Mutex(true, GUID);
|
||||||
|
|
||||||
|
private const string CUSTOM_LANGUAGE = @"TopMostFriendLanguage.xml";
|
||||||
|
|
||||||
public const string FOREGROUND_HOTKEY_ATOM = @"{86795D64-770D-4BD6-AA26-FA638FBAABCF}";
|
public const string FOREGROUND_HOTKEY_ATOM = @"{86795D64-770D-4BD6-AA26-FA638FBAABCF}";
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
public const string FOREGROUND_HOTKEY_SETTING = @"ForegroundHotKey_DEBUG";
|
public const string FOREGROUND_HOTKEY_SETTING = @"ForegroundHotKey_DEBUG";
|
||||||
|
@ -44,6 +47,10 @@ namespace TopMostFriend {
|
||||||
public const string TITLE_BLACKLIST = @"TitleBlacklist";
|
public const string TITLE_BLACKLIST = @"TitleBlacklist";
|
||||||
public const string SHOW_HOTKEY_ICON = @"ShowHotkeyIcon";
|
public const string SHOW_HOTKEY_ICON = @"ShowHotkeyIcon";
|
||||||
public const string SHOW_WINDOW_LIST = @"ShowWindowList";
|
public const string SHOW_WINDOW_LIST = @"ShowWindowList";
|
||||||
|
public const string LAST_VERSION = @"LastVersion";
|
||||||
|
public const string ALWAYS_RETRY_ELEVATED = @"AlwaysRetryElevated";
|
||||||
|
public const string REVERT_ON_EXIT = @"RevertOnExit";
|
||||||
|
public const string LANGUAGE = @"Language";
|
||||||
|
|
||||||
private static ToolStripItem RefreshButton;
|
private static ToolStripItem RefreshButton;
|
||||||
private static ToolStripItem LastSelectedItem = null;
|
private static ToolStripItem LastSelectedItem = null;
|
||||||
|
@ -53,8 +60,39 @@ namespace TopMostFriend {
|
||||||
private static ToolStripItem[] ListActionItems;
|
private static ToolStripItem[] ListActionItems;
|
||||||
private static ToolStripItem[] AppActionItems;
|
private static ToolStripItem[] AppActionItems;
|
||||||
|
|
||||||
|
private static readonly Dictionary<IntPtr, bool> OriginalStates = new Dictionary<IntPtr, bool>();
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args) {
|
public static int Main(string[] args) {
|
||||||
|
Settings.Set(LAST_VERSION, Application.ProductVersion);
|
||||||
|
|
||||||
|
IEnumerable<string> cliToggleNew = args.Where(a => a.StartsWith(@"--toggle=")).Select(a => a.Substring(9));
|
||||||
|
if(cliToggleNew.Any()) {
|
||||||
|
bool is32bit = IntPtr.Size == 4;
|
||||||
|
|
||||||
|
foreach(string hwndStr in cliToggleNew) {
|
||||||
|
IntPtr hwnd;
|
||||||
|
if(is32bit) {
|
||||||
|
if(int.TryParse(hwndStr, out int hwnd32))
|
||||||
|
hwnd = new IntPtr(hwnd32);
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
if(long.TryParse(hwndStr, out long hwnd64))
|
||||||
|
hwnd = new IntPtr(hwnd64);
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass 0 to skip implicit FindOwnerId call
|
||||||
|
WindowInfo wi = new WindowInfo(hwnd, 0);
|
||||||
|
if(!wi.ToggleTopMost(!args.Contains($@"--background={hwndStr}")))
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(Environment.OSVersion.Version.Major >= 6)
|
if(Environment.OSVersion.Version.Major >= 6)
|
||||||
Win32.SetProcessDPIAware();
|
Win32.SetProcessDPIAware();
|
||||||
|
|
||||||
|
@ -64,26 +102,53 @@ namespace TopMostFriend {
|
||||||
if(args.Contains(@"--reset-admin"))
|
if(args.Contains(@"--reset-admin"))
|
||||||
Settings.Remove(ALWAYS_ADMIN_SETTING);
|
Settings.Remove(ALWAYS_ADMIN_SETTING);
|
||||||
|
|
||||||
string cliToggle = args.FirstOrDefault(x => x.StartsWith(@"--hwnd="));
|
string cliToggleOld = args.FirstOrDefault(a => a.StartsWith(@"--hwnd="))?.Substring(7);
|
||||||
if(!string.IsNullOrEmpty(cliToggle) && int.TryParse(cliToggle.Substring(7), out int cliToggleHWnd)) {
|
if(!string.IsNullOrEmpty(cliToggleOld)) {
|
||||||
WindowInfo cliWindow = new WindowInfo(cliToggleHWnd);
|
IntPtr cliToggleHWnd = IntPtr.Zero;
|
||||||
if(!cliWindow.ToggleTopMost())
|
if(IntPtr.Size == 4) {
|
||||||
TopMostFailed(cliWindow);
|
if(int.TryParse(cliToggleOld, out int hwnd32))
|
||||||
|
cliToggleHWnd = new IntPtr(hwnd32);
|
||||||
|
} else {
|
||||||
|
if(long.TryParse(cliToggleOld, out long hwnd64))
|
||||||
|
cliToggleHWnd = new IntPtr(hwnd64);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cliToggleHWnd != IntPtr.Zero) {
|
||||||
|
WindowInfo cliWindow = new WindowInfo(cliToggleHWnd);
|
||||||
|
if(!cliWindow.ToggleTopMost())
|
||||||
|
TopMostFailed(cliWindow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(args.Contains(@"--stop"))
|
if(args.Contains(@"--stop"))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
|
if(File.Exists(CUSTOM_LANGUAGE)) {
|
||||||
|
string customLanguage;
|
||||||
|
using(Stream s = File.OpenRead(CUSTOM_LANGUAGE))
|
||||||
|
try {
|
||||||
|
customLanguage = Locale.LoadLanguage(s);
|
||||||
|
} catch {
|
||||||
|
customLanguage = Locale.DEFAULT;
|
||||||
|
}
|
||||||
|
Locale.SetLanguage(customLanguage);
|
||||||
|
} else
|
||||||
|
Locale.SetLanguage(Locale.GetPreferredLanguage());
|
||||||
|
|
||||||
if(!GlobalMutex.WaitOne(0, true)) {
|
if(!GlobalMutex.WaitOne(0, true)) {
|
||||||
MessageBox.Show(@"An instance of Top Most Friend is already running.", @"Top Most Friend");
|
MessageBox.Show(Locale.String(@"AlreadyRunning"), TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isFirstRun = !Settings.Has(FOREGROUND_HOTKEY_SETTING);
|
||||||
|
|
||||||
Settings.SetDefault(FOREGROUND_HOTKEY_SETTING, 0);
|
Settings.SetDefault(FOREGROUND_HOTKEY_SETTING, 0);
|
||||||
Settings.SetDefault(ALWAYS_ADMIN_SETTING, false);
|
Settings.SetDefault(ALWAYS_ADMIN_SETTING, false);
|
||||||
Settings.SetDefault(SHIFT_CLICK_BLACKLIST, true);
|
Settings.SetDefault(SHIFT_CLICK_BLACKLIST, true);
|
||||||
Settings.SetDefault(SHOW_HOTKEY_ICON, true);
|
Settings.SetDefault(SHOW_HOTKEY_ICON, true);
|
||||||
Settings.SetDefault(SHOW_WINDOW_LIST, true);
|
Settings.SetDefault(SHOW_WINDOW_LIST, true);
|
||||||
|
Settings.SetDefault(ALWAYS_RETRY_ELEVATED, false);
|
||||||
|
Settings.SetDefault(REVERT_ON_EXIT, false);
|
||||||
// Defaulting to false on Windows 10 because it uses the stupid, annoying and intrusive new Android style notification system
|
// Defaulting to false on Windows 10 because it uses the stupid, annoying and intrusive new Android style notification system
|
||||||
// This would fucking piledrive the notification history and also just be annoying in general because intrusive
|
// This would fucking piledrive the notification history and also just be annoying in general because intrusive
|
||||||
Settings.SetDefault(TOGGLE_BALLOON_SETTING, ToggleBalloonDefault);
|
Settings.SetDefault(TOGGLE_BALLOON_SETTING, ToggleBalloonDefault);
|
||||||
|
@ -102,9 +167,9 @@ namespace TopMostFriend {
|
||||||
Settings.Set(TITLE_BLACKLIST, titles.ToArray());
|
Settings.Set(TITLE_BLACKLIST, titles.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Settings.Get<bool>(ALWAYS_ADMIN_SETTING) && !IsElevated()) {
|
if(Settings.Get<bool>(ALWAYS_ADMIN_SETTING) && !UAC.IsElevated) {
|
||||||
Elevate();
|
UAC.RestartElevated();
|
||||||
return;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
TitleBlacklist.Clear();
|
TitleBlacklist.Clear();
|
||||||
|
@ -134,19 +199,19 @@ namespace TopMostFriend {
|
||||||
CtxMenu.ItemClicked += CtxMenu_ItemClicked;
|
CtxMenu.ItemClicked += CtxMenu_ItemClicked;
|
||||||
ListActionItems = new ToolStripItem[] {
|
ListActionItems = new ToolStripItem[] {
|
||||||
new ToolStripSeparator(),
|
new ToolStripSeparator(),
|
||||||
RefreshButton = new ToolStripMenuItem(@"&Refresh", Properties.Resources.arrow_refresh, new EventHandler((s, e) => RefreshWindowList())),
|
RefreshButton = new ToolStripMenuItem(Locale.String(@"TrayRefresh"), Properties.Resources.arrow_refresh, new EventHandler((s, e) => RefreshWindowList())),
|
||||||
};
|
};
|
||||||
AppActionItems = new ToolStripItem[] {
|
AppActionItems = new ToolStripItem[] {
|
||||||
new ToolStripMenuItem(@"&Settings", Properties.Resources.cog, new EventHandler((s, e) => SettingsWindow.Display())),
|
new ToolStripMenuItem(Locale.String(@"TraySettings"), Properties.Resources.cog, new EventHandler((s, e) => SettingsWindow.Display())),
|
||||||
new ToolStripMenuItem(@"&About", Properties.Resources.help, new EventHandler((s, e) => AboutWindow.Display())),
|
new ToolStripMenuItem(Locale.String(@"TrayAbout"), Properties.Resources.help, new EventHandler((s, e) => AboutWindow.Display())),
|
||||||
new ToolStripMenuItem(@"&Quit", Properties.Resources.door_in, new EventHandler((s, e) => Application.Exit())),
|
new ToolStripMenuItem(Locale.String(@"TrayQuit"), Properties.Resources.door_in, new EventHandler((s, e) => Application.Exit())),
|
||||||
};
|
};
|
||||||
CtxMenu.Items.AddRange(AppActionItems);
|
CtxMenu.Items.AddRange(AppActionItems);
|
||||||
|
|
||||||
SysIcon = new NotifyIcon {
|
SysIcon = new NotifyIcon {
|
||||||
Visible = true,
|
Visible = true,
|
||||||
Icon = OriginalIcon,
|
Icon = OriginalIcon,
|
||||||
Text = @"Top Most Application Manager",
|
Text = TITLE,
|
||||||
};
|
};
|
||||||
SysIcon.ContextMenuStrip = CtxMenu;
|
SysIcon.ContextMenuStrip = CtxMenu;
|
||||||
SysIcon.MouseDown += SysIcon_MouseDown;
|
SysIcon.MouseDown += SysIcon_MouseDown;
|
||||||
|
@ -154,9 +219,26 @@ namespace TopMostFriend {
|
||||||
HotKeys = new HotKeyWindow();
|
HotKeys = new HotKeyWindow();
|
||||||
SetForegroundHotKey(Settings.Get<int>(FOREGROUND_HOTKEY_SETTING));
|
SetForegroundHotKey(Settings.Get<int>(FOREGROUND_HOTKEY_SETTING));
|
||||||
|
|
||||||
|
if(isFirstRun)
|
||||||
|
FirstRunWindow.Display();
|
||||||
|
|
||||||
Application.Run();
|
Application.Run();
|
||||||
|
|
||||||
|
if(Settings.Get(REVERT_ON_EXIT, false))
|
||||||
|
RevertTopMostStatus();
|
||||||
|
|
||||||
Shutdown();
|
Shutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RevertTopMostStatus() {
|
||||||
|
foreach(KeyValuePair<IntPtr, bool> originalState in OriginalStates) {
|
||||||
|
WindowInfo wi = new WindowInfo(originalState.Key);
|
||||||
|
if(wi.IsTopMost != originalState.Value)
|
||||||
|
if(!wi.ToggleTopMost(false))
|
||||||
|
TopMostFailed(wi, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddBlacklistedTitle(string title) {
|
public static void AddBlacklistedTitle(string title) {
|
||||||
|
@ -192,33 +274,6 @@ namespace TopMostFriend {
|
||||||
GlobalMutex.ReleaseMutex();
|
GlobalMutex.ReleaseMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool? IsElevatedValue;
|
|
||||||
|
|
||||||
public static bool IsElevated() {
|
|
||||||
if(!IsElevatedValue.HasValue) {
|
|
||||||
using(WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
|
||||||
IsElevatedValue = identity != null && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return IsElevatedValue.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Elevate(string args = null) {
|
|
||||||
if(IsElevated())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Shutdown();
|
|
||||||
|
|
||||||
Process.Start(new ProcessStartInfo {
|
|
||||||
UseShellExecute = true,
|
|
||||||
FileName = Application.ExecutablePath,
|
|
||||||
WorkingDirectory = Environment.CurrentDirectory,
|
|
||||||
Arguments = args ?? string.Empty,
|
|
||||||
Verb = @"runas",
|
|
||||||
});
|
|
||||||
Application.Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetForegroundHotKey(int keyCode) {
|
public static void SetForegroundHotKey(int keyCode) {
|
||||||
SetForegroundHotKey((Win32ModKeys)(keyCode & 0xFFFF), (Keys)((keyCode & 0xFFFF0000) >> 16));
|
SetForegroundHotKey((Win32ModKeys)(keyCode & 0xFFFF), (Keys)((keyCode & 0xFFFF0000) >> 16));
|
||||||
}
|
}
|
||||||
|
@ -270,8 +325,13 @@ namespace TopMostFriend {
|
||||||
if(Settings.Get(SHIFT_CLICK_BLACKLIST, true) && Control.ModifierKeys.HasFlag(Keys.Shift)) {
|
if(Settings.Get(SHIFT_CLICK_BLACKLIST, true) && Control.ModifierKeys.HasFlag(Keys.Shift)) {
|
||||||
AddBlacklistedTitle(title);
|
AddBlacklistedTitle(title);
|
||||||
SaveBlacklistedTitles();
|
SaveBlacklistedTitles();
|
||||||
} else if(!window.ToggleTopMost())
|
} else {
|
||||||
TopMostFailed(window);
|
if(window.ToggleTopMost()) {
|
||||||
|
if(!OriginalStates.ContainsKey(window.Handle))
|
||||||
|
OriginalStates[window.Handle] = !window.IsTopMost;
|
||||||
|
} else
|
||||||
|
TopMostFailed(window);
|
||||||
|
}
|
||||||
})) {
|
})) {
|
||||||
CheckOnClick = true,
|
CheckOnClick = true,
|
||||||
Checked = window.IsTopMost,
|
Checked = window.IsTopMost,
|
||||||
|
@ -287,50 +347,29 @@ namespace TopMostFriend {
|
||||||
CtxMenu.Items.AddRange(items.ToArray());
|
CtxMenu.Items.AddRange(items.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TopMostFailed(WindowInfo window) {
|
private static void TopMostFailed(WindowInfo window, bool switchWindow = true) {
|
||||||
MessageBoxButtons buttons = MessageBoxButtons.OK;
|
bool retryElevated = Settings.Get(ALWAYS_RETRY_ELEVATED, false),
|
||||||
StringBuilder sb = new StringBuilder();
|
isElevated = UAC.IsElevated;
|
||||||
sb.AppendLine(@"Wasn't able to change topmost status on this window.");
|
|
||||||
|
|
||||||
if(!IsElevated()) {
|
if(!retryElevated) {
|
||||||
sb.AppendLine(@"Do you want to restart Top Most Friend as administrator and try again?");
|
MessageBoxButtons buttons = MessageBoxButtons.OK;
|
||||||
buttons = MessageBoxButtons.YesNo;
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.AppendLine(Locale.String(@"ErrUnableAlterStatus1"));
|
||||||
|
|
||||||
|
if(!isElevated) {
|
||||||
|
sb.AppendLine(Locale.String(@"ErrUnableAlterStatus2"));
|
||||||
|
buttons = MessageBoxButtons.YesNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
retryElevated = MessageBox.Show(sb.ToString(), TITLE, buttons, MessageBoxIcon.Error) == DialogResult.Yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogResult result = MessageBox.Show(sb.ToString(), @"Top Most Friend", buttons, MessageBoxIcon.Error);
|
if(retryElevated) {
|
||||||
|
if(window.ToggleTopMostElevated(switchWindow)) {
|
||||||
if(result == DialogResult.Yes)
|
if(!OriginalStates.ContainsKey(window.Handle))
|
||||||
Elevate($@"--hwnd={window.Handle}");
|
OriginalStates[window.Handle] = !window.IsTopMost;
|
||||||
}
|
} else
|
||||||
|
MessageBox.Show(Locale.String(@"ErrUnableAlterStatusProtected"), TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
private class ActionTimeout {
|
|
||||||
private readonly Action Action;
|
|
||||||
private bool Continue = true;
|
|
||||||
private int Remaining = 0;
|
|
||||||
private const int STEP = 500;
|
|
||||||
|
|
||||||
public ActionTimeout(Action action, int timeout) {
|
|
||||||
Action = action ?? throw new ArgumentNullException(nameof(action));
|
|
||||||
if(timeout < 1)
|
|
||||||
throw new ArgumentException(@"Timeout must be a positive integer.", nameof(timeout));
|
|
||||||
Remaining = timeout;
|
|
||||||
new Thread(ThreadBody) { IsBackground = true }.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ThreadBody() {
|
|
||||||
do {
|
|
||||||
Thread.Sleep(STEP);
|
|
||||||
Remaining -= STEP;
|
|
||||||
|
|
||||||
if(!Continue)
|
|
||||||
return;
|
|
||||||
} while(Remaining > 0);
|
|
||||||
|
|
||||||
Action.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Cancel() {
|
|
||||||
Continue = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,8 +382,8 @@ namespace TopMostFriend {
|
||||||
if(Settings.Get(TOGGLE_BALLOON_SETTING, false)) {
|
if(Settings.Get(TOGGLE_BALLOON_SETTING, false)) {
|
||||||
string title = window.Title;
|
string title = window.Title;
|
||||||
SysIcon?.ShowBalloonTip(
|
SysIcon?.ShowBalloonTip(
|
||||||
2000, window.IsTopMost ? @"Always on top" : @"No longer always on top",
|
2000, Locale.String(window.IsTopMost ? @"NotifyOnTop" : @"NotifyNoLonger"),
|
||||||
string.IsNullOrEmpty(title) ? @"Window has no title." : title,
|
string.IsNullOrEmpty(title) ? Locale.String(@"NotifyNoTitle") : title,
|
||||||
ToolTipIcon.Info
|
ToolTipIcon.Info
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||||
// Build Number
|
// Build Number
|
||||||
// Revision
|
// Revision
|
||||||
//
|
//
|
||||||
[assembly: AssemblyVersion("1.5.1.0")]
|
[assembly: AssemblyVersion("1.6.0.0")]
|
||||||
[assembly: AssemblyFileVersion("1.5.1.0")]
|
[assembly: AssemblyFileVersion("1.6.0.0")]
|
||||||
|
|
10
TopMostFriend/Properties/Resources.Designer.cs
generated
10
TopMostFriend/Properties/Resources.Designer.cs
generated
|
@ -100,6 +100,16 @@ namespace TopMostFriend.Properties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap firstrun {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("firstrun", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -130,6 +130,9 @@
|
||||||
<data name="door_in" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="door_in" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\door_in.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\door_in.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="firstrun" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\firstrun.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
<data name="help" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="help" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\help.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\help.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
BIN
TopMostFriend/Resources/firstrun.png
Normal file
BIN
TopMostFriend/Resources/firstrun.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -26,9 +26,7 @@ namespace TopMostFriend {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string[] Get(string name, string[] fallback = null) {
|
public static string[] Get(string name, string[] fallback = null) {
|
||||||
byte[] buffer = GetRoot().GetValue(name, null) as byte[];
|
if(!(GetRoot().GetValue(name, null) is byte[] buffer))
|
||||||
|
|
||||||
if (buffer == null)
|
|
||||||
return fallback;
|
return fallback;
|
||||||
|
|
||||||
List<string> strings = new List<string>();
|
List<string> strings = new List<string>();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using TopMostFriend.Languages;
|
||||||
|
|
||||||
namespace TopMostFriend {
|
namespace TopMostFriend {
|
||||||
public class SettingsWindow : Form {
|
public class SettingsWindow : Form {
|
||||||
|
@ -29,184 +32,172 @@ namespace TopMostFriend {
|
||||||
public readonly CheckBox FlShiftClickBlacklist;
|
public readonly CheckBox FlShiftClickBlacklist;
|
||||||
public readonly CheckBox FlShowHotkeyIcon;
|
public readonly CheckBox FlShowHotkeyIcon;
|
||||||
public readonly CheckBox FlShowWindowList;
|
public readonly CheckBox FlShowWindowList;
|
||||||
|
public readonly CheckBox FlAlwaysRetryAsAdmin;
|
||||||
|
public readonly CheckBox FlRevertOnExit;
|
||||||
|
|
||||||
|
public readonly ComboBox LangSelect;
|
||||||
|
|
||||||
public SettingsWindow() {
|
public SettingsWindow() {
|
||||||
Text = @"Top Most Friend Settings";
|
Text = Locale.String(@"SettingsTitle");
|
||||||
Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||||
StartPosition = FormStartPosition.CenterScreen;
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
FormBorderStyle = FormBorderStyle.FixedSingle;
|
FormBorderStyle = FormBorderStyle.FixedSingle;
|
||||||
AutoScaleMode = AutoScaleMode.Dpi;
|
AutoScaleMode = AutoScaleMode.Dpi;
|
||||||
ClientSize = new Size(430, 298);
|
ClientSize = new Size(430, 407);
|
||||||
MinimizeBox = MaximizeBox = false;
|
MinimizeBox = MaximizeBox = false;
|
||||||
MinimumSize = MaximumSize = Size;
|
TopMost = true;
|
||||||
|
|
||||||
KeyCode = Settings.Get(Program.FOREGROUND_HOTKEY_SETTING, 0);
|
KeyCode = Settings.Get(Program.FOREGROUND_HOTKEY_SETTING, 0);
|
||||||
|
|
||||||
Button applyButton = new Button {
|
Button applyButton = new Button {
|
||||||
Text = @"Apply",
|
Text = Locale.String(@"SettingsApply"),
|
||||||
Size = new Size(75, 23),
|
Size = new Size(75, 23),
|
||||||
Location = new Point(ClientSize.Width - 81, ClientSize.Height - 30),
|
Location = new Point(ClientSize.Width - 81, ClientSize.Height - 30),
|
||||||
TabIndex = 10003,
|
TabIndex = 10003,
|
||||||
|
Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
|
||||||
};
|
};
|
||||||
applyButton.Click += ApplyButton_Click;
|
applyButton.Click += ApplyButton_Click;
|
||||||
Button cancelButton = new Button {
|
Button cancelButton = new Button {
|
||||||
Text = @"Cancel",
|
Text = Locale.String(@"SettingsCancel"),
|
||||||
Size = applyButton.Size,
|
Size = applyButton.Size,
|
||||||
Location = new Point(ClientSize.Width - 162, applyButton.Location.Y),
|
Location = new Point(ClientSize.Width - 162, applyButton.Location.Y),
|
||||||
TabIndex = 10002,
|
TabIndex = 10002,
|
||||||
|
Anchor = applyButton.Anchor,
|
||||||
};
|
};
|
||||||
cancelButton.Click += CancelButton_Click;
|
cancelButton.Click += CancelButton_Click;
|
||||||
Button okButton = new Button {
|
Button okButton = new Button {
|
||||||
Text = @"OK",
|
Text = Locale.String(@"SettingsOk"),
|
||||||
Size = applyButton.Size,
|
Size = applyButton.Size,
|
||||||
Location = new Point(ClientSize.Width - 243, applyButton.Location.Y),
|
Location = new Point(ClientSize.Width - 243, applyButton.Location.Y),
|
||||||
TabIndex = 10001,
|
TabIndex = 10001,
|
||||||
|
Anchor = applyButton.Anchor,
|
||||||
};
|
};
|
||||||
okButton.Click += OkButton_Click;
|
okButton.Click += OkButton_Click;
|
||||||
|
|
||||||
GroupBox hotKeyGroup = new GroupBox {
|
GroupBox hotKeyGroup = new GroupBox {
|
||||||
Text = @"Hotkeys",
|
Text = Locale.String(@"SettingsHotKeysTitle"),
|
||||||
Location = new Point(6, 6),
|
Location = new Point(6, 6),
|
||||||
Size = new Size(Width - 18, 70),
|
Size = new Size(Width - 18, 70),
|
||||||
|
Anchor = AnchorStyles.Left | AnchorStyles.Right,
|
||||||
};
|
};
|
||||||
|
|
||||||
GroupBox flagsGroup = new GroupBox {
|
GroupBox flagsGroup = new GroupBox {
|
||||||
Text = @"Flags",
|
Text = Locale.String(@"SettingsOptionsTitle"),
|
||||||
Location = new Point(6, 76),
|
Location = new Point(6, 80),
|
||||||
Size = new Size(Width - 18, 130),
|
Size = new Size(Width - 18, 170),
|
||||||
|
Anchor = hotKeyGroup.Anchor,
|
||||||
};
|
};
|
||||||
|
GroupBox langGroup = new GroupBox {
|
||||||
GroupBox blackListGroup = new GroupBox {
|
Text = Locale.String(@"SettingsLanguageTitle"),
|
||||||
Text = @"Blacklist",
|
Location = new Point(6, 254),
|
||||||
Location = new Point(6, 206),
|
|
||||||
Size = new Size(Width - 18, 55),
|
Size = new Size(Width - 18, 55),
|
||||||
|
Anchor = hotKeyGroup.Anchor,
|
||||||
|
};
|
||||||
|
GroupBox otherGroup = new GroupBox {
|
||||||
|
Text = Locale.String(@"SettingsOtherTitle"),
|
||||||
|
Location = new Point(6, 313),
|
||||||
|
Size = new Size(Width - 18, 55),
|
||||||
|
Anchor = hotKeyGroup.Anchor,
|
||||||
};
|
};
|
||||||
|
|
||||||
Controls.AddRange(new Control[] {
|
Controls.AddRange(new Control[] {
|
||||||
applyButton, cancelButton, okButton,
|
applyButton, cancelButton, okButton,
|
||||||
hotKeyGroup, flagsGroup, blackListGroup,
|
hotKeyGroup, flagsGroup, langGroup, otherGroup,
|
||||||
});
|
});
|
||||||
|
|
||||||
Label toggleForegroundLabel = new Label {
|
hotKeyGroup.Controls.Add(new Label {
|
||||||
AutoSize = true,
|
AutoSize = true,
|
||||||
Text = @"Toggle always on top status on active window",
|
Text = Locale.String(@"SettingsHotKeysToggle"),
|
||||||
Location = new Point(8, 17),
|
Location = new Point(8, 17),
|
||||||
};
|
|
||||||
|
|
||||||
const int mod_x = 120;
|
|
||||||
const int mod_y = 34;
|
|
||||||
|
|
||||||
Button fgReset = new Button {
|
|
||||||
Text = @"Reset",
|
|
||||||
Location = new Point(hotKeyGroup.Width - 85, mod_y),
|
|
||||||
TabIndex = 105,
|
|
||||||
};
|
|
||||||
fgReset.Click += FgReset_Click;
|
|
||||||
|
|
||||||
FgKey = new TextBox {
|
|
||||||
Text = ((Keys)(KeyCode >> 16)).ToString(),
|
|
||||||
Location = new Point(12, mod_y + 2),
|
|
||||||
TabIndex = 101,
|
|
||||||
};
|
|
||||||
FgKey.KeyDown += FgKey_KeyDown;
|
|
||||||
|
|
||||||
FgModCtrl = new CheckBox {
|
|
||||||
Text = @"CTRL",
|
|
||||||
Location = new Point(mod_x, mod_y),
|
|
||||||
Checked = (KeyCode & (int)Win32ModKeys.MOD_CONTROL) > 0,
|
|
||||||
Appearance = Appearance.Button,
|
|
||||||
Size = new Size(50, 23),
|
|
||||||
TextAlign = ContentAlignment.MiddleCenter,
|
|
||||||
TabIndex = 102,
|
|
||||||
};
|
|
||||||
FgModCtrl.Click += FgModCtrl_Click;
|
|
||||||
|
|
||||||
FgModAlt = new CheckBox {
|
|
||||||
Text = @"ALT",
|
|
||||||
Location = new Point(mod_x + 50, mod_y),
|
|
||||||
Checked = (KeyCode & (int)Win32ModKeys.MOD_ALT) > 0,
|
|
||||||
Appearance = FgModCtrl.Appearance,
|
|
||||||
Size = FgModCtrl.Size,
|
|
||||||
TextAlign = FgModCtrl.TextAlign,
|
|
||||||
TabIndex = 103,
|
|
||||||
};
|
|
||||||
FgModAlt.Click += FgModAlt_Click;
|
|
||||||
|
|
||||||
FgModShift = new CheckBox {
|
|
||||||
Text = @"SHIFT",
|
|
||||||
Location = new Point(mod_x + 100, mod_y),
|
|
||||||
Checked = (KeyCode & (int)Win32ModKeys.MOD_SHIFT) > 0,
|
|
||||||
Appearance = FgModCtrl.Appearance,
|
|
||||||
Size = FgModCtrl.Size,
|
|
||||||
TextAlign = FgModCtrl.TextAlign,
|
|
||||||
TabIndex = 104,
|
|
||||||
};
|
|
||||||
FgModShift.Click += FgModShift_Click;
|
|
||||||
|
|
||||||
FgModWindows = new CheckBox {
|
|
||||||
Text = @"WIN",
|
|
||||||
Location = new Point(mod_x + 150, mod_y),
|
|
||||||
Checked = (KeyCode & (int)Win32ModKeys.MOD_WIN) > 0,
|
|
||||||
Appearance = FgModCtrl.Appearance,
|
|
||||||
Size = FgModCtrl.Size,
|
|
||||||
TextAlign = FgModCtrl.TextAlign,
|
|
||||||
TabIndex = 105,
|
|
||||||
};
|
|
||||||
FgModWindows.Click += FgModWindows_Click;
|
|
||||||
|
|
||||||
hotKeyGroup.Controls.AddRange(new Control[] {
|
|
||||||
toggleForegroundLabel, FgModCtrl, FgModAlt, FgModShift, FgModWindows, fgReset, FgKey,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
FlAlwaysAdmin = new CheckBox {
|
CreateHotKeyInput(
|
||||||
Text = @"Always run as administrator",
|
hotKeyGroup,
|
||||||
|
() => KeyCode,
|
||||||
|
keyCode => KeyCode = keyCode
|
||||||
|
);
|
||||||
|
|
||||||
|
FlToggleNotification = new CheckBox {
|
||||||
|
Text = Locale.String(@"SettingsOptionsToggleNotify"),
|
||||||
Location = new Point(10, 20),
|
Location = new Point(10, 20),
|
||||||
Checked = Settings.Get(Program.ALWAYS_ADMIN_SETTING, false),
|
Checked = Settings.Get(Program.TOGGLE_BALLOON_SETTING, Program.ToggleBalloonDefault),
|
||||||
AutoSize = true,
|
AutoSize = true,
|
||||||
TabIndex = 201,
|
TabIndex = 201,
|
||||||
};
|
};
|
||||||
FlToggleNotification = new CheckBox {
|
FlShowHotkeyIcon = new CheckBox {
|
||||||
Text = @"Show notification when using toggle hotkey",
|
Text = Locale.String(@"SettingsOptionsToggleNotifyIcon"),
|
||||||
Location = new Point(10, 40),
|
Location = new Point(10, 40),
|
||||||
Checked = Settings.Get(Program.TOGGLE_BALLOON_SETTING, Program.ToggleBalloonDefault),
|
Checked = Settings.Get(Program.SHOW_HOTKEY_ICON, true),
|
||||||
AutoSize = true,
|
AutoSize = true,
|
||||||
TabIndex = 202,
|
TabIndex = 202,
|
||||||
};
|
};
|
||||||
FlShiftClickBlacklist = new CheckBox {
|
FlAlwaysRetryAsAdmin = new CheckBox {
|
||||||
Text = @"SHIFT+CLICK items in the list to add to the title blacklist",
|
Text = Locale.String(@"SettingsOptionsElevatedRetry"),
|
||||||
Location = new Point(10, 60),
|
Location = new Point(10, 60),
|
||||||
Checked = Settings.Get(Program.SHIFT_CLICK_BLACKLIST, true),
|
Checked = Settings.Get(Program.ALWAYS_RETRY_ELEVATED, false),
|
||||||
AutoSize = true,
|
AutoSize = true,
|
||||||
TabIndex = 203,
|
TabIndex = 203,
|
||||||
};
|
};
|
||||||
FlShowHotkeyIcon = new CheckBox {
|
FlShiftClickBlacklist = new CheckBox {
|
||||||
Text = @"Show icon of window affected by hotkey",
|
Text = Locale.String(@"SettingsOptionsShiftBlacklist"),
|
||||||
Location = new Point(10, 80),
|
Location = new Point(10, 80),
|
||||||
Checked = Settings.Get(Program.SHOW_HOTKEY_ICON, true),
|
Checked = Settings.Get(Program.SHIFT_CLICK_BLACKLIST, true),
|
||||||
AutoSize = true,
|
AutoSize = true,
|
||||||
TabIndex = 204,
|
TabIndex = 204,
|
||||||
};
|
};
|
||||||
FlShowWindowList = new CheckBox {
|
FlRevertOnExit = new CheckBox {
|
||||||
Text = @"Show list of open windows in the task bar context menu",
|
Text = Locale.String(@"SettingsOptionsRevertOnExit"),
|
||||||
Location = new Point(10, 100),
|
Location = new Point(10, 100),
|
||||||
Checked = Settings.Get(Program.SHOW_WINDOW_LIST, true),
|
Checked = Settings.Get(Program.REVERT_ON_EXIT, false),
|
||||||
AutoSize = true,
|
AutoSize = true,
|
||||||
TabIndex = 205,
|
TabIndex = 205,
|
||||||
};
|
};
|
||||||
|
FlShowWindowList = new CheckBox {
|
||||||
|
Text = Locale.String(@"SettingsOptionsShowTrayList"),
|
||||||
|
Location = new Point(10, 120),
|
||||||
|
Checked = Settings.Get(Program.SHOW_WINDOW_LIST, true),
|
||||||
|
AutoSize = true,
|
||||||
|
TabIndex = 206,
|
||||||
|
};
|
||||||
|
FlAlwaysAdmin = new CheckBox {
|
||||||
|
Text = Locale.String(@"SettingsOptionsAlwaysAdmin"),
|
||||||
|
Location = new Point(10, 140),
|
||||||
|
Checked = Settings.Get(Program.ALWAYS_ADMIN_SETTING, false),
|
||||||
|
AutoSize = true,
|
||||||
|
TabIndex = 207,
|
||||||
|
};
|
||||||
|
|
||||||
flagsGroup.Controls.AddRange(new[] {
|
CheckBox[] options = new[] {
|
||||||
FlAlwaysAdmin, FlToggleNotification, FlShiftClickBlacklist,
|
FlAlwaysAdmin, FlToggleNotification, FlShiftClickBlacklist,
|
||||||
FlShowHotkeyIcon, FlShowWindowList,
|
FlShowHotkeyIcon, FlShowWindowList, FlAlwaysRetryAsAdmin,
|
||||||
});
|
FlRevertOnExit,
|
||||||
|
};
|
||||||
|
|
||||||
|
flagsGroup.Controls.AddRange(options);
|
||||||
|
|
||||||
|
foreach(CheckBox option in options)
|
||||||
|
if((option.Width + (option.Left * 2)) > flagsGroup.ClientSize.Width)
|
||||||
|
ClientSize = new Size(option.Width + 30, ClientSize.Height);
|
||||||
|
|
||||||
|
LangSelect = new ComboBox {
|
||||||
|
Anchor = AnchorStyles.Left | AnchorStyles.Right,
|
||||||
|
DropDownStyle = ComboBoxStyle.DropDownList,
|
||||||
|
Size = new Size(langGroup.Width - 24, 21),
|
||||||
|
Location = new Point(12, 22),
|
||||||
|
};
|
||||||
|
LangSelect.Items.AddRange(Locale.GetAvailableLanguages());
|
||||||
|
LangSelect.SelectedItem = Locale.GetCurrentLanguage();
|
||||||
|
langGroup.Controls.Add(LangSelect);
|
||||||
|
|
||||||
Button titleBlacklist = new Button {
|
Button titleBlacklist = new Button {
|
||||||
Size = new Size(120, 23),
|
Size = new Size(120, 23),
|
||||||
Location = new Point(10, 20),
|
Location = new Point(10, 20),
|
||||||
Text = @"Manage...",
|
Text = Locale.String(@"SettingsOtherBlacklistButton"),
|
||||||
TabIndex = 301,
|
TabIndex = 301,
|
||||||
|
AutoSize = true,
|
||||||
|
AutoSizeMode = AutoSizeMode.GrowOnly,
|
||||||
};
|
};
|
||||||
titleBlacklist.Click += (s, e) => {
|
titleBlacklist.Click += (s, e) => {
|
||||||
string[] newList = BlacklistWindow.Display(@"Title Blacklist", Program.GetBlacklistedTitles());
|
string[] newList = BlacklistWindow.Display(Locale.String(@"SettingsOtherBlacklistWindowTitle"), Program.GetBlacklistedTitles());
|
||||||
|
|
||||||
if(newList != null) {
|
if(newList != null) {
|
||||||
Program.ApplyBlacklistedTitles(newList);
|
Program.ApplyBlacklistedTitles(newList);
|
||||||
|
@ -214,22 +205,207 @@ namespace TopMostFriend {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
blackListGroup.Controls.AddRange(new[] { titleBlacklist });
|
Button startWithWindows = new Button {
|
||||||
|
Size = new Size(120, 23),
|
||||||
|
Location = new Point(134, 20),
|
||||||
|
Text = Locale.String(@"SettingsOtherStartupButton"),
|
||||||
|
TabIndex = 302,
|
||||||
|
AutoSize = true,
|
||||||
|
AutoSizeMode = AutoSizeMode.GrowOnly,
|
||||||
|
};
|
||||||
|
startWithWindows.Click += (s, e) => {
|
||||||
|
DialogResult dr = MessageBox.Show(Locale.String(@"SettingsOtherStartupConfirm"), Program.TITLE, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||||
|
|
||||||
|
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), @"TopMostFriend.lnk");
|
||||||
|
|
||||||
|
if(File.Exists(path))
|
||||||
|
File.Delete(path);
|
||||||
|
|
||||||
|
if(dr == DialogResult.Yes) {
|
||||||
|
IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
|
||||||
|
IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(path);
|
||||||
|
shortcut.TargetPath = Application.ExecutablePath;
|
||||||
|
shortcut.Save();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Button resetSettings = new Button {
|
||||||
|
Size = new Size(120, 23),
|
||||||
|
Location = new Point(258, 20),
|
||||||
|
Text = Locale.String(@"SettingsOtherResetButton"),
|
||||||
|
TabIndex = 303,
|
||||||
|
AutoSize = true,
|
||||||
|
AutoSizeMode = AutoSizeMode.GrowOnly,
|
||||||
|
};
|
||||||
|
resetSettings.Click += (s, e) => {
|
||||||
|
DialogResult dr = MessageBox.Show(Locale.String(@"SettingsOtherResetConfirm"), Program.TITLE, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
|
||||||
|
|
||||||
|
if(dr == DialogResult.Yes) {
|
||||||
|
Settings.Remove(Program.FOREGROUND_HOTKEY_SETTING);
|
||||||
|
Settings.Remove(Program.PROCESS_SEPARATOR_SETTING);
|
||||||
|
Settings.Remove(Program.LIST_SELF_SETTING);
|
||||||
|
Settings.Remove(Program.LIST_BACKGROUND_PATH_SETTING);
|
||||||
|
Settings.Remove(Program.LIST_BACKGROUND_LAYOUT_SETTING);
|
||||||
|
Settings.Remove(Program.ALWAYS_ADMIN_SETTING);
|
||||||
|
Settings.Remove(Program.TOGGLE_BALLOON_SETTING);
|
||||||
|
Settings.Remove(Program.SHIFT_CLICK_BLACKLIST);
|
||||||
|
Settings.Remove(Program.TITLE_BLACKLIST);
|
||||||
|
Settings.Remove(Program.SHOW_HOTKEY_ICON);
|
||||||
|
Settings.Remove(Program.SHOW_WINDOW_LIST);
|
||||||
|
Settings.Remove(Program.LAST_VERSION);
|
||||||
|
Settings.Remove(Program.ALWAYS_RETRY_ELEVATED);
|
||||||
|
Settings.Remove(Program.REVERT_ON_EXIT);
|
||||||
|
Program.Shutdown();
|
||||||
|
Process.Start(Application.ExecutablePath);
|
||||||
|
Application.Exit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Button[] otherButtons = new[] { titleBlacklist, startWithWindows, resetSettings };
|
||||||
|
|
||||||
|
otherGroup.Controls.AddRange(otherButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FgReset_Click(object sender, EventArgs e) {
|
public static void CreateHotKeyInput(
|
||||||
FgModCtrl.Checked = FgModAlt.Checked = FgModShift.Checked = false;
|
Control target,
|
||||||
FgKey.Text = string.Empty;
|
Func<int> getKeyCode,
|
||||||
KeyCode = 0;
|
Action<int> setKeyCode,
|
||||||
|
int offsetX = 0,
|
||||||
|
int offsetY = 0
|
||||||
|
) {
|
||||||
|
int modX = 120 + offsetX;
|
||||||
|
int modY = 34 + offsetY;
|
||||||
|
int keyCode = getKeyCode();
|
||||||
|
|
||||||
|
Button fgReset = new Button {
|
||||||
|
Text = Locale.String(@"SettingsHotKeysReset"),
|
||||||
|
Location = new Point(target.Width - 85 + offsetX, modY),
|
||||||
|
TabIndex = 105,
|
||||||
|
};
|
||||||
|
|
||||||
|
TextBox fgKey = new TextBox {
|
||||||
|
Text = ((Keys)(keyCode >> 16)).ToString(),
|
||||||
|
Location = new Point(12 + offsetX, modY + 2),
|
||||||
|
TabIndex = 101,
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckBox fgModCtrl = new CheckBox {
|
||||||
|
Text = @"CTRL",
|
||||||
|
Location = new Point(modX, modY),
|
||||||
|
Checked = (keyCode & (int)Win32ModKeys.MOD_CONTROL) > 0,
|
||||||
|
Appearance = Appearance.Button,
|
||||||
|
Size = new Size(50, 23),
|
||||||
|
TextAlign = ContentAlignment.MiddleCenter,
|
||||||
|
TabIndex = 102,
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckBox fgModWindows = new CheckBox {
|
||||||
|
Text = @"WIN",
|
||||||
|
Location = new Point(modX + 50, modY),
|
||||||
|
Checked = (keyCode & (int)Win32ModKeys.MOD_WIN) > 0,
|
||||||
|
Appearance = fgModCtrl.Appearance,
|
||||||
|
Size = fgModCtrl.Size,
|
||||||
|
TextAlign = fgModCtrl.TextAlign,
|
||||||
|
TabIndex = 103,
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckBox fgModAlt = new CheckBox {
|
||||||
|
Text = @"ALT",
|
||||||
|
Location = new Point(modX + 100, modY),
|
||||||
|
Checked = (keyCode & (int)Win32ModKeys.MOD_ALT) > 0,
|
||||||
|
Appearance = fgModCtrl.Appearance,
|
||||||
|
Size = fgModCtrl.Size,
|
||||||
|
TextAlign = fgModCtrl.TextAlign,
|
||||||
|
TabIndex = 104,
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckBox fgModShift = new CheckBox {
|
||||||
|
Text = @"SHIFT",
|
||||||
|
Location = new Point(modX + 150, modY),
|
||||||
|
Checked = (keyCode & (int)Win32ModKeys.MOD_SHIFT) > 0,
|
||||||
|
Appearance = fgModCtrl.Appearance,
|
||||||
|
Size = fgModCtrl.Size,
|
||||||
|
TextAlign = fgModCtrl.TextAlign,
|
||||||
|
TabIndex = 105,
|
||||||
|
};
|
||||||
|
|
||||||
|
fgReset.Click += (s, e) => {
|
||||||
|
fgModCtrl.Checked = fgModAlt.Checked = fgModShift.Checked = false;
|
||||||
|
fgKey.Text = ((Keys)0).ToString();
|
||||||
|
setKeyCode(0);
|
||||||
|
};
|
||||||
|
fgModCtrl.Click += (s, e) => {
|
||||||
|
if(s is CheckBox cb) {
|
||||||
|
if(cb.Checked)
|
||||||
|
keyCode |= (int)Win32ModKeys.MOD_CONTROL;
|
||||||
|
else
|
||||||
|
keyCode &= ~(int)Win32ModKeys.MOD_CONTROL;
|
||||||
|
setKeyCode(keyCode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fgModAlt.Click += (s, e) => {
|
||||||
|
if(s is CheckBox cb) {
|
||||||
|
if(cb.Checked)
|
||||||
|
keyCode |= (int)Win32ModKeys.MOD_ALT;
|
||||||
|
else
|
||||||
|
keyCode &= ~(int)Win32ModKeys.MOD_ALT;
|
||||||
|
setKeyCode(keyCode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fgModShift.Click += (s, e) => {
|
||||||
|
if(s is CheckBox cb) {
|
||||||
|
if(cb.Checked)
|
||||||
|
keyCode |= (int)Win32ModKeys.MOD_SHIFT;
|
||||||
|
else
|
||||||
|
keyCode &= ~(int)Win32ModKeys.MOD_SHIFT;
|
||||||
|
setKeyCode(keyCode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fgModWindows.Click += (s, e) => {
|
||||||
|
if(s is CheckBox cb) {
|
||||||
|
if(cb.Checked)
|
||||||
|
keyCode |= (int)Win32ModKeys.MOD_WIN;
|
||||||
|
else
|
||||||
|
keyCode &= ~(int)Win32ModKeys.MOD_WIN;
|
||||||
|
setKeyCode(keyCode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fgKey.KeyDown += (s, e) => {
|
||||||
|
if(!(s is TextBox textBox))
|
||||||
|
return;
|
||||||
|
e.Handled = e.SuppressKeyPress = true;
|
||||||
|
textBox.Text = e.KeyCode.ToString();
|
||||||
|
keyCode &= 0xFFFF;
|
||||||
|
keyCode |= (int)e.KeyCode << 16;
|
||||||
|
setKeyCode(keyCode);
|
||||||
|
};
|
||||||
|
|
||||||
|
target.Controls.AddRange(new Control[] {
|
||||||
|
fgModCtrl, fgModAlt, fgModShift, fgModWindows, fgReset, fgKey,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Apply() {
|
public void Apply() {
|
||||||
|
if(LangSelect.SelectedItem is LanguageInfo li) {
|
||||||
|
if(li != Locale.GetCurrentLanguage()) {
|
||||||
|
if(Locale.GetPreferredLanguage() == li.Id)
|
||||||
|
Settings.Remove(Program.LANGUAGE);
|
||||||
|
else
|
||||||
|
Settings.Set(Program.LANGUAGE, li.Id);
|
||||||
|
|
||||||
|
Locale.SetLanguage(li);
|
||||||
|
MessageBox.Show(Locale.String(@"SettingsLanguageChangedInfo"), Program.TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Settings.Set(Program.FOREGROUND_HOTKEY_SETTING, KeyCode);
|
Settings.Set(Program.FOREGROUND_HOTKEY_SETTING, KeyCode);
|
||||||
Settings.Set(Program.ALWAYS_ADMIN_SETTING, FlAlwaysAdmin.Checked);
|
Settings.Set(Program.ALWAYS_ADMIN_SETTING, FlAlwaysAdmin.Checked);
|
||||||
Settings.Set(Program.TOGGLE_BALLOON_SETTING, FlToggleNotification.Checked);
|
Settings.Set(Program.TOGGLE_BALLOON_SETTING, FlToggleNotification.Checked);
|
||||||
Settings.Set(Program.SHIFT_CLICK_BLACKLIST, FlShiftClickBlacklist.Checked);
|
Settings.Set(Program.SHIFT_CLICK_BLACKLIST, FlShiftClickBlacklist.Checked);
|
||||||
Settings.Set(Program.SHOW_HOTKEY_ICON, FlShowHotkeyIcon.Checked);
|
Settings.Set(Program.SHOW_HOTKEY_ICON, FlShowHotkeyIcon.Checked);
|
||||||
Settings.Set(Program.SHOW_WINDOW_LIST, FlShowWindowList.Checked);
|
Settings.Set(Program.SHOW_WINDOW_LIST, FlShowWindowList.Checked);
|
||||||
|
Settings.Set(Program.ALWAYS_RETRY_ELEVATED, FlAlwaysRetryAsAdmin.Checked);
|
||||||
|
Settings.Set(Program.REVERT_ON_EXIT, FlRevertOnExit.Checked);
|
||||||
Program.SetForegroundHotKey(KeyCode);
|
Program.SetForegroundHotKey(KeyCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,49 +420,6 @@ namespace TopMostFriend {
|
||||||
Apply();
|
Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FgModCtrl_Click(object sender, EventArgs e) {
|
|
||||||
if(sender is CheckBox cb) {
|
|
||||||
if (cb.Checked)
|
|
||||||
KeyCode |= (int)Win32ModKeys.MOD_CONTROL;
|
|
||||||
else
|
|
||||||
KeyCode &= ~(int)Win32ModKeys.MOD_CONTROL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void FgModAlt_Click(object sender, EventArgs e) {
|
|
||||||
if (sender is CheckBox cb) {
|
|
||||||
if (cb.Checked)
|
|
||||||
KeyCode |= (int)Win32ModKeys.MOD_ALT;
|
|
||||||
else
|
|
||||||
KeyCode &= ~(int)Win32ModKeys.MOD_ALT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void FgModShift_Click(object sender, EventArgs e) {
|
|
||||||
if (sender is CheckBox cb) {
|
|
||||||
if (cb.Checked)
|
|
||||||
KeyCode |= (int)Win32ModKeys.MOD_SHIFT;
|
|
||||||
else
|
|
||||||
KeyCode &= ~(int)Win32ModKeys.MOD_SHIFT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FgModWindows_Click(object sender, EventArgs e) {
|
|
||||||
if(sender is CheckBox cb) {
|
|
||||||
if(cb.Checked)
|
|
||||||
KeyCode |= (int)Win32ModKeys.MOD_WIN;
|
|
||||||
else
|
|
||||||
KeyCode &= ~(int)Win32ModKeys.MOD_WIN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FgKey_KeyDown(object sender, KeyEventArgs e) {
|
|
||||||
if (!(sender is TextBox textBox))
|
|
||||||
return;
|
|
||||||
e.Handled = e.SuppressKeyPress = true;
|
|
||||||
textBox.Text = e.KeyCode.ToString();
|
|
||||||
KeyCode &= 0xFFFF;
|
|
||||||
KeyCode |= (int)e.KeyCode << 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnFormClosed(FormClosedEventArgs e) {
|
protected override void OnFormClosed(FormClosedEventArgs e) {
|
||||||
base.OnFormClosed(e);
|
base.OnFormClosed(e);
|
||||||
Instance.Dispose();
|
Instance.Dispose();
|
||||||
|
|
|
@ -44,12 +44,20 @@
|
||||||
<Compile Include="AboutWindow.cs">
|
<Compile Include="AboutWindow.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="ActionTimeout.cs" />
|
||||||
<Compile Include="BlacklistWindow.cs">
|
<Compile Include="BlacklistWindow.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="FirstRunWindow.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="HotKeyWindow.cs">
|
<Compile Include="HotKeyWindow.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Languages\Language.cs" />
|
||||||
|
<Compile Include="Languages\LanguageInfo.cs" />
|
||||||
|
<Compile Include="Languages\LanguageString.cs" />
|
||||||
|
<Compile Include="Locale.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Properties\Resources.Designer.cs">
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
@ -61,10 +69,12 @@
|
||||||
<Compile Include="SettingsWindow.cs">
|
<Compile Include="SettingsWindow.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="UAC.cs" />
|
||||||
<Compile Include="Win32.cs" />
|
<Compile Include="Win32.cs" />
|
||||||
<Compile Include="WindowInfo.cs" />
|
<Compile Include="WindowInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
|
@ -80,6 +90,9 @@
|
||||||
<None Include="Resources\about.png" />
|
<None Include="Resources\about.png" />
|
||||||
<None Include="Resources\cog.png" />
|
<None Include="Resources\cog.png" />
|
||||||
<None Include="Resources\arrow_refresh.png" />
|
<None Include="Resources\arrow_refresh.png" />
|
||||||
|
<None Include="Resources\firstrun.png" />
|
||||||
|
<EmbeddedResource Include="Languages\en-GB.xml" />
|
||||||
|
<EmbeddedResource Include="Languages\nl-NL.xml" />
|
||||||
<Content Include="TopMostFriend.ico" />
|
<Content Include="TopMostFriend.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -88,5 +101,16 @@
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<COMReference Include="IWshRuntimeLibrary">
|
||||||
|
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
|
||||||
|
<VersionMajor>1</VersionMajor>
|
||||||
|
<VersionMinor>0</VersionMinor>
|
||||||
|
<Lcid>0</Lcid>
|
||||||
|
<WrapperTool>tlbimp</WrapperTool>
|
||||||
|
<Isolated>False</Isolated>
|
||||||
|
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||||
|
</COMReference>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
81
TopMostFriend/UAC.cs
Normal file
81
TopMostFriend/UAC.cs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace TopMostFriend {
|
||||||
|
public static class UAC {
|
||||||
|
private static bool? IsElevatedValue;
|
||||||
|
private static string ExecutablePathValue;
|
||||||
|
|
||||||
|
static UAC() {
|
||||||
|
ExecutablePath = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsElevated {
|
||||||
|
get {
|
||||||
|
if(!IsElevatedValue.HasValue)
|
||||||
|
using(WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
||||||
|
IsElevatedValue = identity != null && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator);
|
||||||
|
|
||||||
|
return IsElevatedValue.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ExecutablePath {
|
||||||
|
get => ExecutablePathValue;
|
||||||
|
set {
|
||||||
|
ExecutablePathValue = string.IsNullOrWhiteSpace(value) || !File.Exists(value)
|
||||||
|
? Assembly.GetEntryAssembly().Location
|
||||||
|
: value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int RunElevatedTask(string args) {
|
||||||
|
if(string.IsNullOrWhiteSpace(args))
|
||||||
|
throw new ArgumentException(@"No arguments provided.", nameof(args));
|
||||||
|
|
||||||
|
try {
|
||||||
|
Process process = Process.Start(new ProcessStartInfo {
|
||||||
|
UseShellExecute = true,
|
||||||
|
FileName = ExecutablePath,
|
||||||
|
WorkingDirectory = Environment.CurrentDirectory,
|
||||||
|
Arguments = args,
|
||||||
|
Verb = @"runas",
|
||||||
|
});
|
||||||
|
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
return process.ExitCode;
|
||||||
|
} catch(Win32Exception ex) {
|
||||||
|
return ex.ErrorCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ToggleWindowTopMost(WindowInfo window, bool switchWindow)
|
||||||
|
=> ToggleWindowTopMost(window.Handle, switchWindow);
|
||||||
|
|
||||||
|
public static int ToggleWindowTopMost(IntPtr handle, bool switchWindow)
|
||||||
|
=> RunElevatedTask(switchWindow ? $@"--toggle={handle}" : $@"--toggle={handle} --background={handle}");
|
||||||
|
|
||||||
|
public static void RestartElevated() {
|
||||||
|
if(IsElevated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Program.Shutdown();
|
||||||
|
|
||||||
|
Process.Start(new ProcessStartInfo {
|
||||||
|
UseShellExecute = true,
|
||||||
|
FileName = ExecutablePath,
|
||||||
|
WorkingDirectory = Environment.CurrentDirectory,
|
||||||
|
Arguments = string.Join(@" ", Environment.GetCommandLineArgs()),
|
||||||
|
Verb = @"runas",
|
||||||
|
});
|
||||||
|
|
||||||
|
Application.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,12 +52,10 @@ namespace TopMostFriend {
|
||||||
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
|
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
|
||||||
|
|
||||||
[DllImport(@"user32", SetLastError = true)]
|
[DllImport(@"user32", SetLastError = true)]
|
||||||
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
|
||||||
|
|
||||||
public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex) {
|
public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex) {
|
||||||
if (IntPtr.Size == 8)
|
return IntPtr.Size == 8 ? GetWindowLongPtr64(hWnd, nIndex) : new IntPtr(GetWindowLong32(hWnd, nIndex));
|
||||||
return GetWindowLongPtr64(hWnd, nIndex);
|
|
||||||
return new IntPtr(GetWindowLong32(hWnd, nIndex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport(@"user32", EntryPoint = "GetWindowLong")]
|
[DllImport(@"user32", EntryPoint = "GetWindowLong")]
|
||||||
|
@ -84,9 +82,7 @@ namespace TopMostFriend {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex) {
|
public static IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex) {
|
||||||
if (IntPtr.Size > 4)
|
return IntPtr.Size > 4 ? GetClassLongPtr64(hWnd, nIndex) : new IntPtr(GetClassLongPtr32(hWnd, nIndex));
|
||||||
return GetClassLongPtr64(hWnd, nIndex);
|
|
||||||
return new IntPtr(GetClassLongPtr32(hWnd, nIndex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport(@"user32", EntryPoint = "GetClassLong")]
|
[DllImport(@"user32", EntryPoint = "GetClassLong")]
|
||||||
|
|
|
@ -3,18 +3,18 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace TopMostFriend {
|
namespace TopMostFriend {
|
||||||
public class WindowInfo {
|
public class WindowInfo {
|
||||||
public IntPtr Handle { get; }
|
public IntPtr Handle { get; }
|
||||||
public Process Owner { get; }
|
public int ProcessId { get; }
|
||||||
|
|
||||||
|
public Process Owner => Process.GetProcessById(ProcessId);
|
||||||
|
|
||||||
public string Title => Win32.GetWindowTextString(Handle);
|
public string Title => Win32.GetWindowTextString(Handle);
|
||||||
|
|
||||||
public long Flags => Win32.GetWindowLongPtr(Handle, Win32.GWL_EXSTYLE).ToInt32();
|
|
||||||
public bool IsTopMost {
|
public bool IsTopMost {
|
||||||
get => (Flags & Win32.WS_EX_TOPMOST) > 0;
|
get => (Win32.GetWindowLongPtr(Handle, Win32.GWL_EXSTYLE).ToInt32() & Win32.WS_EX_TOPMOST) > 0;
|
||||||
set {
|
set {
|
||||||
Win32.SetWindowPos(
|
Win32.SetWindowPos(
|
||||||
Handle, new IntPtr(value ? Win32.HWND_TOPMOST : Win32.HWND_NOTOPMOST),
|
Handle, new IntPtr(value ? Win32.HWND_TOPMOST : Win32.HWND_NOTOPMOST),
|
||||||
|
@ -52,33 +52,34 @@ namespace TopMostFriend {
|
||||||
public Image IconBitmap
|
public Image IconBitmap
|
||||||
=> Icon?.ToBitmap();
|
=> Icon?.ToBitmap();
|
||||||
|
|
||||||
public WindowInfo(int handle)
|
|
||||||
: this(new IntPtr(handle)) {}
|
|
||||||
|
|
||||||
public WindowInfo(IntPtr handle)
|
public WindowInfo(IntPtr handle)
|
||||||
: this(handle, FindOwner(handle)) {}
|
: this(handle, FindOwnerId(handle)) { }
|
||||||
|
|
||||||
public WindowInfo(IntPtr handle, Process owner) {
|
public WindowInfo(IntPtr handle, int processId) {
|
||||||
Handle = handle;
|
Handle = handle;
|
||||||
Owner = owner ?? throw new ArgumentNullException(nameof(owner));
|
ProcessId = processId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SwitchTo() {
|
public void SwitchTo() {
|
||||||
Win32.SwitchToThisWindow(Handle, false);
|
Win32.SwitchToThisWindow(Handle, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ToggleTopMost() {
|
public bool ToggleTopMost(bool switchWindow = true) {
|
||||||
bool expected = !IsTopMost;
|
bool expected = !IsTopMost;
|
||||||
IsTopMost = expected;
|
IsTopMost = expected;
|
||||||
bool success = IsTopMost == expected;
|
bool success = IsTopMost == expected;
|
||||||
if(expected && success)
|
if(switchWindow && expected && success)
|
||||||
SwitchTo();
|
SwitchTo();
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Process FindOwner(IntPtr hWnd) {
|
public bool ToggleTopMostElevated(bool switchWindow = true) {
|
||||||
Win32.GetWindowThreadProcessId(hWnd, out uint procId);
|
return UAC.ToggleWindowTopMost(this, switchWindow) == 0;
|
||||||
return Process.GetProcessById((int)procId);
|
}
|
||||||
|
|
||||||
|
public static int FindOwnerId(IntPtr hWnd) {
|
||||||
|
Win32.GetWindowThreadProcessId(hWnd, out int procId);
|
||||||
|
return procId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WindowInfo GetForegroundWindow() {
|
public static WindowInfo GetForegroundWindow() {
|
||||||
|
|
BIN
firstrun.psd
Normal file
BIN
firstrun.psd
Normal file
Binary file not shown.
Loading…
Reference in a new issue