Skip to content

Commit

Permalink
Add support for workspaces
Browse files Browse the repository at this point in the history
  • Loading branch information
nir9 committed Jun 13, 2024
1 parent c190191 commit 136a157
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 55 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

### Minimalist Tiling Window Manager for Microsoft Windows

Video in which I make the POC of this project: https://youtu.be/cuPirXZ6AWo
Video in which I make the PoC of this project: https://youtu.be/cuPirXZ6AWo

## Usage

Expand All @@ -16,6 +16,8 @@ You can use ```alt+j``` and ```alt+k``` to go to the next/previous window with y

You can use ```alt+f``` hotkey to toggle focus mode which will disable tiling and put the focused window in fullscreen, pressing ```alt+f``` again will enable tiling again and tile all non-minimized windows

You can use ```alt+1``` and ```alt+2``` and ```alt+3``` to go to workspace number 1, 2 and 3 respectively

## Building

You can build using the "x64 Native Tools Command Prompt for VS 2022" that comes with Microsoft Visual Studio Build Tools:
Expand All @@ -26,9 +28,9 @@ In the console you can run nmake to build according to the Makefile

I haven't tried building with a different VS version or building x86, but that may work as well.

## Todo
## Contributing

- Add support for workspaces (maintain a list of maximized windows for each workspace)
One of my main goals with this project is to keep it as minimal as possible, for example I decidd against using a dynamic configuration on purpose. Thus, make sure to keep the contributions as simple as possible. If you plan on adding a completely new feature, let's discuss it on the issues beforehand.

## Coding Conventions

Expand Down Expand Up @@ -69,7 +71,7 @@ Example of when a comment is necessary and has added value:

#### For/while/switch/if blocks

