diff --git a/include/scale.h b/include/scale.h index 07c73e4..1d8913a 100644 --- a/include/scale.h +++ b/include/scale.h @@ -37,12 +37,21 @@ #define SCALE_ICON_BIG 2 #define SCALE_ICON_LAST SCALE_ICON_BIG +#define SCALE_MMMODE_CURRENT 0 +#define SCALE_MMMODE_ALL 1 +#define SCALE_MMMODE_LAST SCALE_MMMODE_ALL + typedef struct _ScaleSlot { int x1, y1, x2, y2; int filled; float scale; } ScaleSlot; +typedef struct _SlotArea { + int nWindows; + XRectangle workArea; +} SlotArea; + #define SCALE_DISPLAY_OPTION_ABI 0 #define SCALE_DISPLAY_OPTION_INDEX 1 #define SCALE_DISPLAY_OPTION_INITIATE 2 @@ -64,15 +73,16 @@ typedef struct _ScaleDisplay { KeyCode leftKeyCode, rightKeyCode, upKeyCode, downKeyCode; } ScaleDisplay; -#define SCALE_SCREEN_OPTION_SPACING 0 -#define SCALE_SCREEN_OPTION_SPEED 1 -#define SCALE_SCREEN_OPTION_TIMESTEP 2 -#define SCALE_SCREEN_OPTION_WINDOW_MATCH 3 -#define SCALE_SCREEN_OPTION_DARKEN_BACK 4 -#define SCALE_SCREEN_OPTION_OPACITY 5 -#define SCALE_SCREEN_OPTION_ICON 6 -#define SCALE_SCREEN_OPTION_HOVER_TIME 7 -#define SCALE_SCREEN_OPTION_NUM 8 +#define SCALE_SCREEN_OPTION_SPACING 0 +#define SCALE_SCREEN_OPTION_SPEED 1 +#define SCALE_SCREEN_OPTION_TIMESTEP 2 +#define SCALE_SCREEN_OPTION_WINDOW_MATCH 3 +#define SCALE_SCREEN_OPTION_DARKEN_BACK 4 +#define SCALE_SCREEN_OPTION_OPACITY 5 +#define SCALE_SCREEN_OPTION_ICON 6 +#define SCALE_SCREEN_OPTION_HOVER_TIME 7 +#define SCALE_SCREEN_OPTION_MULTIMONITOR_MODE 8 +#define SCALE_SCREEN_OPTION_NUM 9 typedef enum { ScaleTypeNormal = 0, diff --git a/metadata/scale.xml.in b/metadata/scale.xml.in index 19b334a..60ad22e 100644 --- a/metadata/scale.xml.in +++ b/metadata/scale.xml.in @@ -108,6 +108,21 @@ 50 10000 + diff --git a/plugins/scale.c b/plugins/scale.c index 2cbe092..c16d534 100644 --- a/plugins/scale.c +++ b/plugins/scale.c @@ -397,42 +397,35 @@ compareWindowsDistance (const void *elem1, GET_SCALE_WINDOW (w2, ss)->distance; } -static void -layoutSlots (CompScreen *s) +static void +layoutSlotsForArea (CompScreen * s, + XRectangle workArea, + int nWindows) { - int i, j, x, y, width, height, lines, n; - int x1, y1, x2, y2; + int i, j; + int x, y, width, height; + int lines, n, nSlots; int spacing; SCALE_SCREEN (s); - spacing = ss->opt[SCALE_SCREEN_OPTION_SPACING].value.i; - - ss->nSlots = 0; - - lines = sqrt (ss->nWindows + 1); - - getCurrentOutputExtents (s, &x1, &y1, &x2, &y2); + if (!nWindows) + return; - if (s->workArea.x > x1) - x1 = s->workArea.x; - if (s->workArea.x + s->workArea.width < x2) - x2 = s->workArea.x + s->workArea.width; - if (s->workArea.y > y1) - y1 = s->workArea.y; - if (s->workArea.y + s->workArea.height < y2) - y2 = s->workArea.y + s->workArea.height; + lines = sqrt (nWindows + 1); + spacing = ss->opt[SCALE_SCREEN_OPTION_SPACING].value.i; - y = y1 + spacing; - height = ((y2 - y1) - (lines + 1) * spacing) / lines; + nSlots = 0; + y = workArea.y + spacing; + height = (workArea.height - (lines + 1) * spacing) / lines; for (i = 0; i < lines; i++) { - n = MIN (ss->nWindows - ss->nSlots, - ceilf ((float) ss->nWindows / lines)); + n = MIN (nWindows - nSlots, + ceilf ((float)nWindows / lines)); - x = x1 + spacing; - width = ((x2 - x1) - (n + 1) * spacing) / n; + x = workArea.x + spacing; + width = (workArea.width - (n + 1) * spacing) / n; for (j = 0; j < n; j++) { @@ -446,12 +439,135 @@ layoutSlots (CompScreen *s) x += width + spacing; ss->nSlots++; + nSlots++; } y += height + spacing; } } +static SlotArea* +getSlotAreas (CompScreen *s) +{ + int i; + XRectangle workArea; + float *size; + float sizePerWindow, sum = 0.0f; + int left; + SlotArea *slotAreas; + + SCALE_SCREEN(s); + + size = malloc (s->nOutputDev * sizeof (int)); + slotAreas = malloc (s->nOutputDev * sizeof (SlotArea)); + + left = ss->nWindows; + + for (i = 0; i < s->nOutputDev; i++) + { + /* determine the size of the workarea for each output device */ + workArea = s->outputDev[i].workArea; + + size[i] = workArea.width * workArea.height; + sum += size[i]; + + slotAreas[i].nWindows = 0; + slotAreas[i].workArea = workArea; + } + + /* calculate size available for each window */ + sizePerWindow = sum / ss->nWindows; + + for (i = 0; i < s->nOutputDev && left; i++) + { + /* fill the areas with windows */ + int nw = floor(size[i] / sizePerWindow); + nw = MIN (nw,left); + size[i] -= nw * sizePerWindow; + slotAreas[i].nWindows = nw; + left -= nw; + } + + /* add left windows to output devices with the biggest free space */ + while (left > 0) + { + int num = 0; + float big = 0; + + for (i = 0; i < s->nOutputDev; i++) + if (size[i] > big) + { + num = i; + big = size[i]; + } + + size[num] -= sizePerWindow; + slotAreas[num].nWindows++; + left--; + } + + free(size); + return slotAreas; +} + +static void +layoutSlots (CompScreen *s) +{ + int i; + int spacing; + int mmMode; + + SCALE_SCREEN (s); + + spacing = ss->opt[SCALE_SCREEN_OPTION_SPACING].value.i; + mmMode = ss->opt[SCALE_SCREEN_OPTION_MULTIMONITOR_MODE].value.i; + + /* if we have only one head, we don't need the + additional effort of the all monitor mode */ + if (s->nOutputDev == 1) + mmMode = SCALE_MMMODE_CURRENT; + + ss->nSlots = 0; + + switch (mmMode) + { + case SCALE_MMMODE_ALL: + { + SlotArea *slotAreas; + slotAreas = getSlotAreas (s); + if (slotAreas) + { + for (i = 0; i < s->nOutputDev; i++) + layoutSlotsForArea (s, + slotAreas[i].workArea, + slotAreas[i].nWindows); + free (slotAreas); + } + } + break; + case SCALE_MMMODE_CURRENT: + default: + { + XRectangle workArea; + workArea = s->outputDev[s->currentOutputDev].workArea; + layoutSlotsForArea (s, workArea, ss->nWindows); + } + break; + } +/* + getCurrentOutputExtents (s, &x1, &y1, &x2, &y2); + + if (s->workArea.x > x1) + x1 = s->workArea.x; + if (s->workArea.x + s->workArea.width < x2) + x2 = s->workArea.x + s->workArea.width; + if (s->workArea.y > y1) + y1 = s->workArea.y; + if (s->workArea.y + s->workArea.height < y2) + y2 = s->workArea.y + s->workArea.height; +*/ +} + static void findBestSlots (CompScreen *s) { @@ -1745,7 +1861,8 @@ static const CompMetadataOptionInfo scaleScreenOptionInfo[] = { { "darken_back", "bool", 0, 0, 0 }, { "opacity", "int", "0100", 0, 0 }, { "overlay_icon", "int", RESTOSTRING (0, SCALE_ICON_LAST), 0, 0 }, - { "hover_time", "int", "50", 0, 0 } + { "hover_time", "int", "50", 0, 0 }, + { "multimonitor_mode", "int", RESTOSTRING (0, SCALE_MMMODE_LAST), 0, 0 } }; static Bool