using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Diagnostics;
/*
Lets you define the taskbar and order for your window taskbar buttons.
I wanted to have my applications in a fixed order on each taskbar. So my workspace is predictable and I know where a particular window will be.
e.g. left taskbar will have email, then spotify, any chatgpt chrome windows
Right hand taskbar will have remaining chrome windows, then firefox.
Any unmatched windows will be moved to the bottom of the second taskbar.
This required a lot of hacking as I understand you can't just move window taskbar buttons.
I worked out that moving the window from one to another and back again will move it to the end of the taskbar.
So the method is find all the windows for particular apps (or window title string) and then move everything around until the taskbar is as you want it.
Assumes you have two virtual monitors, 101 and 102.
You would edit the patterns that you want to implement
*/
public static class DisplayFusionFunction
{
static uint wait = 300; // I don't think it's reliable if less than this. Increase if not reliable.
// Debug Functions
static bool debug = false;
static string debugText = "";
static void debug_add(params object[] inputs)
{
debugText += string.Join("|", inputs.Select(input => input.ToString())) + "\n";
}
public static void Run(IntPtr windowHandle)
{
debugText = "";
Main();
if (debug) {
BFS.Dialog.ShowMessageInfo(debugText);
}
else {
BFS.Dialog.ShowMessageInfo("Reorganise complete");
}
}
// Function to move windows based on specific patterns to target monitors
public static void Main()
{
// Define app orders with the target monitor as the key
Dictionary<uint, string[]> appOrder = new Dictionary<uint, string[]>
{
{
101, new string[]
{
"calendar","inbox","gmail", "outlook",
"spotify","chatgpt","perplexity",
"teams", "remote",
"x1", "notion","logseq", "obsidian","onenote",
"visual studio","komodo","notepad","dbeaver",
"command", "powershell","task",
"word","excel"
}
},
{
102, new string[]
{
"chrome","firefox"
}
}
};
// Data structure to store app names and their windows
List<Dictionary<string, object>> table = new List<Dictionary<string, object>>();
foreach (IntPtr window in BFS.Window.GetVisibleAndMinimizedWindowHandles()) {
bool found = false;
string processFile = BFS.Application.GetMainFileByWindow(window);
string appName = Path.GetFileNameWithoutExtension(processFile).ToLower();
string windowTitle = BFS.Window.GetText(window).ToLower();
// You can edit this to zone in on behaviour
if (debug && !(Regex.IsMatch(windowTitle,"chrome|firefox", RegexOptions.IgnoreCase))) {
continue;
}
uint currentMonitorIndex = BFS.Monitor.GetMonitorIDByWindow(window);
uint otherMonitorIndex;
if (currentMonitorIndex == 101u) {
otherMonitorIndex = 102u;
} else if (currentMonitorIndex == 102u) {
otherMonitorIndex = 101u;
}
else {
debug_add("Bad Monitor",currentMonitorIndex,windowTitle);
found = true;
continue;
}
// Iterate over the monitor entries in sorted order (sorted by monitor index)
foreach (var monitorEntry in appOrder.OrderBy(entry => entry.Key)) {
if (found) break;
uint monitorIndex = monitorEntry.Key;
string[] patterns = monitorEntry.Value;
for (int i = 0; i < patterns.Length; i++) {
if (found) continue;
string pattern = patterns[i];
if (appName.Contains(pattern) || windowTitle.Contains(pattern)) {
var record = new Dictionary<string, object> {
{ "CurrentMonitor", currentMonitorIndex },
{ "OtherMonitor", otherMonitorIndex },
{ "TargetMonitor", monitorIndex },
{ "PatternIndex", i },
{ "Pattern", pattern },
{ "AppName", appName },
{ "WindowTitle", windowTitle },
{ "WindowHandle", window }
};
table.Add(record);
found = true;
break;
}
}
}
if(!found) {
// not found
var notfound = new Dictionary<string, object> {
{ "CurrentMonitor", currentMonitorIndex },
{ "OtherMonitor", otherMonitorIndex },
{ "TargetMonitor", 102u },
{ "PatternIndex", 999 },
{ "Pattern", "nomatch"},
{ "AppName", appName },
{ "WindowTitle", windowTitle },
{ "WindowHandle", window }
};
table.Add(notfound);
}
}
// Sort the table by TargetMonitor and then by PatternIndex
var sortedTable = table
.OrderBy(dict => (uint)dict["TargetMonitor"]) // Sort by monitor index
.ThenBy(dict => (int)dict["PatternIndex"]) // Then sort by pattern index
.ThenBy(dict => (string)dict["AppName"]) // Then sort by pattern index
.ToList();
// Move the windows to the correct monitor
for (int pass = 1; pass <= 2; pass++)
{
foreach (var rec in sortedTable)
{
IntPtr window = (IntPtr)rec["WindowHandle"];
uint otherMonitor = (uint)rec["OtherMonitor"];
uint targetMonitor = (uint)rec["TargetMonitor"];
if (pass == 1) {
BFS.Window.MoveToMonitor(otherMonitor, window);
BFS.General.ThreadWait(wait);
debug_add(pass, rec["CurrentMonitor"], rec["OtherMonitor"], rec["TargetMonitor"], rec["Pattern"], rec["PatternIndex"],rec["WindowTitle"]);
}
if (pass == 2 && otherMonitor != targetMonitor) {
BFS.Window.MoveToMonitor(targetMonitor, window); // Move to the target monitor
BFS.General.ThreadWait(wait);
debug_add(pass, rec["CurrentMonitor"], rec["OtherMonitor"], rec["TargetMonitor"], rec["Pattern"], rec["PatternIndex"],rec["WindowTitle"]);
}
}
}
}
}