Opening braces { in the same line as the block definition
Opening braces ```{``` in the same line as the block definition

```c
if (cond) {
Expand All @@ -86,7 +88,7 @@ if (cond)

#### Function blocks

Opening braces { in a new line after the function definition
Opening braces ```{``` in a new line after the function definition

```c
void init()
Expand Down
14 changes: 10 additions & 4 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
#define NEXT_WINDOW_HOTKEY_ID 1
#define PREV_WINDOW_HOTKEY_ID 2
#define QUIT_LIGHTWM_HOTKEY_ID 3
#define WORKSPACE_1_LIGHTWM_HOTKEY_ID 4
#define WORKSPACE_2_LIGHTWM_HOTKEY_ID 5
#define WORKSPACE_3_LIGHTWM_HOTKEY_ID 6

#define FOCUS_MODE_HOTKEY "alt+f"
#define NEXT_WINDOW_HOTKEY "alt+j"
#define PREV_WINDOW_HOTKEY "alt+k"
#define QUIT_LIGHTWM_HOTKEY "alt+q"
#define FOCUS_MODE_HOTKEY 'f'
#define NEXT_WINDOW_HOTKEY 'j'
#define PREV_WINDOW_HOTKEY 'k'
#define QUIT_LIGHTWM_HOTKEY 'q'
#define WORKSPACE_1_LIGHTWM_HOTKEY '1'
#define WORKSPACE_2_LIGHTWM_HOTKEY '2'
#define WORKSPACE_3_LIGHTWM_HOTKEY '3'
54 changes: 23 additions & 31 deletions keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,28 @@
#include "error.h"
#include "config.h"

UINT getModifier(const char* value)
UINT getKeyCode(char value)
{
if (lstrcmpA(value, "alt") == 0) {
return MOD_ALT;
}

if (lstrcmpA(value, "win") == 0) {
return MOD_WIN;
}

if (lstrcmpA(value, "ctrl") == 0) {
return MOD_CONTROL;
}

if (lstrcmpA(value, "shift") == 0) {
return MOD_SHIFT;
}

return MOD_ALT;
}

UINT getKeyCode(const char* value)
{
return VkKeyScanEx(value[lstrlenA(value) - 1], GetKeyboardLayout(0));
return VkKeyScanEx(value, GetKeyboardLayout(0));
}

void addKeyboardKeybind(int id, UINT modifier, UINT keyCode)
void addKeyboardKeybind(int id, UINT keyCode)
{
if (!RegisterHotKey(NULL, id, modifier | MOD_NOREPEAT, keyCode)) {
if (!RegisterHotKey(NULL, id, MOD_ALT | MOD_NOREPEAT, keyCode)) {
reportWin32Error(L"Failed to register hotkey");
return;
}
}

bool initializeKeyboardConfig()
{
addKeyboardKeybind(TOGGLE_FOCUS_MODE_HOYKEY_ID, getModifier(FOCUS_MODE_HOTKEY), getKeyCode(FOCUS_MODE_HOTKEY));
addKeyboardKeybind(NEXT_WINDOW_HOTKEY_ID, getModifier(NEXT_WINDOW_HOTKEY), getKeyCode(NEXT_WINDOW_HOTKEY));
addKeyboardKeybind(PREV_WINDOW_HOTKEY_ID, getModifier(PREV_WINDOW_HOTKEY), getKeyCode(PREV_WINDOW_HOTKEY));
addKeyboardKeybind(QUIT_LIGHTWM_HOTKEY_ID, getModifier(QUIT_LIGHTWM_HOTKEY), getKeyCode(QUIT_LIGHTWM_HOTKEY));
addKeyboardKeybind(TOGGLE_FOCUS_MODE_HOYKEY_ID, getKeyCode(FOCUS_MODE_HOTKEY));
addKeyboardKeybind(NEXT_WINDOW_HOTKEY_ID, getKeyCode(NEXT_WINDOW_HOTKEY));
addKeyboardKeybind(PREV_WINDOW_HOTKEY_ID, getKeyCode(PREV_WINDOW_HOTKEY));
addKeyboardKeybind(QUIT_LIGHTWM_HOTKEY_ID, getKeyCode(QUIT_LIGHTWM_HOTKEY));
addKeyboardKeybind(WORKSPACE_1_LIGHTWM_HOTKEY_ID, getKeyCode(WORKSPACE_1_LIGHTWM_HOTKEY));
addKeyboardKeybind(WORKSPACE_2_LIGHTWM_HOTKEY_ID, getKeyCode(WORKSPACE_2_LIGHTWM_HOTKEY));
addKeyboardKeybind(WORKSPACE_3_LIGHTWM_HOTKEY_ID, getKeyCode(WORKSPACE_3_LIGHTWM_HOTKEY));

return true;
}
Expand All @@ -54,6 +36,9 @@ void cleanupKeyboard()
UnregisterHotKey(NULL, NEXT_WINDOW_HOTKEY_ID);
UnregisterHotKey(NULL, PREV_WINDOW_HOTKEY_ID);
UnregisterHotKey(NULL, QUIT_LIGHTWM_HOTKEY_ID);
UnregisterHotKey(NULL, WORKSPACE_1_LIGHTWM_HOTKEY_ID);
UnregisterHotKey(NULL, WORKSPACE_2_LIGHTWM_HOTKEY_ID);
UnregisterHotKey(NULL, WORKSPACE_3_LIGHTWM_HOTKEY_ID);
}

void handleHotkey(WPARAM wparam, LPARAM lparam)
Expand All @@ -68,7 +53,14 @@ void handleHotkey(WPARAM wparam, LPARAM lparam)
case NEXT_WINDOW_HOTKEY_ID:
focusNextWindow(false);
break;
default:
break;
case WORKSPACE_1_LIGHTWM_HOTKEY_ID:
gotoWorkspace(1);
break;
case WORKSPACE_2_LIGHTWM_HOTKEY_ID:
gotoWorkspace(2);
break;
case WORKSPACE_3_LIGHTWM_HOTKEY_ID:
gotoWorkspace(3);
break;
}
}
113 changes: 98 additions & 15 deletions tiling.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,53 @@
#include "error.h"
#include <Windows.h>

#define MAX_MANAGED 1024

typedef struct {
HWND handle;
int workspaceNumber;
bool isFocused;
bool shouldCleanup;
} ManagedWindow;

HWND focusedWindow = 0;
HWND managed[256];
int numOfManagedWindows = 0;
HWND managed[MAX_MANAGED];
ManagedWindow totalManaged[MAX_MANAGED];
int numOfTotalManaged = 0;
int numOfCurrentlyManaged = 0;
int currentFocusedWindowIndex = 0;
int currentWorkspace = 1;
bool newWorkspace = false;

