From 16a05ad1247fdf83ced380615286c1d25bbf7261 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 27 Jun 2024 15:22:48 -0700 Subject: [PATCH 01/10] Proof of concept vertical tasklists --- src/button.c | 274 +++++++++++++++++++++++++++++++++++--------------- src/button.h | 5 + src/taskbar.c | 36 ++++++- 3 files changed, 232 insertions(+), 83 deletions(-) diff --git a/src/button.c b/src/button.c index e07c387f..fb3ad7f0 100644 --- a/src/button.c +++ b/src/button.c @@ -16,6 +16,98 @@ #include "misc.h" #include "settings.h" +static void GetButtonColors(ButtonNode *bp, ColorType *fg, long *bg1, long *bg2, + long *up, long *down, DecorationsType *decorations) +{ + switch(bp->type) { + case BUTTON_LABEL: + *fg = COLOR_MENU_FG; + *bg1 = colors[COLOR_MENU_BG]; + *bg2 = colors[COLOR_MENU_BG]; + *up = colors[COLOR_MENU_UP]; + *down = colors[COLOR_MENU_DOWN]; + *decorations = settings.menuDecorations; + break; + case BUTTON_MENU_ACTIVE: + *fg = COLOR_MENU_ACTIVE_FG; + *bg1 = colors[COLOR_MENU_ACTIVE_BG1]; + *bg2 = colors[COLOR_MENU_ACTIVE_BG2]; + *down = colors[COLOR_MENU_ACTIVE_UP]; + *up = colors[COLOR_MENU_ACTIVE_DOWN]; + *decorations = settings.menuDecorations; + break; + case BUTTON_TRAY: + *fg = COLOR_TRAYBUTTON_FG; + *bg1 = colors[COLOR_TRAYBUTTON_BG1]; + *bg2 = colors[COLOR_TRAYBUTTON_BG2]; + *up = colors[COLOR_TRAYBUTTON_UP]; + *down = colors[COLOR_TRAYBUTTON_DOWN]; + *decorations = settings.trayDecorations; + break; + case BUTTON_TRAY_ACTIVE: + *fg = COLOR_TRAYBUTTON_ACTIVE_FG; + *bg1 = colors[COLOR_TRAYBUTTON_ACTIVE_BG1]; + *bg2 = colors[COLOR_TRAYBUTTON_ACTIVE_BG2]; + *down = colors[COLOR_TRAYBUTTON_ACTIVE_UP]; + *up = colors[COLOR_TRAYBUTTON_ACTIVE_DOWN]; + *decorations = settings.trayDecorations; + break; + case BUTTON_TASK: + *fg = COLOR_TASKLIST_FG; + *bg1 = colors[COLOR_TASKLIST_BG1]; + *bg2 = colors[COLOR_TASKLIST_BG2]; + *up = colors[COLOR_TASKLIST_UP]; + *down = colors[COLOR_TASKLIST_DOWN]; + *decorations = settings.taskListDecorations; + break; + case BUTTON_TASK_ACTIVE: + *fg = COLOR_TASKLIST_ACTIVE_FG; + *bg1 = colors[COLOR_TASKLIST_ACTIVE_BG1]; + *bg2 = colors[COLOR_TASKLIST_ACTIVE_BG2]; + *down = colors[COLOR_TASKLIST_ACTIVE_UP]; + *up = colors[COLOR_TASKLIST_ACTIVE_DOWN]; + *decorations = settings.taskListDecorations; + break; + case BUTTON_MENU: + default: + *fg = COLOR_MENU_FG; + *bg1 = colors[COLOR_MENU_BG]; + *bg2 = colors[COLOR_MENU_BG]; + *up = colors[COLOR_MENU_UP]; + *down = colors[COLOR_MENU_DOWN]; + *decorations = settings.menuDecorations; + break; + } + +} + +/* Determine the size of the icon (if any) to display. */ +static void GetButtonIconSize(ButtonNode *bp, int *width, int *height, int *iconWidth, int *iconHeight) +{ + *iconWidth = 0; + *iconHeight = 0; + if(bp->icon) { + if(!bp->icon->width || !bp->icon->height) { + *iconWidth = Min(*width - BUTTON_BORDER * 2, *height - BUTTON_BORDER * 2); + *iconHeight = *iconWidth; + } else { + const int ratio = (bp->icon->width << 16) / bp->icon->height; + int maxIconWidth = *width - BUTTON_BORDER * 2; + if(bp->text) { + /* Showing text, keep the icon square. */ + maxIconWidth = Min(*width, *height) - BUTTON_BORDER * 2; + } + *iconHeight = *height - BUTTON_BORDER * 2; + *iconWidth = (*iconHeight * ratio) >> 16; + if(*iconWidth > maxIconWidth) { + *iconWidth = maxIconWidth; + *iconHeight = (*iconWidth << 16) / ratio; + } + } + } + +} + /** Draw a button. */ void DrawButton(ButtonNode *bp) { @@ -44,65 +136,7 @@ void DrawButton(ButtonNode *bp) gc = JXCreateGC(display, drawable, 0, NULL); /* Determine the colors to use. */ - switch(bp->type) { - case BUTTON_LABEL: - fg = COLOR_MENU_FG; - bg1 = colors[COLOR_MENU_BG]; - bg2 = colors[COLOR_MENU_BG]; - up = colors[COLOR_MENU_UP]; - down = colors[COLOR_MENU_DOWN]; - decorations = settings.menuDecorations; - break; - case BUTTON_MENU_ACTIVE: - fg = COLOR_MENU_ACTIVE_FG; - bg1 = colors[COLOR_MENU_ACTIVE_BG1]; - bg2 = colors[COLOR_MENU_ACTIVE_BG2]; - down = colors[COLOR_MENU_ACTIVE_UP]; - up = colors[COLOR_MENU_ACTIVE_DOWN]; - decorations = settings.menuDecorations; - break; - case BUTTON_TRAY: - fg = COLOR_TRAYBUTTON_FG; - bg1 = colors[COLOR_TRAYBUTTON_BG1]; - bg2 = colors[COLOR_TRAYBUTTON_BG2]; - up = colors[COLOR_TRAYBUTTON_UP]; - down = colors[COLOR_TRAYBUTTON_DOWN]; - decorations = settings.trayDecorations; - break; - case BUTTON_TRAY_ACTIVE: - fg = COLOR_TRAYBUTTON_ACTIVE_FG; - bg1 = colors[COLOR_TRAYBUTTON_ACTIVE_BG1]; - bg2 = colors[COLOR_TRAYBUTTON_ACTIVE_BG2]; - down = colors[COLOR_TRAYBUTTON_ACTIVE_UP]; - up = colors[COLOR_TRAYBUTTON_ACTIVE_DOWN]; - decorations = settings.trayDecorations; - break; - case BUTTON_TASK: - fg = COLOR_TASKLIST_FG; - bg1 = colors[COLOR_TASKLIST_BG1]; - bg2 = colors[COLOR_TASKLIST_BG2]; - up = colors[COLOR_TASKLIST_UP]; - down = colors[COLOR_TASKLIST_DOWN]; - decorations = settings.taskListDecorations; - break; - case BUTTON_TASK_ACTIVE: - fg = COLOR_TASKLIST_ACTIVE_FG; - bg1 = colors[COLOR_TASKLIST_ACTIVE_BG1]; - bg2 = colors[COLOR_TASKLIST_ACTIVE_BG2]; - down = colors[COLOR_TASKLIST_ACTIVE_UP]; - up = colors[COLOR_TASKLIST_ACTIVE_DOWN]; - decorations = settings.taskListDecorations; - break; - case BUTTON_MENU: - default: - fg = COLOR_MENU_FG; - bg1 = colors[COLOR_MENU_BG]; - bg2 = colors[COLOR_MENU_BG]; - up = colors[COLOR_MENU_UP]; - down = colors[COLOR_MENU_DOWN]; - decorations = settings.menuDecorations; - break; - } + GetButtonColors(bp, &fg, &bg1, &bg2, &up, &down, &decorations); /* Draw the background. */ if(bp->fill) { @@ -138,27 +172,7 @@ void DrawButton(ButtonNode *bp) } /* Determine the size of the icon (if any) to display. */ - iconWidth = 0; - iconHeight = 0; - if(bp->icon) { - if(!bp->icon->width || !bp->icon->height) { - iconWidth = Min(width - BUTTON_BORDER * 2, height - BUTTON_BORDER * 2); - iconHeight = iconWidth; - } else { - const int ratio = (bp->icon->width << 16) / bp->icon->height; - int maxIconWidth = width - BUTTON_BORDER * 2; - if(bp->text) { - /* Showing text, keep the icon square. */ - maxIconWidth = Min(width, height) - BUTTON_BORDER * 2; - } - iconHeight = height - BUTTON_BORDER * 2; - iconWidth = (iconHeight * ratio) >> 16; - if(iconWidth > maxIconWidth) { - iconWidth = maxIconWidth; - iconHeight = (iconWidth << 16) / ratio; - } - } - } + GetButtonIconSize(bp, &width, &height, &iconWidth, &iconHeight); /* Determine how much room is left for text. */ textWidth = 0; @@ -204,6 +218,106 @@ void DrawButton(ButtonNode *bp) } +void DrawButtonVertical(ButtonNode *bp) +{ + ColorType fg; + long bg1, bg2; + long up, down; + DecorationsType decorations; + + Drawable drawable; + GC gc; + int x, y; + int width, height; + int xoffset, yoffset; + int iconWidth, iconHeight; + int textWidth, textHeight; + + Assert(bp); + drawable = bp->drawable; + x = bp->x; + y = bp->y; + width = bp->width; + height = bp->height; + gc = JXCreateGC(display, drawable, 0, NULL); + + /* Determine the colors to use. */ + GetButtonColors(bp, &fg, &bg1, &bg2, &up, &down, &decorations); + + /* Draw the background. */ + if(bp->fill) { + + /* Draw the button background. */ + JXSetForeground(display, gc, bg1); + if(bg1 == bg2) { + /* single color */ + JXFillRectangle(display, drawable, gc, x, y, width, height); + } else { + /* gradient */ + DrawHorizontalGradient(drawable, gc, bg1, bg2, + x, y, width, height); + } + + } + + /* Draw the border. */ + if(bp->border) { + if(decorations == DECO_MOTIF) { + JXSetForeground(display, gc, up); + JXDrawLine(display, drawable, gc, x, y, x + width - 1, y); + JXDrawLine(display, drawable, gc, x, y, x, y + height - 1); + JXSetForeground(display, gc, down); + JXDrawLine(display, drawable, gc, x, y + height - 1, + x + width - 1, y + height - 1); + JXDrawLine(display, drawable, gc, x + width - 1, y, + x + width - 1, y + height - 1); + } else { + JXSetForeground(display, gc, down); + JXDrawRectangle(display, drawable, gc, x, y, width - 1, height - 1); + } + } + + /* Determine the size of the icon (if any) to display. */ + GetButtonIconSize(bp, &width, &height, &iconWidth, &iconHeight); + + /* Determine how much room is left for text. */ + textWidth = 0; + textHeight = 0; + if(bp->text) { + textWidth = GetStringWidth(bp->font, bp->text); + textHeight = GetStringHeight(bp->font); + if(textHeight + iconHeight + BUTTON_BORDER * 3 > height) { + textHeight = height - iconHeight - BUTTON_BORDER * 3; + } + } + + /* Determine the offset of the icon in the button. */ + xoffset = (width - iconWidth + 1) / 2; + yoffset = BUTTON_BORDER; + + /* Display the icon. */ + if(bp->icon) { + PutIcon(bp->icon, drawable, colors[fg], + x + xoffset, y + yoffset, + iconWidth, iconHeight); + yoffset += iconHeight + BUTTON_BORDER; + } + + if(textHeight > 0) { + if(textWidth <= iconWidth) { + xoffset = (width - textWidth + 1) / 2; + } else { + xoffset = BUTTON_BORDER; + } + RenderString(drawable, bp->font, fg, + x + xoffset, y + yoffset, + textWidth, bp->text); + } + + JXFreeGC(display, gc); + +} + /** Reset a button node with default values. */ void ResetButton(ButtonNode *bp, Drawable d) { diff --git a/src/button.h b/src/button.h index 29175cdd..e786726f 100644 --- a/src/button.h +++ b/src/button.h @@ -52,6 +52,11 @@ typedef struct { */ void DrawButton(ButtonNode *bp); +/** Draw a vertical button. + * @param bp The button to draw + */ +void DrawButtonVertical(ButtonNode *bp); + /** Reset the contents of a ButtonNode structure. * @param bp The structure to reset. * @param d The drawable to use. diff --git a/src/taskbar.c b/src/taskbar.c index 2ccfbb52..e286f25f 100644 --- a/src/taskbar.c +++ b/src/taskbar.c @@ -192,14 +192,37 @@ void ComputeItemSize(TaskBarType *tp) { TrayComponentType *cp = tp->cp; if(tp->layout == LAYOUT_VERTICAL) { + TaskEntry *ep; + unsigned itemCount = 0; + + tp->itemWidth = cp->width; + for(ep = taskEntries; ep; ep = ep->next) { + if(ShouldShowEntry(ep)) { + itemCount += 1; + } + } + if(itemCount == 0) { + return; + } + tp->itemHeight = Max(1, cp->height / itemCount); + if(!tp->labeled) { + tp->itemHeight = Min(tp->itemWidth, tp->itemHeight); + } else { + tp->itemHeight = Min(tp->itemWidth + GetStringHeight(FONT_TASKLIST), tp->itemHeight); + } + + if(tp->maxItemWidth > 0) { + tp->itemHeight = Min(tp->maxItemWidth, tp->itemHeight); + } +/* if(tp->userHeight > 0) { tp->itemHeight = tp->userHeight; } else { tp->itemHeight = GetStringHeight(FONT_TASKLIST) + 12; } tp->itemWidth = cp->width; - +*/ } else { TaskEntry *ep; @@ -713,7 +736,7 @@ void UpdateTaskBar(void) } for(bp = bars; bp; bp = bp->next) { - if(bp->layout == LAYOUT_VERTICAL) { +/* if(bp->layout == LAYOUT_VERTICAL) { TaskEntry *tp; lastHeight = bp->cp->requestedHeight; if(bp->userHeight > 0) { @@ -732,6 +755,7 @@ void UpdateTaskBar(void) ResizeTray(bp->cp->tray); } } +*/ ComputeItemSize(bp); Render(bp); } @@ -838,7 +862,13 @@ void Render(const TaskBarType *bp) button.text = tp->clients->client->name; } } - DrawButton(&button); + + if(bp->layout == LAYOUT_HORIZONTAL) { + DrawButton(&button); + } else { + DrawButtonVertical(&button); + } + if(displayName) { Release(displayName); } From 9045e42d8fa8346ceccb5689600594fae6d99ce1 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 9 Jul 2024 16:19:46 -0700 Subject: [PATCH 02/10] Added "altvertlist" attribute to toggle on or off new vertical tasklist. By default it is set to false and will use the previous vertical tasklist logic. Also did some minor refactoring of the ComputeItemSize function. --- src/parse.c | 5 ++++ src/settings.h | 1 + src/taskbar.c | 79 +++++++++++++++++++++++++------------------------- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/parse.c b/src/parse.c index 6cb10ad6..21bce422 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1220,6 +1220,11 @@ void ParseTrayStyle(const TokenNode *tp, FontType font, ColorType fg) settings.listAllTasks = !strcmp(temp, "all"); } + temp = FindAttribute(tp->attributes, "altvertlist"); + if(temp) { + settings.altVerticalTasks = !strcmp(temp, TRUE_VALUE); + } + temp = FindAttribute(tp->attributes, KILL_MENU_ATTRIBUTE); if(temp) { settings.showKillMenuItem = !strcmp(temp, TRUE_VALUE); diff --git a/src/settings.h b/src/settings.h index 4a803729..0fe08ace 100644 --- a/src/settings.h +++ b/src/settings.h @@ -123,6 +123,7 @@ typedef struct { MouseContextType titleBarLayout[TBC_COUNT + 1]; char groupTasks; char listAllTasks; + char altVerticalTasks; char showClientName; char clientNameDelimiters[2]; char showKillMenuItem; diff --git a/src/taskbar.c b/src/taskbar.c index e286f25f..9fff36d4 100644 --- a/src/taskbar.c +++ b/src/taskbar.c @@ -62,6 +62,7 @@ static TaskBarType *bars; static TaskEntry *taskEntries; static TaskEntry *taskEntriesTail; +static unsigned TallyVisibleItems(void); static void ComputeItemSize(TaskBarType *tp); static char ShouldShowEntry(const TaskEntry *tp); static char ShouldFocusEntry(const TaskEntry *tp); @@ -187,61 +188,60 @@ void Resize(TrayComponentType *cp) ClearTrayDrawable(cp); } +/** Count the number of items that should be shown in the task bar. */ +unsigned TallyVisibleItems(void) +{ + TaskEntry *ep; + unsigned count = 0; + for(ep = taskEntries; ep; ep = ep->next) { + if(ShouldShowEntry(ep)) { + count += 1; + } + } + return count; +} + /** Determine the size of items in the task bar. */ void ComputeItemSize(TaskBarType *tp) { TrayComponentType *cp = tp->cp; - if(tp->layout == LAYOUT_VERTICAL) { - TaskEntry *ep; - unsigned itemCount = 0; - tp->itemWidth = cp->width; - for(ep = taskEntries; ep; ep = ep->next) { - if(ShouldShowEntry(ep)) { - itemCount += 1; + if(tp->layout == LAYOUT_VERTICAL) { + if(settings.altVerticalTasks) { + unsigned itemCount = TallyVisibleItems(); + if(itemCount == 0) { + return; } - } - if(itemCount == 0) { - return; - } - - tp->itemHeight = Max(1, cp->height / itemCount); - if(!tp->labeled) { - tp->itemHeight = Min(tp->itemWidth, tp->itemHeight); - } else { - tp->itemHeight = Min(tp->itemWidth + GetStringHeight(FONT_TASKLIST), tp->itemHeight); - } - if(tp->maxItemWidth > 0) { - tp->itemHeight = Min(tp->maxItemWidth, tp->itemHeight); - } -/* - if(tp->userHeight > 0) { - tp->itemHeight = tp->userHeight; - } else { - tp->itemHeight = GetStringHeight(FONT_TASKLIST) + 12; - } - tp->itemWidth = cp->width; -*/ - } else { + tp->itemWidth = cp->width; + tp->itemHeight = Max(1, cp->height / itemCount); - TaskEntry *ep; - unsigned itemCount = 0; + if(!tp->labeled) { + tp->itemHeight = Min(tp->itemWidth, tp->itemHeight); + } else { + tp->itemHeight = Min(tp->itemWidth + GetStringHeight(FONT_TASKLIST), tp->itemHeight); + } - tp->itemHeight = cp->height; - for(ep = taskEntries; ep; ep = ep->next) { - if(ShouldShowEntry(ep)) { - itemCount += 1; + if(tp->maxItemWidth > 0) { + tp->itemHeight = Min(tp->maxItemWidth, tp->itemHeight); } + } else { + tp->itemHeight = tp->userHeight > 0 ? tp->userHeight : GetStringHeight(FONT_TASKLIST) + 12; + tp->itemWidth = cp->width; } + } else { + unsigned itemCount = TallyVisibleItems(); if(itemCount == 0) { - return; + return; } + tp->itemHeight = cp->height; tp->itemWidth = Max(1, cp->width / itemCount); + if(!tp->labeled) { tp->itemWidth = Min(tp->itemHeight, tp->itemWidth); } + if(tp->maxItemWidth > 0) { tp->itemWidth = Min(tp->maxItemWidth, tp->itemWidth); } @@ -736,7 +736,7 @@ void UpdateTaskBar(void) } for(bp = bars; bp; bp = bp->next) { -/* if(bp->layout == LAYOUT_VERTICAL) { + if(bp->layout == LAYOUT_VERTICAL && !settings.altVerticalTasks) { TaskEntry *tp; lastHeight = bp->cp->requestedHeight; if(bp->userHeight > 0) { @@ -755,7 +755,6 @@ void UpdateTaskBar(void) ResizeTray(bp->cp->tray); } } -*/ ComputeItemSize(bp); Render(bp); } @@ -863,7 +862,7 @@ void Render(const TaskBarType *bp) } } - if(bp->layout == LAYOUT_HORIZONTAL) { + if(bp->layout == LAYOUT_HORIZONTAL || !settings.altVerticalTasks) { DrawButton(&button); } else { DrawButtonVertical(&button); From 7bd1767369dc23e7e0bccef0314cc26a6ef1442e Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 9 Jul 2024 16:31:18 -0700 Subject: [PATCH 03/10] Fix whitespace typo --- src/taskbar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/taskbar.c b/src/taskbar.c index 9fff36d4..ea0b3a2f 100644 --- a/src/taskbar.c +++ b/src/taskbar.c @@ -232,7 +232,7 @@ void ComputeItemSize(TaskBarType *tp) } else { unsigned itemCount = TallyVisibleItems(); if(itemCount == 0) { - return; + return; } tp->itemHeight = cp->height; From d20385ca4f793f98453434816cd8e877f4b7f370 Mon Sep 17 00:00:00 2001 From: Matt W Date: Sun, 21 Jul 2024 17:57:45 -0700 Subject: [PATCH 04/10] Implement button label positions. Move labelpos from to as part of the tray. --- src/button.c | 245 ++++++++++++++++++++--------------------------- src/button.h | 12 ++- src/menu.c | 1 + src/parse.c | 11 ++- src/settings.h | 1 - src/taskbar.c | 32 +++++-- src/taskbar.h | 6 ++ src/traybutton.c | 1 + 8 files changed, 148 insertions(+), 161 deletions(-) diff --git a/src/button.c b/src/button.c index fb3ad7f0..5381d0a7 100644 --- a/src/button.c +++ b/src/button.c @@ -16,6 +16,7 @@ #include "misc.h" #include "settings.h" +/** Determine the colors to use. */ static void GetButtonColors(ButtonNode *bp, ColorType *fg, long *bg1, long *bg2, long *up, long *down, DecorationsType *decorations) { @@ -81,144 +82,68 @@ static void GetButtonColors(ButtonNode *bp, ColorType *fg, long *bg1, long *bg2, } -/* Determine the size of the icon (if any) to display. */ +/** Determine the size of the icon (if any) to display. */ static void GetButtonIconSize(ButtonNode *bp, int *width, int *height, int *iconWidth, int *iconHeight) { *iconWidth = 0; *iconHeight = 0; - if(bp->icon) { - if(!bp->icon->width || !bp->icon->height) { - *iconWidth = Min(*width - BUTTON_BORDER * 2, *height - BUTTON_BORDER * 2); - *iconHeight = *iconWidth; - } else { - const int ratio = (bp->icon->width << 16) / bp->icon->height; - int maxIconWidth = *width - BUTTON_BORDER * 2; - if(bp->text) { - /* Showing text, keep the icon square. */ - maxIconWidth = Min(*width, *height) - BUTTON_BORDER * 2; - } - *iconHeight = *height - BUTTON_BORDER * 2; - *iconWidth = (*iconHeight * ratio) >> 16; - if(*iconWidth > maxIconWidth) { - *iconWidth = maxIconWidth; - *iconHeight = (*iconWidth << 16) / ratio; - } - } - } -} + if(!bp->icon) + return; -/** Draw a button. */ -void DrawButton(ButtonNode *bp) -{ + int maxIconWidth = *width - BUTTON_BORDER * 2; + int maxIconHeight = *height - BUTTON_BORDER * 2; - ColorType fg; - long bg1, bg2; - long up, down; - DecorationsType decorations; - - Drawable drawable; - GC gc; - int x, y; - int width, height; - int xoffset, yoffset; - - int iconWidth, iconHeight; - int textWidth, textHeight; - - Assert(bp); - - drawable = bp->drawable; - x = bp->x; - y = bp->y; - width = bp->width; - height = bp->height; - gc = JXCreateGC(display, drawable, 0, NULL); - - /* Determine the colors to use. */ - GetButtonColors(bp, &fg, &bg1, &bg2, &up, &down, &decorations); - - /* Draw the background. */ - if(bp->fill) { - - /* Draw the button background. */ - JXSetForeground(display, gc, bg1); - if(bg1 == bg2) { - /* single color */ - JXFillRectangle(display, drawable, gc, x, y, width, height); + if(bp->text) { + if(bp->labelPos > LABEL_POSITION_RIGHT) { + maxIconHeight -= GetStringHeight(bp->font) + BUTTON_BORDER; } else { - /* gradient */ - DrawHorizontalGradient(drawable, gc, bg1, bg2, - x, y, width, height); + maxIconWidth = Min(*width, *height) - BUTTON_BORDER * 2; } - } - - /* Draw the border. */ - if(bp->border) { - if(decorations == DECO_MOTIF) { - JXSetForeground(display, gc, up); - JXDrawLine(display, drawable, gc, x, y, x + width - 1, y); - JXDrawLine(display, drawable, gc, x, y, x, y + height - 1); - JXSetForeground(display, gc, down); - JXDrawLine(display, drawable, gc, x, y + height - 1, - x + width - 1, y + height - 1); - JXDrawLine(display, drawable, gc, x + width - 1, y, - x + width - 1, y + height - 1); - } else { - JXSetForeground(display, gc, down); - JXDrawRectangle(display, drawable, gc, x, y, width - 1, height - 1); + if(!bp->icon->width || !bp->icon->height) { + *iconWidth = Min(maxIconWidth, maxIconHeight); + *iconHeight = *iconWidth; + } else { + const int ratio = (bp->icon->width << 16) / bp->icon->height; + *iconHeight = maxIconHeight; + *iconWidth = (*iconHeight * ratio) >> 16; + if(*iconWidth > maxIconWidth) { + *iconWidth = maxIconWidth; + *iconHeight = (*iconWidth << 16) / ratio; } - } + } - /* Determine the size of the icon (if any) to display. */ - GetButtonIconSize(bp, &width, &height, &iconWidth, &iconHeight); +} - /* Determine how much room is left for text. */ - textWidth = 0; - textHeight = 0; - if(bp->text && (width > height || !bp->icon)) { - const int borderWidth = BUTTON_BORDER * (bp->icon ? 3 : 2); - textWidth = GetStringWidth(bp->font, bp->text); - textHeight = GetStringHeight(bp->font); - if(textWidth + iconWidth + borderWidth > width) { - textWidth = width - iconWidth - borderWidth; - } - textWidth = textWidth < 0 ? 0 : textWidth; - } +/** Determine how much room is left for text. */ +static void GetTextSpaceRemaining(ButtonNode *bp, int *width, int *height, int *iconWidth, + int *iconHeight, int *textWidth, int *textHeight) +{ + *textWidth = 0; + *textHeight = 0; - /* Determine the offset of the text in the button. */ - if(bp->alignment == ALIGN_CENTER || width <= height) { - xoffset = (width - iconWidth - textWidth + 1) / 2; - if(xoffset < 0) { - xoffset = 0; - } - } else { - xoffset = BUTTON_BORDER; + if(!bp->text) { + return; } - /* Display the icon. */ - if(bp->icon) { - yoffset = (height - iconHeight + 1) / 2; - PutIcon(bp->icon, drawable, colors[fg], - x + xoffset, y + yoffset, - iconWidth, iconHeight); - xoffset += iconWidth + BUTTON_BORDER; - } + *textWidth = GetStringWidth(bp->font, bp->text); + *textHeight = GetStringHeight(bp->font); - /* Display the label. */ - if(textWidth > 0) { - yoffset = (height - textHeight + 1) / 2; - RenderString(drawable, bp->font, fg, - x + xoffset, y + yoffset, - textWidth, bp->text); + if(bp->labelPos < LABEL_POSITION_TOP) { + if(*width > *height || !bp->icon) { + const int borderWidth = BUTTON_BORDER * (bp->icon ? 3 : 2); + *textWidth = Min(*textWidth, *width - *iconWidth - borderWidth); + } + } else { + *textHeight = Min(*textHeight, *height - *iconHeight - BUTTON_BORDER * 3); + *textWidth = Min(*textWidth, *width - BUTTON_BORDER * 2); } - JXFreeGC(display, gc); - + *textWidth = Max(*textWidth, 0); } -void DrawButtonVertical(ButtonNode *bp) +void DrawButton(ButtonNode *bp) { ColorType fg; long bg1, bg2; @@ -281,37 +206,70 @@ void DrawButtonVertical(ButtonNode *bp) GetButtonIconSize(bp, &width, &height, &iconWidth, &iconHeight); /* Determine how much room is left for text. */ - textWidth = 0; - textHeight = 0; - if(bp->text) { - textWidth = GetStringWidth(bp->font, bp->text); - textHeight = GetStringHeight(bp->font); - if(textHeight + iconHeight + BUTTON_BORDER * 3 > height) { - textHeight = height - iconHeight - BUTTON_BORDER * 3; - } - } + GetTextSpaceRemaining(bp, &width, &height, &iconWidth, &iconHeight, + &textWidth, &textHeight); - /* Determine the offset of the icon in the button. */ - xoffset = (width - iconWidth + 1) / 2; - yoffset = BUTTON_BORDER; + if(bp->labelPos == LABEL_POSITION_RIGHT) { + if(bp->alignment == ALIGN_CENTER || width <= height) { + xoffset = Max(0, (width - iconWidth - textWidth + 1) / 2); + } else { + xoffset = BUTTON_BORDER; + } - /* Display the icon. */ - if(bp->icon) { - PutIcon(bp->icon, drawable, colors[fg], - x + xoffset, y + yoffset, - iconWidth, iconHeight); - yoffset += iconHeight + BUTTON_BORDER; - } + if(bp->icon) { + PutIcon(bp->icon, drawable, colors[fg], + x + xoffset, y + yoffset, + iconWidth, iconHeight); + xoffset += iconWidth + BUTTON_BORDER; + } - if(textHeight > 0) { - if(textWidth <= iconWidth) { + /* Display the label. */ + if(textWidth > 0) { + yoffset = (height - textHeight + 1) / 2; + RenderString(drawable, bp->font, fg, + x + xoffset, y + yoffset, + textWidth, bp->text); + } + } else if (bp->labelPos == LABEL_POSITION_TOP) { + const int ycenter = (height - textHeight - iconHeight - BUTTON_BORDER + 1) / 2; + yoffset = (height - iconHeight + 1) / 2; + + /* Display the label before the icon. */ + if(textHeight > 0 && textWidth > 0) { xoffset = (width - textWidth + 1) / 2; - } else { - xoffset = BUTTON_BORDER; + yoffset = width <= height ? Max(BUTTON_BORDER, ycenter) : BUTTON_BORDER; + + RenderString(drawable, bp->font, fg, + x + xoffset, y + yoffset, + textWidth, bp->text); + yoffset += textHeight + BUTTON_BORDER; + } + + if(bp->icon) { + xoffset = (width - iconWidth + 1) / 2; + PutIcon(bp->icon, drawable, colors[fg], + x + xoffset, y + yoffset, + iconWidth, iconHeight); + } + } else if (bp->labelPos == LABEL_POSITION_BOTTOM) { + const int ycenter = (height - iconHeight - textHeight - BUTTON_BORDER + 1) / 2; + xoffset = (width - iconWidth + 1) / 2; + yoffset = width <= height ? Max(BUTTON_BORDER, ycenter) : BUTTON_BORDER; + + if(bp->icon) { + PutIcon(bp->icon, drawable, colors[fg], + x + xoffset, y + yoffset, + iconWidth, iconHeight); + yoffset += iconHeight + BUTTON_BORDER; + } + + /* Display the label. */ + if(textHeight > 0 && textWidth > 0) { + xoffset = (width - textWidth + 1) / 2; + RenderString(drawable, bp->font, fg, + x + xoffset, y + yoffset, + textWidth, bp->text); } - RenderString(drawable, bp->font, fg, - x + xoffset, y + yoffset, - textWidth, bp->text); } JXFreeGC(display, gc); @@ -328,6 +286,7 @@ void ResetButton(ButtonNode *bp, Drawable d) bp->drawable = d; bp->font = FONT_TRAY; bp->alignment = ALIGN_LEFT; + bp->labelPos = LABEL_POSITION_RIGHT; bp->x = 0; bp->y = 0; bp->width = 1; diff --git a/src/button.h b/src/button.h index e786726f..a8018c70 100644 --- a/src/button.h +++ b/src/button.h @@ -28,11 +28,18 @@ typedef unsigned char ButtonType; #define BUTTON_TASK 5 /**< Item in the task list. */ #define BUTTON_TASK_ACTIVE 6 /**< Active item in the task list. */ +/** Enumeration of button label positions. */ +typedef unsigned char LabelPosition; +#define LABEL_POSITION_RIGHT 0 /**< Right of the button icon. */ +#define LABEL_POSITION_TOP 1 /**< Above of the button icon. */ +#define LABEL_POSITION_BOTTOM 2 /**< Below the button icon.. */ + /** Data used for drawing a button. */ typedef struct { ButtonType type; /**< The type of button to draw. */ AlignmentType alignment; /**< Alignment of the button content. */ + LabelPosition labelPos; /**< Position of the button label. */ FontType font; /**< The font for button text. */ char fill; /**< Determine if we should fill. */ char border; /**< Determine if we should draw a border. */ @@ -52,11 +59,6 @@ typedef struct { */ void DrawButton(ButtonNode *bp); -/** Draw a vertical button. - * @param bp The button to draw - */ -void DrawButtonVertical(ButtonNode *bp); - /** Reset the contents of a ButtonNode structure. * @param bp The structure to reset. * @param d The drawable to use. diff --git a/src/menu.c b/src/menu.c index 5b8dd4cd..badcd159 100644 --- a/src/menu.c +++ b/src/menu.c @@ -853,6 +853,7 @@ void DrawMenuItem(Menu *menu, MenuItem *item, int index) button.type = BUTTON_LABEL; button.text = menu->label; button.alignment = ALIGN_CENTER; + button.labelPos = LABEL_POSITION_RIGHT; DrawButton(&button); } return; diff --git a/src/parse.c b/src/parse.c index 21bce422..bce230d9 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1220,11 +1220,6 @@ void ParseTrayStyle(const TokenNode *tp, FontType font, ColorType fg) settings.listAllTasks = !strcmp(temp, "all"); } - temp = FindAttribute(tp->attributes, "altvertlist"); - if(temp) { - settings.altVerticalTasks = !strcmp(temp, TRUE_VALUE); - } - temp = FindAttribute(tp->attributes, KILL_MENU_ATTRIBUTE); if(temp) { settings.showKillMenuItem = !strcmp(temp, TRUE_VALUE); @@ -1444,6 +1439,12 @@ void ParseTaskList(const TokenNode *tp, TrayType *tray) if(temp && !strcmp(temp, FALSE_VALUE)) { SetTaskBarLabeled(cp, 0); } + + temp = FindAttribute(tp->attributes, "labelpos"); + if(temp) { + SetTaskBarLabelPosition(cp, temp); + } + } /** Parse the tray button style. */ diff --git a/src/settings.h b/src/settings.h index 0fe08ace..4a803729 100644 --- a/src/settings.h +++ b/src/settings.h @@ -123,7 +123,6 @@ typedef struct { MouseContextType titleBarLayout[TBC_COUNT + 1]; char groupTasks; char listAllTasks; - char altVerticalTasks; char showClientName; char clientNameDelimiters[2]; char showKillMenuItem; diff --git a/src/taskbar.c b/src/taskbar.c index ea0b3a2f..a7a3faa0 100644 --- a/src/taskbar.c +++ b/src/taskbar.c @@ -38,6 +38,7 @@ typedef struct TaskBarType { int itemWidth; LayoutType layout; char labeled; + LabelPosition labelPos; Pixmap buffer; @@ -129,6 +130,7 @@ TrayComponentType *CreateTaskBar() tp->maxItemWidth = 0; tp->layout = LAYOUT_HORIZONTAL; tp->labeled = 1; + tp->labelPos = LABEL_POSITION_RIGHT; tp->mousex = -settings.doubleClickDelta; tp->mousey = -settings.doubleClickDelta; tp->mouseTime.seconds = 0; @@ -207,7 +209,7 @@ void ComputeItemSize(TaskBarType *tp) TrayComponentType *cp = tp->cp; if(tp->layout == LAYOUT_VERTICAL) { - if(settings.altVerticalTasks) { + if(tp->labelPos > LABEL_POSITION_RIGHT) { unsigned itemCount = TallyVisibleItems(); if(itemCount == 0) { return; @@ -736,7 +738,7 @@ void UpdateTaskBar(void) } for(bp = bars; bp; bp = bp->next) { - if(bp->layout == LAYOUT_VERTICAL && !settings.altVerticalTasks) { + if(bp->layout == LAYOUT_VERTICAL && bp->labelPos < LABEL_POSITION_TOP) { TaskEntry *tp; lastHeight = bp->cp->requestedHeight; if(bp->userHeight > 0) { @@ -809,6 +811,7 @@ void Render(const TaskBarType *bp) button.font = FONT_TASKLIST; button.height = bp->itemHeight; button.width = bp->itemWidth; + button.labelPos = bp->labelPos; button.text = NULL; x = 0; @@ -862,11 +865,7 @@ void Render(const TaskBarType *bp) } } - if(bp->layout == LAYOUT_HORIZONTAL || !settings.altVerticalTasks) { - DrawButton(&button); - } else { - DrawButtonVertical(&button); - } + DrawButton(&button); if(displayName) { Release(displayName); @@ -1074,6 +1073,25 @@ void SetTaskBarLabeled(TrayComponentType *cp, char labeled) bp->labeled = labeled; } +/** Set the label's postion. */ +void SetTaskBarLabelPosition(TrayComponentType *cp, const char *value) +{ + TaskBarType *bp = (TaskBarType*)cp->object; + + Assert(cp); + Assert(value); + + if(!strcmp(value, "right")) { + bp->labelPos = LABEL_POSITION_RIGHT; + } else if(!strcmp(value, "top")) { + bp->labelPos = LABEL_POSITION_TOP; + } else if(!strcmp(value, "bottom")) { + bp->labelPos = LABEL_POSITION_BOTTOM; + } else { + Warning(_("invalid labelpos for TaskList: %s"), value); + } +} + /** Maintain the _NET_CLIENT_LIST[_STACKING] properties on the root. */ void UpdateNetClientList(void) { diff --git a/src/taskbar.h b/src/taskbar.h index 7a762f1b..9c389bee 100644 --- a/src/taskbar.h +++ b/src/taskbar.h @@ -65,6 +65,12 @@ void SetTaskBarHeight(struct TrayComponentType *cp, const char *value); */ void SetTaskBarLabeled(struct TrayComponentType *cp, char value); +/** Set where labels should be positioned in relation to the icon. + * @param cp The task bar component. + * @param value 0 for right of the icon, 1 for above the icon, 2 for below the icon. + */ +void SetTaskBarLabelPosition(struct TrayComponentType *cp, const char *value); + /** Update the _NET_CLIENT_LIST property. */ void UpdateNetClientList(void); diff --git a/src/traybutton.c b/src/traybutton.c index c11ba6b6..6629c5f6 100644 --- a/src/traybutton.c +++ b/src/traybutton.c @@ -296,6 +296,7 @@ void Draw(TrayComponentType *cp) button.y = 0; button.font = FONT_TRAY; button.text = bp->label; + button.labelPos = LABEL_POSITION_RIGHT; button.icon = bp->icon; DrawButton(&button); From 204d3e0a29286b2bb6c5750f8f47023f5de62961 Mon Sep 17 00:00:00 2001 From: Matt W Date: Mon, 22 Jul 2024 14:13:52 -0700 Subject: [PATCH 05/10] Fix some code styling issues --- src/button.c | 4 +++- src/taskbar.c | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/button.c b/src/button.c index 5381d0a7..db384006 100644 --- a/src/button.c +++ b/src/button.c @@ -149,16 +149,18 @@ void DrawButton(ButtonNode *bp) long bg1, bg2; long up, down; DecorationsType decorations; - + Drawable drawable; GC gc; int x, y; int width, height; int xoffset, yoffset; + int iconWidth, iconHeight; int textWidth, textHeight; Assert(bp); + drawable = bp->drawable; x = bp->x; y = bp->y; diff --git a/src/taskbar.c b/src/taskbar.c index a7a3faa0..3754ad94 100644 --- a/src/taskbar.c +++ b/src/taskbar.c @@ -864,7 +864,6 @@ void Render(const TaskBarType *bp) button.text = tp->clients->client->name; } } - DrawButton(&button); if(displayName) { From c3a78b99b8605d82e34b02b300cfafd47b4450eb Mon Sep 17 00:00:00 2001 From: Matt W Date: Mon, 22 Jul 2024 15:02:35 -0700 Subject: [PATCH 06/10] Add missing comments. --- src/button.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/button.c b/src/button.c index db384006..519aaded 100644 --- a/src/button.c +++ b/src/button.c @@ -96,8 +96,10 @@ static void GetButtonIconSize(ButtonNode *bp, int *width, int *height, int *icon if(bp->text) { if(bp->labelPos > LABEL_POSITION_RIGHT) { + /* Make room for the text. */ maxIconHeight -= GetStringHeight(bp->font) + BUTTON_BORDER; } else { + /* Showing text, keep the icon square. */ maxIconWidth = Min(*width, *height) - BUTTON_BORDER * 2; } } From 06a2b216f6e217abf155fd6153a3e709e49d059b Mon Sep 17 00:00:00 2001 From: Matt W Date: Tue, 23 Jul 2024 05:05:46 -0700 Subject: [PATCH 07/10] Fix right label position buttons --- src/button.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/button.c b/src/button.c index 519aaded..fbf3ea7a 100644 --- a/src/button.c +++ b/src/button.c @@ -221,6 +221,7 @@ void DrawButton(ButtonNode *bp) } if(bp->icon) { + yoffset = (height - iconHeight + 1) / 2; PutIcon(bp->icon, drawable, colors[fg], x + xoffset, y + yoffset, iconWidth, iconHeight); From f7e7d6a07576642f342af145a18b6dd39793a7ab Mon Sep 17 00:00:00 2001 From: Matt W Date: Tue, 23 Jul 2024 05:14:36 -0700 Subject: [PATCH 08/10] Minor styling and formatting fixes. --- src/button.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/button.c b/src/button.c index fbf3ea7a..909d741e 100644 --- a/src/button.c +++ b/src/button.c @@ -232,8 +232,8 @@ void DrawButton(ButtonNode *bp) if(textWidth > 0) { yoffset = (height - textHeight + 1) / 2; RenderString(drawable, bp->font, fg, - x + xoffset, y + yoffset, - textWidth, bp->text); + x + xoffset, y + yoffset, + textWidth, bp->text); } } else if (bp->labelPos == LABEL_POSITION_TOP) { const int ycenter = (height - textHeight - iconHeight - BUTTON_BORDER + 1) / 2; @@ -245,26 +245,26 @@ void DrawButton(ButtonNode *bp) yoffset = width <= height ? Max(BUTTON_BORDER, ycenter) : BUTTON_BORDER; RenderString(drawable, bp->font, fg, - x + xoffset, y + yoffset, - textWidth, bp->text); + x + xoffset, y + yoffset, + textWidth, bp->text); yoffset += textHeight + BUTTON_BORDER; } if(bp->icon) { xoffset = (width - iconWidth + 1) / 2; PutIcon(bp->icon, drawable, colors[fg], - x + xoffset, y + yoffset, - iconWidth, iconHeight); + x + xoffset, y + yoffset, + iconWidth, iconHeight); } } else if (bp->labelPos == LABEL_POSITION_BOTTOM) { const int ycenter = (height - iconHeight - textHeight - BUTTON_BORDER + 1) / 2; - xoffset = (width - iconWidth + 1) / 2; yoffset = width <= height ? Max(BUTTON_BORDER, ycenter) : BUTTON_BORDER; if(bp->icon) { + xoffset = (width - iconWidth + 1) / 2; PutIcon(bp->icon, drawable, colors[fg], - x + xoffset, y + yoffset, - iconWidth, iconHeight); + x + xoffset, y + yoffset, + iconWidth, iconHeight); yoffset += iconHeight + BUTTON_BORDER; } @@ -272,8 +272,8 @@ void DrawButton(ButtonNode *bp) if(textHeight > 0 && textWidth > 0) { xoffset = (width - textWidth + 1) / 2; RenderString(drawable, bp->font, fg, - x + xoffset, y + yoffset, - textWidth, bp->text); + x + xoffset, y + yoffset, + textWidth, bp->text); } } From 498c9158c4ca6863b4fa37d445cd33d52245871a Mon Sep 17 00:00:00 2001 From: Matt W Date: Tue, 23 Jul 2024 15:37:20 -0700 Subject: [PATCH 09/10] Add back the last missing comments --- src/button.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/button.c b/src/button.c index 909d741e..df86cf8d 100644 --- a/src/button.c +++ b/src/button.c @@ -220,6 +220,7 @@ void DrawButton(ButtonNode *bp) xoffset = BUTTON_BORDER; } + /* Display the icon. */ if(bp->icon) { yoffset = (height - iconHeight + 1) / 2; PutIcon(bp->icon, drawable, colors[fg], @@ -250,6 +251,7 @@ void DrawButton(ButtonNode *bp) yoffset += textHeight + BUTTON_BORDER; } + /* Display the icon. */ if(bp->icon) { xoffset = (width - iconWidth + 1) / 2; PutIcon(bp->icon, drawable, colors[fg], @@ -260,6 +262,7 @@ void DrawButton(ButtonNode *bp) const int ycenter = (height - iconHeight - textHeight - BUTTON_BORDER + 1) / 2; yoffset = width <= height ? Max(BUTTON_BORDER, ycenter) : BUTTON_BORDER; + /* Display the icon. */ if(bp->icon) { xoffset = (width - iconWidth + 1) / 2; PutIcon(bp->icon, drawable, colors[fg], From e28ce1b0f51974aa95c938ccf160a5eda6c190e7 Mon Sep 17 00:00:00 2001 From: Matt W Date: Thu, 25 Jul 2024 23:38:53 -0700 Subject: [PATCH 10/10] Document new "labelpos" attribute for . --- jwm.1.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/jwm.1.in b/jwm.1.in index 1723ec81..bc94ff32 100644 --- a/jwm.1.in +++ b/jwm.1.in @@ -687,6 +687,14 @@ Determines if a label is shown for items in the task list. The default is true. .RE .P +\fBlabelpos\fP \fIstring\fP +.RS +Determines the label position in the task list. The default is "right" where +the icon is on the left and the label is on the right. +Possible values are "right", "top" and "bottom". When the tray is vertical and "top" +or "bottom" is chosen, an alternate method for resizing the task list will be used. +.RE +.P \fBmaxwidth\fP \fIint\fP .RS The maximum width of an item in the task list. 0 indicates no maximum.