aboutsummaryrefslogtreecommitdiff
path: root/src/tray.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tray.c')
-rw-r--r--src/tray.c1104
1 files changed, 1104 insertions, 0 deletions
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;
+ }
+
+}
+
+