From a041d9898e6d699bd8c0c25482ec574feb03c547 Mon Sep 17 00:00:00 2001 From: "John Ankarstr\\xf6m" Date: Sat, 29 May 2021 12:54:47 +0200 Subject: First commit This is the original state of the released tarball for JWM 1.8, which will serve as my starting point for further modifications. --- src/tray.c | 1104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1104 insertions(+) create mode 100644 src/tray.c (limited to 'src/tray.c') diff --git a/src/tray.c b/src/tray.c new file mode 100644 index 0000000..d30dd1e --- /dev/null +++ b/src/tray.c @@ -0,0 +1,1104 @@ +/*************************************************************************** + * Functions to handle the tray. + * Copyright (C) 2004 Joe Wingbermuehle + ***************************************************************************/ + +#include "jwm.h" +#include "tray.h" +#include "color.h" +#include "main.h" +#include "pager.h" +#include "cursor.h" +#include "error.h" +#include "taskbar.h" +#include "menu.h" +#include "timing.h" + +#define DEFAULT_TRAY_WIDTH 32 +#define DEFAULT_TRAY_HEIGHT 32 + +static TrayType *trays; +static Window supportingWindow; + +static void HandleTrayExpose(TrayType *tp, const XExposeEvent *event); +static void HandleTrayEnterNotify(TrayType *tp, const XCrossingEvent *event); + +static void HandleTrayButtonPress(TrayType *tp, const XButtonEvent *event); +static void HandleTrayMotionNotify(TrayType *tp, const XMotionEvent *event); + +static void ComputeTraySize(TrayType *tp); +static int ComputeMaxWidth(TrayType *tp); +static int ComputeTotalWidth(TrayType *tp); +static int ComputeMaxHeight(TrayType *tp); +static int ComputeTotalHeight(TrayType *tp); +static int CheckHorizontalFill(TrayType *tp); +static int CheckVerticalFill(TrayType *tp); +static void LayoutTray(TrayType *tp, int *variableSize, + int *variableRemainder); + +/*************************************************************************** + ***************************************************************************/ +void InitializeTray() { + trays = NULL; + supportingWindow = None; +} + +/*************************************************************************** + ***************************************************************************/ +void StartupTray() { + + XSetWindowAttributes attr; + unsigned long attrMask; + TrayType *tp; + TrayComponentType *cp; + int variableSize; + int variableRemainder; + int width, height; + int xoffset, yoffset; + + for(tp = trays; tp; tp = tp->next) { + + LayoutTray(tp, &variableSize, &variableRemainder); + + /* Create the tray window. */ + /* The window is created larger for a border. */ + attrMask = CWOverrideRedirect; + attr.override_redirect = True; + + /* We can't use PointerMotionHintMask since the exact position + * of the mouse on the tray is important for popups. */ + attrMask |= CWEventMask; + attr.event_mask + = ButtonPressMask + | SubstructureNotifyMask + | ExposureMask + | KeyPressMask + | EnterWindowMask + | PointerMotionMask; + + attrMask |= CWBackPixel; + attr.background_pixel = colors[COLOR_TRAY_BG]; + + tp->window = JXCreateWindow(display, rootWindow, + tp->x, tp->y, tp->width, tp->height, + 0, rootDepth, InputOutput, rootVisual, attrMask, &attr); + + SetDefaultCursor(tp->window); + + /* Create and layout items on the tray. */ + xoffset = tp->border; + yoffset = tp->border; + for(cp = tp->components; cp; cp = cp->next) { + + if(cp->Create) { + if(tp->layout == LAYOUT_HORIZONTAL) { + height = tp->height - 2 * tp->border; + width = cp->width; + if(width == 0) { + width = variableSize; + if(variableRemainder) { + ++width; + --variableRemainder; + } + } + } else { + width = tp->width - 2 * tp->border; + height = cp->height; + if(height == 0) { + height = variableSize; + if(variableRemainder) { + ++height; + --variableRemainder; + } + } + } + cp->width = width; + cp->height = height; + (cp->Create)(cp); + } + + cp->x = xoffset; + cp->y = yoffset; + cp->screenx = tp->x + xoffset; + cp->screeny = tp->y + yoffset; + + if(cp->window != None) { + JXReparentWindow(display, cp->window, tp->window, + xoffset, yoffset); + } + + if(tp->layout == LAYOUT_HORIZONTAL) { + xoffset += cp->width; + } else { + yoffset += cp->height; + } + } + + /* Show the tray. */ + JXMapWindow(display, tp->window); + + } + + UpdatePager(); + UpdateTaskBar(); + +} + +/*************************************************************************** + ***************************************************************************/ +void ShutdownTray() { + + TrayType *tp; + TrayComponentType *cp; + + for(tp = trays; tp; tp = tp->next) { + for(cp = tp->components; cp; cp = cp->next) { + if(cp->Destroy) { + (cp->Destroy)(cp); + } + } + JXDestroyWindow(display, tp->window); + } + + if(supportingWindow != None) { + XDestroyWindow(display, supportingWindow); + supportingWindow = None; + } + +} + + +/*************************************************************************** + ***************************************************************************/ +void DestroyTray() { + + TrayType *tp; + TrayComponentType *cp; + + while(trays) { + tp = trays->next; + + while(trays->components) { + cp = trays->components->next; + Release(trays->components); + trays->components = cp; + } + Release(trays); + + trays = tp; + } + +} + +/*************************************************************************** + ***************************************************************************/ +TrayType *CreateTray() { + + TrayType *tp; + + tp = Allocate(sizeof(TrayType)); + + tp->x = 0; + tp->y = -1; + tp->requestedWidth = 0; + tp->requestedHeight = 0; + tp->width = 0; + tp->height = 0; + tp->border = 1; + tp->layer = DEFAULT_TRAY_LAYER; + tp->layout = LAYOUT_HORIZONTAL; + tp->valign = TALIGN_FIXED; + tp->halign = TALIGN_FIXED; + + tp->autoHide = 0; + tp->hidden = 0; + + tp->window = None; + + tp->components = NULL; + tp->componentsTail = NULL; + + tp->next = trays; + trays = tp; + + return tp; + +} + +/*************************************************************************** + ***************************************************************************/ +TrayComponentType *CreateTrayComponent() { + + TrayComponentType *cp; + + cp = Allocate(sizeof(TrayComponentType)); + + cp->tray = NULL; + cp->object = NULL; + + cp->x = 0; + cp->y = 0; + cp->requestedWidth = 0; + cp->requestedHeight = 0; + cp->width = 0; + cp->height = 0; + + cp->window = None; + cp->pixmap = None; + + cp->Create = NULL; + cp->Destroy = NULL; + + cp->SetSize = NULL; + cp->Resize = NULL; + + cp->ProcessButtonEvent = NULL; + cp->ProcessMotionEvent = NULL; + + cp->next = NULL; + + return cp; + +} + +/*************************************************************************** + ***************************************************************************/ +void AddTrayComponent(TrayType *tp, TrayComponentType *cp) { + + Assert(tp); + Assert(cp); + + cp->tray = tp; + + if(tp->componentsTail) { + tp->componentsTail->next = cp; + } else { + tp->components = cp; + } + tp->componentsTail = cp; + cp->next = NULL; + +} + +/*************************************************************************** + * Compute the max component width. + ***************************************************************************/ +int ComputeMaxWidth(TrayType *tp) { + + TrayComponentType *cp; + int result; + int temp; + + result = 0; + for(cp = tp->components; cp; cp = cp->next) { + temp = cp->width; + if(temp > 0) { + temp += 2 * tp->border; + if(temp > result) { + result = temp; + } + } + } + + return result; + +} + +/*************************************************************************** + ***************************************************************************/ +int ComputeTotalWidth(TrayType *tp) { + + TrayComponentType *cp; + int result; + + result = 2 * tp->border; + for(cp = tp->components; cp; cp = cp->next) { + result += cp->width; + } + + return result; + +} + +/*************************************************************************** + * Compute the max component height. + ***************************************************************************/ +int ComputeMaxHeight(TrayType *tp) { + + TrayComponentType *cp; + int result; + int temp; + + result = 0; + for(cp = tp->components; cp; cp = cp->next) { + temp = cp->height; + if(temp > 0) { + temp += 2 * tp->border; + if(temp > result) { + result = temp; + } + } + } + + return result; + +} + +/*************************************************************************** + ***************************************************************************/ +int ComputeTotalHeight(TrayType *tp) { + + TrayComponentType *cp; + int result; + + result = 2 * tp->border; + for(cp = tp->components; cp; cp = cp->next) { + result += cp->height; + } + + return result; + +} + +/*************************************************************************** + ***************************************************************************/ +int CheckHorizontalFill(TrayType *tp) { + + TrayComponentType *cp; + + for(cp = tp->components; cp; cp = cp->next) { + if(cp->width == 0) { + return 1; + } + } + + return 0; + +} + +/*************************************************************************** + ***************************************************************************/ +int CheckVerticalFill(TrayType *tp) { + + TrayComponentType *cp; + + for(cp = tp->components; cp; cp = cp->next) { + if(cp->height == 0) { + return 1; + } + } + + return 0; + +} + +/*************************************************************************** + ***************************************************************************/ +void ComputeTraySize(TrayType *tp) { + + TrayComponentType *cp; + + /* Determine the first dimension. */ + if(tp->layout == LAYOUT_HORIZONTAL) { + + if(tp->height == 0) { + tp->height = ComputeMaxHeight(tp); + } + + if(tp->height == 0) { + tp->height = DEFAULT_TRAY_HEIGHT; + } + + } else { + + if(tp->width == 0) { + tp->width = ComputeMaxWidth(tp); + } + + if(tp->width == 0) { + tp->width = DEFAULT_TRAY_WIDTH; + } + + } + + /* Now at least one size is known. Inform the components. */ + for(cp = tp->components; cp; cp = cp->next) { + if(cp->SetSize) { + if(tp->layout == LAYOUT_HORIZONTAL) { + (cp->SetSize)(cp, 0, tp->height - 2 * tp->border); + } else { + (cp->SetSize)(cp, tp->width - 2 * tp->border, 0); + } + } + } + + /* Determine the missing dimension. */ + if(tp->layout == LAYOUT_HORIZONTAL) { + if(tp->width == 0) { + if(CheckHorizontalFill(tp)) { + tp->width = rootWidth; + } else { + tp->width = ComputeTotalWidth(tp); + } + if(tp->width == 0) { + tp->width = DEFAULT_TRAY_WIDTH; + } + } + } else { + if(tp->height == 0) { + if(CheckVerticalFill(tp)) { + tp->height = rootHeight; + } else { + tp->height = ComputeTotalHeight(tp); + } + if(tp->height == 0) { + tp->height = DEFAULT_TRAY_HEIGHT; + } + } + } + + /* Compute the tray location. */ + switch(tp->valign) { + case TALIGN_TOP: + tp->y = 0; + break; + case TALIGN_BOTTOM: + tp->y = rootHeight - tp->height + 1; + break; + case TALIGN_CENTER: + tp->y = rootHeight / 2 - tp->height / 2; + break; + default: + if(tp->y < 0) { + tp->y = rootHeight + tp->y - tp->height + 1; + } + break; + } + + switch(tp->halign) { + case TALIGN_LEFT: + tp->x = 0; + break; + case TALIGN_RIGHT: + tp->x = rootWidth - tp->width + 1; + break; + case TALIGN_CENTER: + tp->x = rootWidth / 2 - tp->width / 2; + break; + default: + if(tp->x < 0) { + tp->x = rootWidth + tp->x - tp->width + 1; + } + break; + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ShowTray(TrayType *tp) { + + Window win1, win2; + int winx, winy; + unsigned int mask; + int mousex, mousey; + + if(tp->hidden) { + + tp->hidden = 0; + JXMoveWindow(display, tp->window, tp->x, tp->y); + + JXQueryPointer(display, rootWindow, &win1, &win2, + &mousex, &mousey, &winx, &winy, &mask); + SetMousePosition(mousex, mousey); + + } + +} + +/*************************************************************************** + ***************************************************************************/ +void HideTray(TrayType *tp) { + + int x, y; + + tp->hidden = 1; + + /* Determine where to move the tray. */ + if(tp->layout == LAYOUT_HORIZONTAL) { + + x = tp->x; + + if(tp->y >= rootHeight / 2) { + y = rootHeight - 1; + } else { + y = 1 - tp->height; + } + + } else { + + y = tp->y; + + if(tp->x >= rootWidth / 2) { + x = rootWidth - 1; + } else { + x = 1 - tp->width; + } + + } + + /* Move it. */ + JXMoveWindow(display, tp->window, x, y); + +} + +/*************************************************************************** + ***************************************************************************/ +int ProcessTrayEvent(const XEvent *event) { + + TrayType *tp; + + for(tp = trays; tp; tp = tp->next) { + if(event->xany.window == tp->window) { + switch(event->type) { + case Expose: + HandleTrayExpose(tp, &event->xexpose); + return 1; + case EnterNotify: + HandleTrayEnterNotify(tp, &event->xcrossing); + return 1; + case ButtonPress: + HandleTrayButtonPress(tp, &event->xbutton); + return 1; + case MotionNotify: + HandleTrayMotionNotify(tp, &event->xmotion); + return 1; + default: + return 0; + } + } + } + + return 0; + +} + +/*************************************************************************** + ***************************************************************************/ +void SignalTray(const TimeType *now, int x, int y) { + + TrayType *tp; + + for(tp = trays; tp; tp = tp->next) { + if(tp->autoHide && !tp->hidden && !menuShown) { + if(x < tp->x || x >= tp->x + tp->width + || y < tp->y || y >= tp->y + tp->height) { + HideTray(tp); + } + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void HandleTrayExpose(TrayType *tp, const XExposeEvent *event) { + + DrawSpecificTray(tp); + +} + +/*************************************************************************** + ***************************************************************************/ +void HandleTrayEnterNotify(TrayType *tp, const XCrossingEvent *event) { + + ShowTray(tp); + +} + +/*************************************************************************** + ***************************************************************************/ +void HandleTrayButtonPress(TrayType *tp, const XButtonEvent *event) { + + TrayComponentType *cp; + int xoffset, yoffset; + int width, height; + int x, y; + int mask; + + xoffset = tp->border; + yoffset = tp->border; + for(cp = tp->components; cp; cp = cp->next) { + width = cp->width; + height = cp->height; + if(event->x >= xoffset && event->x < xoffset + width) { + if(event->y >= yoffset && event->y < yoffset + height) { + if(cp->ProcessButtonEvent) { + x = event->x - xoffset; + y = event->y - yoffset; + mask = event->button; + (cp->ProcessButtonEvent)(cp, x, y, mask); + } + break; + } + } + if(tp->layout == LAYOUT_HORIZONTAL) { + xoffset += width; + } else { + yoffset += height; + } + } +} + +/*************************************************************************** + ***************************************************************************/ +void HandleTrayMotionNotify(TrayType *tp, const XMotionEvent *event) { + + TrayComponentType *cp; + int xoffset, yoffset; + int width, height; + int x, y; + int mask; + + xoffset = tp->border; + yoffset = tp->border; + for(cp = tp->components; cp; cp = cp->next) { + width = cp->width; + height = cp->height; + if(event->x >= xoffset && event->x < xoffset + width) { + if(event->y >= yoffset && event->y < yoffset + height) { + if(cp->ProcessMotionEvent) { + x = event->x - xoffset; + y = event->y - yoffset; + mask = event->state; + (cp->ProcessMotionEvent)(cp, x, y, mask); + } + break; + } + } + if(tp->layout == LAYOUT_HORIZONTAL) { + xoffset += width; + } else { + yoffset += height; + } + } +} + +/*************************************************************************** + ***************************************************************************/ +void DrawTray() { + + TrayType *tp; + + if(shouldExit) { + return; + } + + for(tp = trays; tp; tp = tp->next) { + DrawSpecificTray(tp); + } + +} + +/*************************************************************************** + ***************************************************************************/ +void DrawSpecificTray(const TrayType *tp) { + + TrayComponentType *cp; + int x; + + Assert(tp); + + /* Draw components. */ + for(cp = tp->components; cp; cp = cp->next) { + UpdateSpecificTray(tp, cp); + } + + /* Draw the border. */ + for(x = 0; x < tp->border; x++) { + + /* Top */ + JXSetForeground(display, rootGC, colors[COLOR_TRAY_UP]); + JXDrawLine(display, tp->window, rootGC, + 0, x, + tp->width - x - 1, x); + + /* Bottom */ + JXSetForeground(display, rootGC, colors[COLOR_TRAY_DOWN]); + JXDrawLine(display, tp->window, rootGC, + x + 1, tp->height - x - 1, + tp->width - x - 2, tp->height - x - 1); + + /* Left */ + JXSetForeground(display, rootGC, colors[COLOR_TRAY_UP]); + JXDrawLine(display, tp->window, rootGC, + x, x, + x, tp->height - x - 1); + + /* Right */ + JXSetForeground(display, rootGC, colors[COLOR_TRAY_DOWN]); + JXDrawLine(display, tp->window, rootGC, + tp->width - x - 1, x + 1, + tp->width - x - 1, tp->height - x - 1); + + } + +} + +/*************************************************************************** + ***************************************************************************/ +void UpdateSpecificTray(const TrayType *tp, const TrayComponentType *cp) { + + if(cp->pixmap != None && !shouldExit) { + JXCopyArea(display, cp->pixmap, tp->window, rootGC, 0, 0, + cp->width, cp->height, cp->x, cp->y); + } + +} + +/*************************************************************************** + ***************************************************************************/ +void LayoutTray(TrayType *tp, int *variableSize, int *variableRemainder) { + + TrayComponentType *cp; + int variableCount; + int width, height; + int temp; + + tp->width = tp->requestedWidth; + tp->height = tp->requestedHeight; + + for(cp = tp->components; cp; cp = cp->next) { + cp->width = cp->requestedWidth; + cp->height = cp->requestedHeight; + } + + ComputeTraySize(tp); + + /* Get the remaining size after setting fixed size components. */ + /* Also, keep track of the number of variable size components. */ + width = tp->width - 2 * tp->border; + height = tp->height - 2 * tp->border; + variableCount = 0; + for(cp = tp->components; cp; cp = cp->next) { + if(tp->layout == LAYOUT_HORIZONTAL) { + temp = cp->width; + if(temp > 0) { + width -= temp; + } else { + ++variableCount; + } + } else { + temp = cp->height; + if(temp > 0) { + height -= temp; + } else { + ++variableCount; + } + } + } + + /* Distribute excess size among variable size components. + * If there are no variable size components, shrink the tray. + * If we are out of room, just give them a size of one. + */ + *variableSize = 1; + *variableRemainder = 0; + if(tp->layout == LAYOUT_HORIZONTAL) { + if(variableCount) { + if(width >= variableCount) { + *variableSize = width / variableCount; + *variableRemainder = width % variableCount; + } + } else if(width > 0) { + tp->width -= width; + } + } else { + if(variableCount) { + if(height >= variableCount) { + *variableSize = height / variableCount; + *variableRemainder = height % variableCount; + } + } else if(height > 0) { + tp->height -= height; + } + } + +} + +/*************************************************************************** + ***************************************************************************/ +void ResizeTray(TrayType *tp) { + + TrayComponentType *cp; + int variableSize; + int variableRemainder; + int xoffset, yoffset; + int width, height; + + Assert(tp); + + LayoutTray(tp, &variableSize, &variableRemainder); + + /* Reposition items on the tray. */ + xoffset = tp->border; + yoffset = tp->border; + for(cp = tp->components; cp; cp = cp->next) { + + cp->x = xoffset; + cp->y = yoffset; + cp->screenx = tp->x + xoffset; + cp->screeny = tp->y + yoffset; + + if(cp->Resize) { + if(tp->layout == LAYOUT_HORIZONTAL) { + height = tp->height - 2 * tp->border; + width = cp->width; + if(width == 0) { + width = variableSize; + if(variableRemainder) { + ++width; + --variableRemainder; + } + } + } else { + width = tp->width - 2 * tp->border; + height = cp->height; + if(height == 0) { + height = variableSize; + if(variableRemainder) { + ++height; + --variableRemainder; + } + } + } + cp->width = width; + cp->height = height; + (cp->Resize)(cp); + } + + if(cp->window != None) { + JXMoveWindow(display, cp->window, xoffset, yoffset); + } + + if(tp->layout == LAYOUT_HORIZONTAL) { + xoffset += cp->width; + } else { + yoffset += cp->height; + } + } + + JXMoveResizeWindow(display, tp->window, tp->x, tp->y, + tp->width, tp->height); + + UpdateTaskBar(); + DrawSpecificTray(tp); + + if(tp->hidden) { + HideTray(tp); + } + +} + +/*************************************************************************** + ***************************************************************************/ +TrayType *GetTrays() { + return trays; +} + +/*************************************************************************** + ***************************************************************************/ +Window GetSupportingWindow() { + + if(trays) { + return trays->window; + } else if(supportingWindow != None) { + return supportingWindow; + } else { + supportingWindow = JXCreateSimpleWindow(display, rootWindow, + 0, 0, 1, 1, 0, 0, 0); + return supportingWindow; + } + +} + +/*************************************************************************** + ***************************************************************************/ +void SetAutoHideTray(TrayType *tp, int v) { + Assert(tp); + tp->autoHide = v; +} + +/*************************************************************************** + ***************************************************************************/ +void SetTrayX(TrayType *tp, const char *str) { + Assert(tp); + Assert(str); + tp->x = atoi(str); +} + +/*************************************************************************** + ***************************************************************************/ +void SetTrayY(TrayType *tp, const char *str) { + Assert(tp); + Assert(str); + tp->y = atoi(str); +} + +/*************************************************************************** + ***************************************************************************/ +void SetTrayWidth(TrayType *tp, const char *str) { + + int width; + + Assert(tp); + Assert(str); + + width = atoi(str); + + if(width < 0) { + Warning("invalid tray width: %d", width); + } else { + tp->requestedWidth = width; + } + +} + +/*************************************************************************** + ***************************************************************************/ +void SetTrayHeight(TrayType *tp, const char *str) { + + int height; + + Assert(tp); + Assert(str); + + height = atoi(str); + + if(height < 0) { + Warning("invalid tray height: %d", height); + } else { + tp->requestedHeight = height; + } + +} + + +/*************************************************************************** + ***************************************************************************/ +void SetTrayLayout(TrayType *tp, const char *str) { + + Assert(tp); + + if(!str) { + + /* Compute based on requested size. */ + + } else if(!strcmp(str, "horizontal")) { + + tp->layout = LAYOUT_HORIZONTAL; + return; + + } else if(!strcmp(str, "vertical")) { + + tp->layout = LAYOUT_VERTICAL; + return; + + } else { + Warning("invalid tray layout: \"%s\"", str); + } + + /* Prefer horizontal layout, but use vertical if + * width is finite and height is larger than width or infinite. + */ + if(tp->requestedWidth > 0 + && (tp->requestedHeight == 0 + || tp->requestedHeight > tp->requestedWidth)) { + tp->layout = LAYOUT_VERTICAL; + } else { + tp->layout = LAYOUT_HORIZONTAL; + } + +} + +/*************************************************************************** + ***************************************************************************/ +void SetTrayLayer(TrayType *tp, const char *str) { + + int temp; + + Assert(tp); + Assert(str); + + temp = atoi(str); + if(temp < LAYER_BOTTOM || temp > LAYER_TOP) { + Warning("invalid tray layer: %d", temp); + tp->layer = DEFAULT_TRAY_LAYER; + } else { + tp->layer = temp; + } + +} + +/*************************************************************************** + ***************************************************************************/ +void SetTrayBorder(TrayType *tp, const char *str) { + + int temp; + + Assert(tp); + Assert(str); + + temp = atoi(str); + if(temp < MIN_TRAY_BORDER || temp > MAX_TRAY_BORDER) { + Warning("invalid tray border: %d", temp); + tp->border = DEFAULT_TRAY_BORDER; + } else { + tp->border = temp; + } + +} + +/*************************************************************************** + ***************************************************************************/ +void SetTrayHorizontalAlignment(TrayType *tp, const char *str) { + + Assert(tp); + + if(!str || !strcmp(str, "fixed")) { + tp->halign = TALIGN_FIXED; + } else if(!strcmp(str, "left")) { + tp->halign = TALIGN_LEFT; + } else if(!strcmp(str, "right")) { + tp->halign = TALIGN_RIGHT; + } else if(!strcmp(str, "center")) { + tp->halign = TALIGN_CENTER; + } else { + Warning("invalid tray horizontal alignment: \"%s\"", str); + tp->halign = TALIGN_FIXED; + } + +} + +/*************************************************************************** + ***************************************************************************/ +void SetTrayVerticalAlignment(TrayType *tp, const char *str) { + + Assert(tp); + + if(!str || !strcmp(str, "fixed")) { + tp->valign = TALIGN_FIXED; + } else if(!strcmp(str, "top")) { + tp->valign = TALIGN_TOP; + } else if(!strcmp(str, "bottom")) { + tp->valign = TALIGN_BOTTOM; + } else if(!strcmp(str, "center")) { + tp->valign = TALIGN_CENTER; + } else { + Warning("invalid tray vertical alignment: \"%s\"", str); + tp->valign = TALIGN_FIXED; + } + +} + + -- cgit v1.2.3