Processing Ajax...

Title

Message

Confirm

Confirm

Confirm

Confirm

Are you sure you want to delete this item?

Confirm

Are you sure you want to delete this item?

Confirm

Are you sure?

Reorganise Taskbar Windows Buttons

Description
This scripted function lets you define the taskbar and order for your window taskbar buttons.
Language
C#.net
Minimum Version
Created By
Nicholas A
Contributors
-
Date Created
Sep 25, 2024
Date Last Modified
Sep 25, 2024

Scripted Function (Macro) Code

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"]);
				}
			}
		}
	}
}