diff options
Diffstat (limited to 'src/traybutton.c')
-rw-r--r-- | src/traybutton.c | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/src/traybutton.c b/src/traybutton.c new file mode 100644 index 0000000..b596ba0 --- /dev/null +++ b/src/traybutton.c @@ -0,0 +1,454 @@ +/*************************************************************************** + ***************************************************************************/ + +#include "jwm.h" +#include "traybutton.h" +#include "tray.h" +#include "icon.h" +#include "image.h" +#include "error.h" +#include "root.h" +#include "main.h" +#include "color.h" +#include "font.h" +#include "button.h" +#include "misc.h" +#include "screen.h" +#include "desktop.h" +#include "popup.h" +#include "timing.h" + +#define BUTTON_SIZE 4 + +typedef struct TrayButtonType { + + TrayComponentType *cp; + + char *label; + char *popup; + char *iconName; + IconNode *icon; + + char *action; + + int mousex; + int mousey; + TimeType mouseTime; + + struct TrayButtonType *next; + +} TrayButtonType; + +static TrayButtonType *buttons; + +static void CheckedCreate(TrayComponentType *cp); +static void Create(TrayComponentType *cp); +static void Destroy(TrayComponentType *cp); +static void SetSize(TrayComponentType *cp, int width, int height); +static void Resize(TrayComponentType *cp); + +static void ProcessButtonEvent(TrayComponentType *cp, + int x, int y, int mask); +static void ProcessMotionEvent(TrayComponentType *cp, + int x, int y, int mask); + +/*************************************************************************** + ***************************************************************************/ +void InitializeTrayButtons() { + buttons = NULL; +} + +/*************************************************************************** + ***************************************************************************/ +void StartupTrayButtons() { + + TrayButtonType *bp; + + for(bp = buttons; bp; bp = bp->next) { + if(bp->label) { + bp->cp->requestedWidth + = GetStringWidth(FONT_TRAYBUTTON, bp->label) + 4; + bp->cp->requestedHeight + = GetStringHeight(FONT_TRAYBUTTON); + } else { + bp->cp->requestedWidth = 0; + bp->cp->requestedHeight = 0; + } + if(bp->iconName) { + bp->icon = LoadNamedIcon(bp->iconName); + if(bp->icon) { + bp->cp->requestedWidth += bp->icon->image->width; + bp->cp->requestedHeight += bp->icon->image->height; + } else { + Warning("could not load tray icon: \"%s\"", bp->iconName); + } + } + bp->cp->requestedWidth += 2 * BUTTON_SIZE; + bp->cp->requestedHeight += 2 * BUTTON_SIZE; + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ShutdownTrayButtons() { + +} + +/*************************************************************************** + ***************************************************************************/ +void DestroyTrayButtons() { + + TrayButtonType *bp; + + while(buttons) { + bp = buttons->next; + if(buttons->label) { + Release(buttons->label); + } + if(buttons->iconName) { + Release(buttons->iconName); + } + if(buttons->action) { + Release(buttons->action); + } + if(buttons->popup) { + Release(buttons->popup); + } + Release(buttons); + buttons = bp; + } + +} + +/*************************************************************************** + ***************************************************************************/ +TrayComponentType *CreateTrayButton(const char *iconName, + const char *label, const char *action, + const char *popup, int width, int height) { + + TrayButtonType *bp; + TrayComponentType *cp; + + if((label == NULL || strlen(label) == 0) + && (iconName == NULL || strlen(iconName) == 0)) { + Warning("no icon or label for TrayButton"); + return NULL; + } + + if(width < 0) { + Warning("invalid TrayButton width: %d", width); + width = 0; + } + if(height < 0) { + Warning("invalid TrayButton height: %d", height); + height = 0; + } + + bp = Allocate(sizeof(TrayButtonType)); + bp->next = buttons; + buttons = bp; + + bp->icon = NULL; + if(iconName) { + bp->iconName = Allocate(strlen(iconName) + 1); + strcpy(bp->iconName, iconName); + } else { + bp->iconName = NULL; + } + + if(label) { + bp->label = Allocate(strlen(label) + 1); + strcpy(bp->label, label); + } else { + bp->label = NULL; + } + + if(action) { + bp->action = Allocate(strlen(action) + 1); + strcpy(bp->action, action); + } else { + bp->action = NULL; + } + + if(popup) { + bp->popup = Allocate(strlen(popup) + 1); + strcpy(bp->popup, popup); + } else { + bp->popup = NULL; + } + + cp = CreateTrayComponent(); + cp->object = bp; + bp->cp = cp; + cp->requestedWidth = width; + cp->requestedHeight = height; + + cp->Create = CheckedCreate; + cp->Destroy = Destroy; + cp->SetSize = SetSize; + cp->Resize = Resize; + + cp->ProcessButtonEvent = ProcessButtonEvent; + if(popup || label) { + cp->ProcessMotionEvent = ProcessMotionEvent; + } + + return cp; + +} + +/*************************************************************************** + ***************************************************************************/ +void SetSize(TrayComponentType *cp, int width, int height) { + + TrayButtonType *bp; + int labelWidth, labelHeight; + int iconWidth, iconHeight; + double ratio; + + bp = (TrayButtonType*)cp->object; + + if(bp->icon) { + + if(bp->label) { + labelWidth = GetStringWidth(FONT_TRAYBUTTON, bp->label) + 4; + labelHeight = GetStringHeight(FONT_TRAYBUTTON); + } else { + labelWidth = 0; + labelHeight = 0; + } + + iconWidth = bp->icon->image->width; + iconHeight = bp->icon->image->height; + ratio = (double)iconWidth / iconHeight; + + if(width > 0) { + + /* Compute height from width. */ + iconWidth = width - labelWidth - 2 * BUTTON_SIZE; + iconHeight = iconWidth / ratio; + height = Max(iconHeight, labelHeight) + 2 * BUTTON_SIZE; + + } else if(height > 0) { + + /* Compute width from height. */ + iconHeight = height - 2 * BUTTON_SIZE; + iconWidth = iconHeight * ratio; + width = iconWidth + labelWidth + 2 * BUTTON_SIZE; + + } + + cp->width = width; + cp->height = height; + + } + +} + +/*************************************************************************** + ***************************************************************************/ +void CheckedCreate(TrayComponentType *cp) { + + TrayButtonType *bp; + + bp = (TrayButtonType*)cp->object; + + /* Validate the action for this tray button. */ + if(bp->action && strlen(bp->action) > 0) { + if(!strncmp(bp->action, "exec:", 5)) { + /* Valid. */ + } else if(!strncmp(bp->action, "root:", 5)) { + /* Valid. However, the specified root menu may not exist. + * This case is handled in ValidateTrayButtons. + */ + } else if(!strcmp(bp->action, "showdesktop")) { + /* Valid. */ + } else { + Warning("invalid TrayButton action: \"%s\"", bp->action); + } + } else { + /* Valid. However, root menu 1 may not exist. + * This case is handled in ValidateTrayButtons. + */ + } + + Create(cp); + +} + +/*************************************************************************** + ***************************************************************************/ +void Create(TrayComponentType *cp) { + + ButtonNode button; + TrayButtonType *bp; + int labelx; + + bp = (TrayButtonType*)cp->object; + + cp->pixmap = JXCreatePixmap(display, rootWindow, + cp->width, cp->height, rootDepth); + + JXSetForeground(display, rootGC, colors[COLOR_TRAYBUTTON_BG]); + JXFillRectangle(display, cp->pixmap, rootGC, 0, 0, cp->width, cp->height); + + ResetButton(&button, cp->pixmap, rootGC); + button.type = BUTTON_TASK; + button.width = cp->width - 3; + button.height = cp->height - 3; + button.x = 1; + button.y = 1; + DrawButton(&button); + + /* Compute the offset of the text. */ + if(bp->label) { + if(!bp->icon) { + labelx = 2 + cp->width / 2; + labelx -= GetStringWidth(FONT_TRAYBUTTON, bp->label) / 2; + } else { + labelx = cp->width; + labelx -= GetStringWidth(FONT_TRAYBUTTON, bp->label) + 4; + } + } else { + labelx = cp->width; + } + labelx -= BUTTON_SIZE; + + if(bp->icon) { + PutIcon(bp->icon, cp->pixmap, BUTTON_SIZE, BUTTON_SIZE, + labelx - BUTTON_SIZE, cp->height - BUTTON_SIZE * 2); + } + + if(bp->label) { + RenderString(cp->pixmap, FONT_TRAYBUTTON, COLOR_TRAYBUTTON_FG, + labelx + 2, cp->height / 2 - GetStringHeight(FONT_TRAYBUTTON) / 2, + cp->width - labelx, NULL, bp->label); + } + +} + +/*************************************************************************** + ***************************************************************************/ +void Resize(TrayComponentType *cp) { + + Destroy(cp); + Create(cp); + +} + +/*************************************************************************** + ***************************************************************************/ +void Destroy(TrayComponentType *cp) { + if(cp->pixmap != None) { + JXFreePixmap(display, cp->pixmap); + } +} + +/*************************************************************************** + ***************************************************************************/ +void ProcessButtonEvent(TrayComponentType *cp, int x, int y, int mask) { + + const ScreenType *sp; + int mwidth, mheight; + int button; + + TrayButtonType *bp = (TrayButtonType*)cp->object; + + Assert(bp); + + if(bp->action && strlen(bp->action) > 0) { + if(!strncmp(bp->action, "exec:", 5)) { + RunCommand(bp->action + 5); + return; + } else if(!strncmp(bp->action, "root:", 5)) { + button = atoi(bp->action + 5); + } else if(!strcmp(bp->action, "showdesktop")) { + ShowDesktop(); + return; + } else { + return; + } + } else { + button = 1; + } + + GetRootMenuSize(button, &mwidth, &mheight); + + sp = GetCurrentScreen(cp->screenx, cp->screeny); + + if(cp->tray->layout == LAYOUT_HORIZONTAL) { + x = cp->screenx; + if(cp->screeny + cp->height / 2 < sp->y + sp->height / 2) { + y = cp->screeny + cp->height; + } else { + y = cp->screeny - mheight; + } + } else { + y = cp->screeny; + if(cp->screenx + cp->width / 2 < sp->x + sp->width / 2) { + x = cp->screenx + cp->width; + } else { + x = cp->screenx - mwidth; + } + } + + ShowRootMenu(button, x, y); + +} + +/*************************************************************************** + ***************************************************************************/ +void ProcessMotionEvent(TrayComponentType *cp, int x, int y, int mask) { + + TrayButtonType *bp = (TrayButtonType*)cp->object; + + bp->mousex = cp->screenx + x; + bp->mousey = cp->screeny + y; + GetCurrentTime(&bp->mouseTime); + +} + +/*************************************************************************** + ***************************************************************************/ +void SignalTrayButton(const TimeType *now, int x, int y) { + + TrayButtonType *bp; + const char *popup; + + for(bp = buttons; bp; bp = bp->next) { + if(bp->popup) { + popup = bp->popup; + } else if(bp->label) { + popup = bp->label; + } else { + continue; + } + if(abs(bp->mousex - x) < POPUP_DELTA + && abs(bp->mousey - y) < POPUP_DELTA) { + if(GetTimeDifference(now, &bp->mouseTime) >= popupDelay) { + ShowPopup(x, y, popup); + } + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ValidateTrayButtons() { + + TrayButtonType *bp; + int bindex; + + for(bp = buttons; bp; bp = bp->next) { + if(bp->action && !strncmp(bp->action, "root:", 5)) { + bindex = atoi(bp->action + 5); + if(!IsRootMenuDefined(bindex)) { + Warning("tray button: root menu %d not defined", bindex); + } + } + } + +} + |