#include "copyright.h"
#include <config.h>
#include "XMenuInt.h"
#define toggle_color(x) \
((x) == menu->bkgnd_color ? menu->s_frg_color : menu->bkgnd_color)
#define S_QUE_SIZE 300
#define P_QUE_SIZE 20
#define BUFFER_SIZE (S_QUE_SIZE >= P_QUE_SIZE ? S_QUE_SIZE : P_QUE_SIZE)
typedef struct _xmwinquedef {
int sq_size;
XMSelect *sq[S_QUE_SIZE];
XMSelect **sq_ptr;
int pq_size;
XMPane *pq[P_QUE_SIZE];
XMPane **pq_ptr;
} XMWinQue;
static Bool _XMWinQueIsInit = False;
static XMWinQue _XMWinQue;
int _XMErrorCode = XME_NO_ERROR;
char *
_XMErrorList[XME_CODE_COUNT] = {
"No error",
"Menu not initialized",
"Argument out of bounds",
"Pane not found",
"Selection not found",
"Invalid menu style parameter",
"Unable to grab mouse",
"Unable to interpret locator",
"Unable to calloc memory",
"Unable to create XAssocTable",
"Unable to store bitmap",
"Unable to make tile pixmaps",
"Unable to make pixmap",
"Unable to create cursor",
"Unable to open font",
"Unable to create windows",
"Unable to create transparencies",
};
int (*_XMEventHandler)() = NULL;
_XMWinQueInit()
{
if (!_XMWinQueIsInit) {
register int i;
for (i = 0; i < S_QUE_SIZE; i++)
_XMWinQue.sq[i] = 0;
for (i = 0; i < P_QUE_SIZE; i++)
_XMWinQue.pq[i] = 0;
_XMWinQue.sq_size = _XMWinQue.pq_size = 0;
_XMWinQue.sq_ptr = _XMWinQue.sq;
_XMWinQue.pq_ptr = _XMWinQue.pq;
}
}
int
_XMWinQueAddPane(display, menu, p_ptr)
register Display *display;
register XMenu *menu;
register XMPane *p_ptr;
{
if (_XMWinQue.pq_size == P_QUE_SIZE) {
if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE);
}
*_XMWinQue.pq_ptr = p_ptr;
_XMWinQue.pq_ptr++;
_XMWinQue.pq_size++;
_XMErrorCode = XME_NO_ERROR;
return(_SUCCESS);
}
int
_XMWinQueAddSelection(display, menu, s_ptr)
register Display *display;
register XMenu *menu;
register XMSelect *s_ptr;
{
if (_XMWinQue.sq_size == S_QUE_SIZE) {
if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE);
}
*_XMWinQue.sq_ptr = s_ptr;
_XMWinQue.sq_ptr++;
_XMWinQue.sq_size++;
_XMErrorCode = XME_NO_ERROR;
return(_SUCCESS);
}
int
_XMWinQueFlush(display, menu, pane, select)
register Display *display;
register XMenu *menu;
register XMPane *pane;
{
register int pq_index;
register int sq_index;
register XMPane *p_ptr;
register XMSelect *s_ptr;
unsigned long valuemask;
XSetWindowAttributes *attributes;
if (_XMWinQue.pq_size > 0) {
valuemask = (CWBackPixmap | CWBorderPixel | CWOverrideRedirect);
attributes = (XSetWindowAttributes *)malloc(sizeof(XSetWindowAttributes));
attributes->border_pixel = menu->p_bdr_color;
attributes->background_pixmap = menu->inact_pixmap;
attributes->override_redirect = True;
for (pq_index = _XMWinQue.pq_size - 1;
pq_index >= 0;
pq_index--)
{
p_ptr = _XMWinQue.pq[pq_index];
if (p_ptr == pane) break;
p_ptr->window = XCreateWindow(display,
menu->parent,
p_ptr->window_x,
p_ptr->window_y,
p_ptr->window_w,
p_ptr->window_h,
menu->p_bdr_width,
CopyFromParent,
InputOutput,
CopyFromParent,
valuemask,
attributes);
XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr);
XSelectInput(display, p_ptr->window, menu->p_events);
}
for (pq_index = 0;
pq_index < _XMWinQue.pq_size;
pq_index++)
{
p_ptr = _XMWinQue.pq[pq_index];
p_ptr->window = XCreateWindow(display,
menu->parent,
p_ptr->window_x,
p_ptr->window_y,
p_ptr->window_w,
p_ptr->window_h,
menu->p_bdr_width,
CopyFromParent,
InputOutput,
CopyFromParent,
valuemask,
attributes);
XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr);
XSelectInput(display, p_ptr->window, menu->p_events);
if (p_ptr == pane) break;
}
_XMWinQue.pq_size = 0;
_XMWinQue.pq_ptr = _XMWinQue.pq;
}
if (_XMWinQue.sq_size > 0) {
for (sq_index = 0; sq_index < _XMWinQue.sq_size; sq_index++) {
s_ptr = _XMWinQue.sq[sq_index];
s_ptr->window = XCreateWindow(display,
s_ptr->parent_p->window,
s_ptr->window_x,
s_ptr->window_y,
s_ptr->window_w,
s_ptr->window_h,
0,
CopyFromParent,
InputOnly,
CopyFromParent,
0,
attributes);
XMakeAssoc(display, menu->assoc_tab, s_ptr->window, s_ptr);
XSelectInput(display, s_ptr->window, menu->s_events);
}
_XMWinQue.sq_size = 0;
_XMWinQue.sq_ptr = _XMWinQue.sq;
}
XFlush(display);
_XMErrorCode = XME_NO_ERROR;
return(_SUCCESS);
}
XMPane *
_XMGetPanePtr(menu, p_num)
register XMenu *menu;
register int p_num;
{
register XMPane *p_ptr;
register int i;
if ((p_num < 0) || (p_num > (menu->p_count - 1))) {
_XMErrorCode = XME_P_NOT_FOUND;
return(NULL);
}
p_ptr = menu->p_list->next;
for (i = 0; i < p_num; i++) p_ptr = p_ptr->next;
_XMErrorCode = XME_NO_ERROR;
return(p_ptr);
}
XMSelect *
_XMGetSelectionPtr(p_ptr, s_num)
register XMPane *p_ptr;
register int s_num;
{
register XMSelect *s_ptr;
register int i;
if ((s_num < 0) || (s_num > (p_ptr->s_count - 1))) {
_XMErrorCode = XME_S_NOT_FOUND;
return(NULL);
}
s_ptr = p_ptr->s_list->next;
for (i = 0; i < s_num; i++) s_ptr = s_ptr->next;
_XMErrorCode = XME_NO_ERROR;
return(s_ptr);
}
_XMRecomputeGlobals(display, menu)
register Display *display;
register XMenu *menu;
{
register XMPane *p_ptr;
register XMSelect *s_ptr;
register int max_p_label = 0;
register int max_s_label = 0;
register int s_count = 0;
int p_s_pad;
int p_s_diff;
int p_height;
int p_width;
int s_width;
int screen;
for (
p_ptr = menu->p_list->next;
p_ptr != menu->p_list;
p_ptr = p_ptr->next
){
max_p_label = max(max_p_label, p_ptr->label_width);
s_count = max(s_count, p_ptr->s_count);
for (
s_ptr = p_ptr->s_list->next;
s_ptr != p_ptr->s_list;
s_ptr = s_ptr->next
){
max_s_label = max(max_s_label, s_ptr->label_width);
}
}
p_height = (menu->flag_height << 1) + (menu->s_y_off * s_count);
p_s_pad = menu->p_x_off << 1;
p_width = max_p_label + p_s_pad;
s_width = max_s_label + (menu->s_fnt_pad << 1) + (menu->s_bdr_width << 1);
p_s_diff = p_width - s_width;
if (p_s_diff < p_s_pad) {
p_width = s_width + p_s_pad;
}
else if (p_s_diff > p_s_pad) {
s_width = p_width - p_s_pad;
}
menu->s_count = s_count;
menu->p_height = p_height;
menu->p_width = p_width;
menu->s_width = s_width;
screen = DefaultScreen(display);
if (menu->x_pos + menu->width > DisplayWidth(display, screen))
menu->x_pos = DisplayWidth(display, screen) - menu->width;
else if (menu->x_pos < 0) menu->x_pos = 0;
if(menu->y_pos + menu->height > DisplayHeight(display, screen))
menu->y_pos = DisplayHeight(display, screen) - menu->height;
else if (menu->y_pos < 0) menu->y_pos = 0;
}
int
_XMRecomputePane(display, menu, p_ptr, p_num)
register Display *display;
register XMenu *menu;
register XMPane *p_ptr;
register int p_num;
{
register int window_x;
register int window_y;
unsigned long change_mask;
XWindowChanges *changes;
register Bool config_p = False;
p_ptr->serial = p_num;
switch (menu->menu_style) {
case LEFT:
window_x = menu->p_x_off * ((menu->p_count - 1) - p_num);
window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
break;
case RIGHT:
window_x = menu->p_x_off * p_num;
window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
break;
case CENTER:
window_x = 0;
window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
break;
default:
_XMErrorCode = XME_STYLE_PARAM;
return(_FAILURE);
}
window_x += menu->x_pos;
window_y += menu->y_pos;
if (
(window_x != p_ptr->window_x) ||
(window_y != p_ptr->window_y)
){
p_ptr->window_x = window_x;
p_ptr->window_y = window_y;
config_p = True;
}
if (
(p_ptr->window_w != menu->p_width) ||
(p_ptr->window_h != menu->p_height)
){
p_ptr->window_w = menu->p_width;
p_ptr->window_h = menu->p_height;
config_p = True;
}
if (config_p == True) {
if (p_ptr->window) {
change_mask = (CWX | CWY | CWWidth | CWHeight);
changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
changes->x = p_ptr->window_x;
changes->y = p_ptr->window_y;
changes->width = p_ptr->window_w;
changes->height = p_ptr->window_h;
XConfigureWindow(
display,
p_ptr->window,
change_mask,
changes
);
free(changes);
}
else {
if (_XMWinQueAddPane(display, menu, p_ptr) == _FAILURE) {
return(_FAILURE);
}
}
}
switch (menu->p_style) {
case LEFT:
p_ptr->label_x = menu->p_x_off + menu->p_fnt_pad;
break;
case RIGHT:
p_ptr->label_x = menu->p_width -
(p_ptr->label_width + menu->p_x_off + menu->p_fnt_pad);
break;
case CENTER:
p_ptr->label_x = (menu->p_width - p_ptr->label_width) >> 1;
break;
default:
_XMErrorCode = XME_STYLE_PARAM;
return(_FAILURE);
}
p_ptr->label_uy = menu->p_fnt_pad + menu->p_fnt_info->max_bounds.ascent;
p_ptr->label_ly = (menu->p_height - menu->p_fnt_pad - menu->p_fnt_info->max_bounds.descent);
_XMErrorCode = XME_NO_ERROR;
return(_SUCCESS);
}
int
_XMRecomputeSelection(display, menu, s_ptr, s_num)
register Display *display;
register XMenu *menu;
register XMSelect *s_ptr;
register int s_num;
{
register Bool config_s = False;
XWindowChanges *changes;
unsigned long change_mask;
if (s_ptr->serial != s_num) {
s_ptr->serial = s_num;
s_ptr->window_x = menu->s_x_off;
s_ptr->window_y = menu->flag_height + (menu->s_y_off * s_num);
config_s = True;
}
if (
(s_ptr->window_w != menu->s_width) ||
(s_ptr->window_h != menu->s_height)
){
config_s = True;
s_ptr->window_w = menu->s_width;
s_ptr->window_h = menu->s_height;
}
if (config_s == True) {
if (s_ptr->window) {
changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
change_mask = (CWX | CWY | CWWidth | CWHeight);
changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
changes->x = s_ptr->window_x;
changes->y = s_ptr->window_y;
changes->width = s_ptr->window_w;
changes->height = s_ptr->window_h;
XConfigureWindow(
display,
s_ptr->window,
change_mask,
changes
);
free(changes);
}
else {
if (_XMWinQueAddSelection(display, menu, s_ptr) == _FAILURE) {
return(_FAILURE);
}
}
}
switch (menu->s_style) {
case LEFT:
s_ptr->label_x = menu->s_bdr_width + menu->s_fnt_pad + s_ptr->window_x;
break;
case RIGHT:
s_ptr->label_x = s_ptr->window_x + menu->s_width -
(s_ptr->label_width + menu->s_bdr_width + menu->s_fnt_pad);
break;
case CENTER:
s_ptr->label_x = s_ptr->window_x + ((menu->s_width - s_ptr->label_width) >> 1);
break;
default:
_XMErrorCode = XME_STYLE_PARAM;
return(_FAILURE);
}
s_ptr->label_y = s_ptr->window_y + menu->s_fnt_info->max_bounds.ascent + menu->s_fnt_pad + menu->s_bdr_width;
_XMErrorCode = XME_NO_ERROR;
return(_SUCCESS);
}
_XMTransToOrigin(display, menu, p_ptr, s_ptr, x_pos, y_pos, orig_x, orig_y)
Display *display;
register XMenu *menu;
register XMPane *p_ptr;
register XMSelect *s_ptr;
int x_pos;
int y_pos;
int *orig_x;
int *orig_y;
{
register int l_orig_x;
register int l_orig_y;
if (s_ptr == NULL) {
l_orig_x = x_pos - (menu->p_width >> 1) - menu->p_bdr_width;
l_orig_y = y_pos - (menu->flag_height >> 1) - menu->p_bdr_width;
}
else {
l_orig_x = x_pos - (menu->s_width >> 1);
l_orig_y = y_pos - (menu->s_height >> 1);
l_orig_x -= (s_ptr->window_x + menu->p_bdr_width);
l_orig_y -= (s_ptr->window_y + menu->p_bdr_width);
}
l_orig_x -= (p_ptr->window_x - menu->x_pos);
l_orig_y -= (p_ptr->window_y - menu->y_pos);
*orig_x = l_orig_x;
*orig_y = l_orig_y;
}
_XMRefreshPane(display, menu, pane)
register Display *display;
register XMenu *menu;
register XMPane *pane;
{
register XMSelect *s_list = pane->s_list;
register XMSelect *s_ptr;
XClearWindow(display, pane->window);
if (!pane->activated) {
XFillRectangle(display,
pane->window,
menu->inverse_select_GC,
pane->label_x - menu->p_fnt_pad,
pane->label_uy - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad,
pane->label_width + (menu->p_fnt_pad << 1),
menu->flag_height);
XFillRectangle(display,
pane->window,
menu->inverse_select_GC,
pane->label_x - menu->p_fnt_pad,
pane->label_ly - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad,
pane->label_width + (menu->p_fnt_pad << 1),
menu->flag_height);
}
if (!pane->active) {
XDrawString(display,
pane->window,
menu->inact_GC,
pane->label_x, pane->label_uy,
pane->label, pane->label_length);
XDrawString(display,
pane->window,
menu->inact_GC,
pane->label_x, pane->label_ly,
pane->label, pane->label_length);
}
else {
XDrawString(display,
pane->window,
menu->pane_GC,
pane->label_x, pane->label_uy,
pane->label, pane->label_length);
XDrawString(display,
pane->window,
menu->pane_GC,
pane->label_x, pane->label_ly,
pane->label, pane->label_length);
if (pane->activated) {
for (s_ptr = s_list->next; s_ptr != s_list; s_ptr = s_ptr->next)
_XMRefreshSelection(display, menu, s_ptr);
}
}
}
_XMRefreshSelection(display, menu, select)
register Display *display;
register XMenu *menu;
register XMSelect *select;
{
register int width = select->window_w;
register int height = select->window_h;
register int bdr_width = menu->s_bdr_width;
if (select->type == SEPARATOR) {
XDrawLine(display,
select->parent_p->window,
menu->normal_select_GC,
select->window_x,
select->window_y + height / 2,
select->window_x + width,
select->window_y + height / 2);
}
else if (select->activated) {
if (menu->menu_mode == INVERT) {
XFillRectangle(display,
select->parent_p->window,
menu->normal_select_GC,
select->window_x, select->window_y,
width, height);
XDrawString(display,
select->parent_p->window,
menu->inverse_select_GC,
select->label_x,
select->label_y,
select->label, select->label_length);
}
else {
XDrawRectangle(display,
select->parent_p->window,
menu->normal_select_GC,
select->window_x + (bdr_width >> 1),
select->window_y + (bdr_width >> 1 ),
width - bdr_width,
height - bdr_width);
XDrawString(display,
select->parent_p->window,
menu->normal_select_GC,
select->label_x,
select->label_y,
select->label, select->label_length);
}
}
else {
XClearArea(display,
select->parent_p->window,
select->window_x, select->window_y,
width, height,
False);
if (select->active) {
XDrawString(display,
select->parent_p->window,
menu->normal_select_GC,
select->label_x,
select->label_y,
select->label, select->label_length);
}
else {
XDrawString(display,
select->parent_p->window,
menu->inact_GC,
select->label_x,
select->label_y,
select->label, select->label_length);
}
}
}