ManagedWindow* searchManaged(HWND handle)
{
for (int i = 0; i < numOfTotalManaged; i++) {
if (totalManaged[i].handle == handle) {
return &totalManaged[i];
}
}

return NULL;
}

void cleanupWorkspaceWindows()
{
int keepCounter = 0;
for (int i = 0; i < numOfTotalManaged; i++) {
if (totalManaged[i].workspaceNumber == currentWorkspace) {
continue;
}

totalManaged[keepCounter] = totalManaged[i];
keepCounter++;
}

numOfTotalManaged = keepCounter;
}

BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lparam)
{
if (numOfManagedWindows > 255) {
if (numOfTotalManaged > MAX_MANAGED) {
return FALSE;
}

Expand Down Expand Up @@ -45,37 +84,70 @@ BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lparam)
return TRUE;
}

managed[numOfManagedWindows] = hwnd;
numOfManagedWindows++;
if (searchManaged(hwnd) != NULL) {
return TRUE;
}

totalManaged[numOfTotalManaged].handle = hwnd;
totalManaged[numOfTotalManaged].isFocused = false;
totalManaged[numOfTotalManaged].workspaceNumber = currentWorkspace;
totalManaged[numOfTotalManaged].shouldCleanup = false;
numOfTotalManaged++;

return TRUE;
}

void tileWindows()
void updateManagedWindows()
{
numOfManagedWindows = 0;
numOfCurrentlyManaged = 0;

for (int i = 0; i < numOfTotalManaged; i++) {
if (totalManaged[i].workspaceNumber != currentWorkspace) {
continue;
}

if (totalManaged[i].isFocused) {
managed[0] = totalManaged[i].handle;
numOfCurrentlyManaged = 1;
break;
}

managed[numOfCurrentlyManaged] = totalManaged[i].handle;
ShowWindow(managed[numOfCurrentlyManaged], SW_RESTORE);
numOfCurrentlyManaged++;
}
}

if (focusedWindow == NULL) {
EnumChildWindows(GetDesktopWindow(), EnumChildProc, 0);
void tileWindows()
{
if (newWorkspace) {
newWorkspace = false;
} else {
managed[numOfManagedWindows] = focusedWindow;
numOfManagedWindows++;
cleanupWorkspaceWindows();
}

if (numOfManagedWindows == 0) {
EnumChildWindows(GetDesktopWindow(), EnumChildProc, 0);

if (numOfTotalManaged == 0) {
return;
}

TileWindows(GetDesktopWindow(), MDITILE_VERTICAL | MDITILE_SKIPDISABLED, NULL, numOfManagedWindows, managed);
updateManagedWindows();

TileWindows(GetDesktopWindow(), MDITILE_VERTICAL | MDITILE_SKIPDISABLED, NULL, numOfCurrentlyManaged, managed);
}

void toggleFocusedWindow(HWND hwnd)
{
if (focusedWindow != NULL) {
searchManaged(focusedWindow)->isFocused = false;
focusedWindow = NULL;
} else {
focusedWindow = hwnd;
searchManaged(focusedWindow)->isFocused = true;
}

newWorkspace = true;
tileWindows();
}

Expand All @@ -88,10 +160,21 @@ void focusNextWindow(bool goBack)
currentFocusedWindowIndex += goBack ? -1 : 1;

if (currentFocusedWindowIndex < 0) {
currentFocusedWindowIndex = numOfManagedWindows - 1;
} else if (currentFocusedWindowIndex >= numOfManagedWindows) {
currentFocusedWindowIndex = numOfCurrentlyManaged - 1;
} else if (currentFocusedWindowIndex >= numOfCurrentlyManaged) {
currentFocusedWindowIndex = 0;
}

SwitchToThisWindow(managed[currentFocusedWindowIndex], FALSE);
}

void gotoWorkspace(int number)
{
for (int i = 0; i < numOfCurrentlyManaged; i++) {
CloseWindow(managed[i]);
}

currentWorkspace = number;
newWorkspace = true;
tileWindows();
}
1 change: 1 addition & 0 deletions tiling.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
void tileWindows();
void toggleFocusedWindow(HWND hwnd);
void focusNextWindow(bool goBack);
void gotoWorkspace(int number);

0 comments on commit 136a157

Please sign in to comment.