1999-08-17 18:12:47 -07:00
|
|
|
/* menus.c -- Eterm popup menu module
|
|
|
|
|
|
|
|
* This file is original work by Michael Jennings <mej@eterm.org> and
|
|
|
|
* Tuomo Venalainen <vendu@cc.hut.fi>. This file, and any other file
|
|
|
|
* bearing this same message or a similar one, is distributed under
|
|
|
|
* the GNU Public License (GPL) as outlined in the COPYING file.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1997, Michael Jennings and Tuomo Venalainen
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static const char cvs_ident[] = "$Id$";
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "feature.h"
|
|
|
|
|
|
|
|
#include <X11/cursorfont.h>
|
|
|
|
|
|
|
|
#include "../libmej/debug.h"
|
|
|
|
#include "../libmej/mem.h"
|
|
|
|
#include "../libmej/strings.h"
|
|
|
|
#include "command.h"
|
|
|
|
#include "events.h"
|
|
|
|
#include "main.h"
|
|
|
|
#include "menus.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "pixmap.h"
|
|
|
|
#include "screen.h"
|
|
|
|
#include "term.h"
|
|
|
|
#include "windows.h"
|
|
|
|
|
|
|
|
event_dispatcher_data_t menu_event_data;
|
|
|
|
menulist_t *menu_list = NULL;
|
|
|
|
static GC topShadowGC, botShadowGC;
|
|
|
|
static Time button_press_time;
|
|
|
|
static menu_t *current_menu;
|
|
|
|
static menuitem_t *current_item;
|
|
|
|
|
|
|
|
inline void
|
|
|
|
grab_pointer(Window win)
|
|
|
|
{
|
|
|
|
|
|
|
|
int success;
|
|
|
|
|
|
|
|
D_EVENTS(("grab_pointer(): Grabbing control of pointer for window 0x%08x.\n", win));
|
|
|
|
success = XGrabPointer(Xdisplay, win, False,
|
|
|
|
EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask
|
|
|
|
| Button1MotionMask | Button2MotionMask | Button3MotionMask,
|
|
|
|
GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
|
|
|
|
if (success != GrabSuccess) {
|
|
|
|
switch (success) {
|
|
|
|
case GrabNotViewable:
|
|
|
|
D_MENU((" -> Unable to grab pointer -- Grab window is not viewable.\n"));
|
|
|
|
break;
|
|
|
|
case AlreadyGrabbed:
|
|
|
|
D_MENU((" -> Unable to grab pointer -- Pointer is already grabbed by another client.\n"));
|
|
|
|
break;
|
|
|
|
case GrabFrozen:
|
|
|
|
D_MENU((" -> Unable to grab pointer -- Pointer is frozen by another grab.\n"));
|
|
|
|
break;
|
|
|
|
case GrabInvalidTime:
|
|
|
|
D_MENU((" -> Unable to grab pointer -- Invalid grab time.\n"));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
ungrab_pointer(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
D_EVENTS(("ungrab_pointer(): Releasing pointer grab.\n"));
|
|
|
|
XUngrabPointer(Xdisplay, CurrentTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
draw_string(Drawable d, GC gc, int x, int y, char *str, size_t len)
|
|
|
|
{
|
|
|
|
|
|
|
|
/*D_MENU(("draw_string(): Writing string \"%s\" (length %lu) onto drawable 0x%08x at %d, %d\n", str, len, d, x, y)); */
|
|
|
|
|
|
|
|
#ifdef MULTI_CHARSET
|
|
|
|
if (current_menu && current_menu->fontset)
|
|
|
|
XmbDrawString(Xdisplay, d, current_menu->fontset, gc, x, y, str, len);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
XDrawString(Xdisplay, d, gc, x, y, str, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline unsigned short
|
|
|
|
center_coords(register unsigned short c1, register unsigned short c2)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (((c2 - c1) >> 1) + c1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_init(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
XGCValues gcvalue;
|
|
|
|
|
|
|
|
if (!menu_list || menu_list->nummenus == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gcvalue.foreground = PixColors[menuTopShadowColor];
|
|
|
|
topShadowGC = XCreateGC(Xdisplay, menu_list->menus[0]->win, GCForeground, &gcvalue);
|
|
|
|
gcvalue.foreground = PixColors[menuBottomShadowColor];
|
|
|
|
botShadowGC = XCreateGC(Xdisplay, menu_list->menus[0]->win, GCForeground, &gcvalue);
|
|
|
|
|
|
|
|
event_register_dispatcher(menu_dispatch_event, menu_event_init_dispatcher);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_event_init_dispatcher(void)
|
|
|
|
{
|
|
|
|
register unsigned char i;
|
|
|
|
|
|
|
|
MEMSET(&menu_event_data, 0, sizeof(event_dispatcher_data_t));
|
|
|
|
|
|
|
|
EVENT_DATA_ADD_HANDLER(menu_event_data, EnterNotify, menu_handle_enter_notify);
|
|
|
|
EVENT_DATA_ADD_HANDLER(menu_event_data, LeaveNotify, menu_handle_leave_notify);
|
|
|
|
EVENT_DATA_ADD_HANDLER(menu_event_data, GraphicsExpose, menu_handle_expose);
|
|
|
|
EVENT_DATA_ADD_HANDLER(menu_event_data, Expose, menu_handle_expose);
|
|
|
|
EVENT_DATA_ADD_HANDLER(menu_event_data, ButtonPress, menu_handle_button_press);
|
|
|
|
EVENT_DATA_ADD_HANDLER(menu_event_data, ButtonRelease, menu_handle_button_release);
|
|
|
|
EVENT_DATA_ADD_HANDLER(menu_event_data, MotionNotify, menu_handle_motion_notify);
|
|
|
|
|
|
|
|
for (i = 0; i < menu_list->nummenus; i++) {
|
|
|
|
event_data_add_mywin(&menu_event_data, menu_list->menus[i]->win);
|
|
|
|
}
|
|
|
|
|
|
|
|
event_data_add_parent(&menu_event_data, TermWin.vt);
|
|
|
|
event_data_add_parent(&menu_event_data, TermWin.parent);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_handle_enter_notify(event_t * ev)
|
|
|
|
{
|
|
|
|
|
|
|
|
register menu_t *menu;
|
|
|
|
|
|
|
|
D_EVENTS(("menu_handle_enter_notify(ev [0x%08x] on window 0x%08x)\n", ev, ev->xany.window));
|
|
|
|
|
|
|
|
REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &menu_event_data), 0);
|
|
|
|
|
|
|
|
/* Take control of the pointer so we get all events for it, even those outside the menu window */
|
|
|
|
menu = find_menu_by_window(menu_list, ev->xany.window);
|
|
|
|
if (menu && menu != current_menu) {
|
|
|
|
ungrab_pointer();
|
|
|
|
if (menu->state & MENU_STATE_IS_MAPPED) {
|
|
|
|
grab_pointer(menu->win);
|
|
|
|
menu->state |= MENU_STATE_IS_FOCUSED;
|
|
|
|
current_menu = menu;
|
|
|
|
menu_reset_submenus(menu);
|
|
|
|
menuitem_change_current(find_item_by_coords(current_menu, ev->xbutton.x, ev->xbutton.y));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_handle_leave_notify(event_t * ev)
|
|
|
|
{
|
|
|
|
|
|
|
|
D_EVENTS(("menu_handle_leave_notify(ev [0x%08x] on window 0x%08x)\n", ev, ev->xany.window));
|
|
|
|
|
|
|
|
REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &menu_event_data), 0);
|
|
|
|
|
|
|
|
if (current_menu) {
|
|
|
|
current_menu->state &= ~(MENU_STATE_IS_FOCUSED);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_handle_focus_in(event_t * ev)
|
|
|
|
{
|
|
|
|
|
|
|
|
D_EVENTS(("menu_handle_focus_in(ev [0x%08x] on window 0x%08x)\n", ev, ev->xany.window));
|
|
|
|
|
|
|
|
REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &menu_event_data), 0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_handle_focus_out(event_t * ev)
|
|
|
|
{
|
|
|
|
|
|
|
|
D_EVENTS(("menu_handle_focus_out(ev [0x%08x] on window 0x%08x)\n", ev, ev->xany.window));
|
|
|
|
|
|
|
|
REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &menu_event_data), 0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_handle_expose(event_t * ev)
|
|
|
|
{
|
|
|
|
|
|
|
|
XEvent unused_xevent;
|
|
|
|
|
|
|
|
D_EVENTS(("menu_handle_expose(ev [0x%08x] on window 0x%08x)\n", ev, ev->xany.window));
|
|
|
|
|
|
|
|
REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &menu_event_data), 0);
|
|
|
|
|
|
|
|
while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, Expose, &unused_xevent));
|
|
|
|
while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, GraphicsExpose, &unused_xevent));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_handle_button_press(event_t * ev)
|
|
|
|
{
|
|
|
|
|
|
|
|
D_EVENTS(("menu_handle_button_press(ev [0x%08x] on window 0x%08x)\n", ev, ev->xany.window));
|
|
|
|
|
|
|
|
REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &menu_event_data), 0);
|
|
|
|
|
|
|
|
D_EVENTS(("ButtonPress at %d, %d\n", ev->xbutton.x, ev->xbutton.y));
|
|
|
|
|
|
|
|
button_press_time = ev->xbutton.time;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_handle_button_release(event_t * ev)
|
|
|
|
{
|
|
|
|
|
|
|
|
D_EVENTS(("menu_handle_button_release(ev [0x%08x] on window 0x%08x)\n", ev, ev->xany.window));
|
|
|
|
|
|
|
|
REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &menu_event_data), 0);
|
|
|
|
|
|
|
|
D_EVENTS(("ButtonRelease at %d, %d\n", ev->xbutton.x, ev->xbutton.y));
|
|
|
|
|
|
|
|
if (current_menu && (current_menu->state & MENU_STATE_IS_DRAGGING)) {
|
|
|
|
|
|
|
|
/* Dragging-and-release mode */
|
|
|
|
D_MENU(("Drag-and-release mode, detected release.\n"));
|
|
|
|
ungrab_pointer();
|
|
|
|
|
|
|
|
if (button_press_time && (ev->xbutton.time - button_press_time > MENU_CLICK_TIME)) {
|
|
|
|
/* Take action here based on the current menu item */
|
|
|
|
if (current_item) {
|
|
|
|
if (current_item->type == MENUITEM_SUBMENU) {
|
|
|
|
menu_display_submenu(current_menu, current_item);
|
|
|
|
current_item = NULL;
|
|
|
|
} else {
|
|
|
|
menu_action(current_item);
|
|
|
|
menuitem_deselect(current_menu, current_item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Reset the state of the menu system. */
|
|
|
|
menu_reset_all(menu_list);
|
|
|
|
current_menu = NULL;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Single-click mode */
|
|
|
|
D_MENU(("Single click mode, detected click.\n"));
|
|
|
|
if ((ev->xbutton.x >= 0) && (ev->xbutton.y >= 0) && (ev->xbutton.x < current_menu->w) && (ev->xbutton.y < current_menu->h)) {
|
|
|
|
/* Click inside the menu window. Activate the current item. */
|
|
|
|
if (current_item) {
|
|
|
|
if (current_item->type == MENUITEM_SUBMENU) {
|
|
|
|
menu_display_submenu(current_menu, current_item);
|
|
|
|
current_item = NULL;
|
|
|
|
} else {
|
|
|
|
menu_action(current_item);
|
|
|
|
menuitem_deselect(current_menu, current_item);
|
|
|
|
menu_reset_all(menu_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ungrab_pointer();
|
|
|
|
/* Reset the state of the menu system. */
|
|
|
|
menu_reset_all(menu_list);
|
|
|
|
current_menu = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
button_press_time = 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_handle_motion_notify(event_t * ev)
|
|
|
|
{
|
|
|
|
|
|
|
|
register menuitem_t *item = NULL;
|
|
|
|
|
|
|
|
D_EVENTS(("menu_handle_motion_notify(ev [0x%08x] on window 0x%08x)\n", ev, ev->xany.window));
|
|
|
|
|
|
|
|
REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &menu_event_data), 0);
|
|
|
|
|
|
|
|
while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, MotionNotify, ev));
|
|
|
|
if (!current_menu) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
if ((current_menu->win != ev->xany.window)
|
|
|
|
&& !(current_item && current_item->type == MENUITEM_SUBMENU
|
|
|
|
&& current_item->action.submenu && current_item->action.submenu->win == ev->xany.window)) {
|
|
|
|
register menu_t *menu;
|
|
|
|
|
|
|
|
menu = find_menu_by_window(menu_list, ev->xany.window);
|
|
|
|
if (menu) {
|
|
|
|
menu_reset_tree(current_menu);
|
|
|
|
current_menu = menu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (button_press_time) {
|
|
|
|
current_menu->state |= MENU_STATE_IS_DRAGGING;
|
|
|
|
}
|
|
|
|
if ((ev->xbutton.x >= 0) && (ev->xbutton.y >= 0) && (ev->xbutton.x < current_menu->w) && (ev->xbutton.y < current_menu->h)) {
|
|
|
|
/* Motion within the current menu */
|
|
|
|
item = find_item_by_coords(current_menu, ev->xbutton.x, ev->xbutton.y);
|
|
|
|
menuitem_change_current(item);
|
|
|
|
} else {
|
|
|
|
/* Motion outside the current menu */
|
|
|
|
int dest_x, dest_y;
|
|
|
|
Window child;
|
|
|
|
menu_t *menu;
|
|
|
|
|
|
|
|
XTranslateCoordinates(Xdisplay, ev->xany.window, Xroot, ev->xbutton.x, ev->xbutton.y, &dest_x, &dest_y, &child);
|
|
|
|
menu = find_menu_by_window(menu_list, child);
|
|
|
|
if (menu) {
|
|
|
|
D_MENU(("Mouse is actually over window 0x%08x belonging to menu \"%s\"\n", child, menu->title));
|
|
|
|
XTranslateCoordinates(Xdisplay, ev->xany.window, child, ev->xbutton.x, ev->xbutton.y, &dest_x, &dest_y, &child);
|
|
|
|
item = find_item_by_coords(menu, dest_x, dest_y);
|
|
|
|
if (item && item != current_item) {
|
|
|
|
ungrab_pointer();
|
|
|
|
grab_pointer(menu->win);
|
|
|
|
current_menu->state &= ~(MENU_STATE_IS_FOCUSED);
|
|
|
|
menu->state |= MENU_STATE_IS_FOCUSED;
|
|
|
|
if (!menu_is_child(current_menu, menu)) {
|
|
|
|
menu_reset_tree(current_menu);
|
|
|
|
}
|
|
|
|
current_menu = menu;
|
|
|
|
menu_reset_submenus(menu);
|
|
|
|
menuitem_change_current(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_dispatch_event(event_t * ev)
|
|
|
|
{
|
|
|
|
if (menu_event_data.handlers[ev->type] != NULL) {
|
|
|
|
return ((menu_event_data.handlers[ev->type]) (ev));
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
menulist_t *
|
|
|
|
menulist_add_menu(menulist_t * list, menu_t * menu)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT_RVAL(menu != NULL, list);
|
|
|
|
|
|
|
|
if (list) {
|
|
|
|
list->nummenus++;
|
|
|
|
list->menus = (menu_t **) REALLOC(list->menus, sizeof(menu_t *) * list->nummenus);
|
|
|
|
} else {
|
|
|
|
list = (menulist_t *) MALLOC(sizeof(menulist_t));
|
|
|
|
list->nummenus = 1;
|
|
|
|
list->menus = (menu_t **) MALLOC(sizeof(menu_t *));
|
|
|
|
}
|
|
|
|
list->menus[list->nummenus - 1] = menu;
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
menu_t *
|
|
|
|
menu_create(char *title)
|
|
|
|
{
|
|
|
|
|
|
|
|
menu_t *menu;
|
|
|
|
static Cursor cursor;
|
|
|
|
static long mask;
|
|
|
|
static XGCValues gcvalue;
|
|
|
|
static XSetWindowAttributes xattr;
|
|
|
|
|
|
|
|
ASSERT_RVAL(title != NULL, NULL);
|
|
|
|
|
|
|
|
if (!mask) {
|
|
|
|
xattr.border_pixel = BlackPixel(Xdisplay, Xscreen);
|
|
|
|
xattr.save_under = TRUE;
|
|
|
|
xattr.backing_store = WhenMapped;
|
|
|
|
xattr.override_redirect = TRUE;
|
|
|
|
xattr.colormap = cmap;
|
|
|
|
|
|
|
|
cursor = XCreateFontCursor(Xdisplay, XC_left_ptr);
|
|
|
|
mask = EnterNotify | LeaveNotify | PointerMotionMask | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask
|
|
|
|
| Button1MotionMask | Button2MotionMask | Button3MotionMask;
|
|
|
|
gcvalue.foreground = PixColors[menuTextColor];
|
|
|
|
}
|
|
|
|
menu = (menu_t *) MALLOC(sizeof(menu_t));
|
|
|
|
MEMSET(menu, 0, sizeof(menu_t));
|
|
|
|
menu->title = StrDup(title);
|
|
|
|
|
|
|
|
menu->win = XCreateWindow(Xdisplay, Xroot, 0, 0, 1, 1, 0, Xdepth, InputOutput, CopyFromParent,
|
|
|
|
CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWBorderPixel | CWColormap, &xattr);
|
|
|
|
XDefineCursor(Xdisplay, menu->win, cursor);
|
|
|
|
XSelectInput(Xdisplay, menu->win, mask);
|
|
|
|
XStoreName(Xdisplay, menu->win, menu->title);
|
|
|
|
|
|
|
|
menu->swin = XCreateWindow(Xdisplay, menu->win, 0, 0, 1, 1, 0, Xdepth, InputOutput, CopyFromParent,
|
|
|
|
CWOverrideRedirect | CWSaveUnder | CWBackingStore | CWBorderPixel | CWColormap, &xattr);
|
|
|
|
|
|
|
|
menu->gc = XCreateGC(Xdisplay, menu->win, GCForeground, &gcvalue);
|
|
|
|
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_set_font(menu_t * menu, const char *fontname)
|
|
|
|
{
|
|
|
|
|
|
|
|
XFontStruct *font;
|
|
|
|
XGCValues gcvalue;
|
|
|
|
|
|
|
|
ASSERT_RVAL(menu != NULL, 0);
|
|
|
|
ASSERT_RVAL(fontname != NULL, 0);
|
|
|
|
|
|
|
|
font = load_font(fontname);
|
|
|
|
#ifdef MULTI_CHARSET
|
|
|
|
menu->fontset = create_fontset(fontname, rs_mfont[0]);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
menu->font = font;
|
|
|
|
menu->fwidth = font->max_bounds.width;
|
|
|
|
menu->fheight = font->ascent + font->descent + rs_line_space;
|
|
|
|
|
|
|
|
gcvalue.font = font->fid;
|
|
|
|
XChangeGC(Xdisplay, menu->gc, GCFont, &gcvalue);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menu_add_item(menu_t * menu, menuitem_t * item)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT_RVAL(menu != NULL, 0);
|
|
|
|
ASSERT_RVAL(item != NULL, 0);
|
|
|
|
|
|
|
|
if (menu->numitems) {
|
|
|
|
menu->numitems++;
|
|
|
|
menu->items = (menuitem_t **) REALLOC(menu->items, sizeof(menuitem_t *) * menu->numitems);
|
|
|
|
} else {
|
|
|
|
menu->numitems = 1;
|
|
|
|
menu->items = (menuitem_t **) MALLOC(sizeof(menuitem_t *));
|
|
|
|
}
|
1999-09-16 15:40:44 -07:00
|
|
|
|
1999-08-17 18:12:47 -07:00
|
|
|
menu->items[menu->numitems - 1] = item;
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return 1 if submenu is a child of menu, 0 if not. */
|
|
|
|
unsigned char
|
|
|
|
menu_is_child(menu_t * menu, menu_t * submenu)
|
|
|
|
{
|
|
|
|
|
|
|
|
register unsigned char i;
|
|
|
|
register menuitem_t *item;
|
|
|
|
|
|
|
|
ASSERT_RVAL(menu != NULL, 0);
|
|
|
|
ASSERT_RVAL(submenu != NULL, 0);
|
|
|
|
|
|
|
|
for (i = 0; i < menu->numitems; i++) {
|
|
|
|
item = menu->items[i];
|
|
|
|
if (item->type == MENUITEM_SUBMENU && item->action.submenu != NULL) {
|
|
|
|
if (item->action.submenu == submenu) {
|
|
|
|
return 1;
|
|
|
|
} else if (menu_is_child(item->action.submenu, submenu)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
menu_t *
|
|
|
|
find_menu_by_title(menulist_t * list, char *title)
|
|
|
|
{
|
|
|
|
|
|
|
|
register unsigned char i;
|
|
|
|
|
1999-09-13 12:18:20 -07:00
|
|
|
REQUIRE_RVAL(list != NULL, NULL);
|
1999-08-17 18:12:47 -07:00
|
|
|
|
|
|
|
for (i = 0; i < list->nummenus; i++) {
|
|
|
|
if (!strcasecmp(list->menus[i]->title, title)) {
|
|
|
|
return (list->menus[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
menu_t *
|
|
|
|
find_menu_by_window(menulist_t * list, Window win)
|
|
|
|
{
|
|
|
|
|
|
|
|
register unsigned char i;
|
|
|
|
|
1999-09-13 12:18:20 -07:00
|
|
|
REQUIRE_RVAL(list != NULL, NULL);
|
1999-08-17 18:12:47 -07:00
|
|
|
|
|
|
|
for (i = 0; i < list->nummenus; i++) {
|
|
|
|
if (list->menus[i]->win == win) {
|
|
|
|
return (list->menus[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
menuitem_t *
|
|
|
|
find_item_by_coords(menu_t * menu, int x, int y)
|
|
|
|
{
|
|
|
|
|
|
|
|
register unsigned char i;
|
|
|
|
register menuitem_t *item;
|
|
|
|
|
|
|
|
ASSERT_RVAL(menu != NULL, NULL);
|
|
|
|
|
|
|
|
for (i = 0; i < menu->numitems; i++) {
|
|
|
|
item = menu->items[i];
|
|
|
|
if ((x > item->x) && (y > item->y) && (x < item->x + item->w) && (y < item->y + item->h) && (item->type != MENUITEM_SEP)) {
|
|
|
|
menu->curitem = i;
|
|
|
|
return (item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned short
|
|
|
|
find_item_in_menu(menu_t * menu, menuitem_t * item)
|
|
|
|
{
|
|
|
|
|
|
|
|
register unsigned char i;
|
|
|
|
|
|
|
|
ASSERT_RVAL(menu != NULL, (unsigned short) -1);
|
|
|
|
ASSERT_RVAL(item != NULL, (unsigned short) -1);
|
|
|
|
|
|
|
|
for (i = 0; i < menu->numitems; i++) {
|
|
|
|
if (item == menu->items[i]) {
|
|
|
|
return (i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ((unsigned short) -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menuitem_change_current(menuitem_t * item)
|
|
|
|
{
|
|
|
|
|
|
|
|
D_MENU(("menuitem_change_current(): Changing current_item from \"%s\" to \"%s\"\n", (current_item ? current_item->text : "(NULL)"),
|
|
|
|
(item ? item->text : "(NULL)")));
|
|
|
|
|
|
|
|
if (current_item != item) {
|
|
|
|
if (current_item) {
|
|
|
|
/* Reset the current item */
|
|
|
|
menuitem_deselect(current_menu, current_item);
|
|
|
|
/* If we're changing from one submenu to another and neither is a child of the other, or if we're changing from a submenu to
|
|
|
|
no current item at all, reset the tree for the current submenu */
|
|
|
|
if (current_item->type == MENUITEM_SUBMENU && current_item->action.submenu != NULL) {
|
|
|
|
if ((item && item->type == MENUITEM_SUBMENU && item->action.submenu != NULL
|
|
|
|
&& !menu_is_child(current_item->action.submenu, item->action.submenu)
|
|
|
|
&& !menu_is_child(item->action.submenu, current_item->action.submenu))
|
|
|
|
|| (!item)) {
|
|
|
|
menu_reset_tree(current_item->action.submenu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
current_item = item;
|
|
|
|
if (current_item) {
|
|
|
|
menuitem_select(current_menu, current_item);
|
|
|
|
if (current_item->type == MENUITEM_SUBMENU) {
|
|
|
|
/* Display the submenu */
|
|
|
|
menu_display_submenu(current_menu, current_item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
menuitem_t *
|
|
|
|
menuitem_create(char *text)
|
|
|
|
{
|
|
|
|
|
|
|
|
menuitem_t *menuitem;
|
|
|
|
|
|
|
|
menuitem = (menuitem_t *) MALLOC(sizeof(menu_t));
|
|
|
|
MEMSET(menuitem, 0, sizeof(menu_t));
|
1999-09-16 15:40:44 -07:00
|
|
|
|
1999-08-17 18:12:47 -07:00
|
|
|
if (text) {
|
|
|
|
menuitem->text = StrDup(text);
|
|
|
|
menuitem->len = strlen(text);
|
|
|
|
}
|
|
|
|
return menuitem;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menuitem_set_icon(menuitem_t * item, image_t * icon)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT_RVAL(item != NULL, 0);
|
|
|
|
ASSERT_RVAL(icon != NULL, 0);
|
|
|
|
|
|
|
|
item->icon = icon;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menuitem_set_action(menuitem_t * item, unsigned char type, char *action)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT_RVAL(item != NULL, 0);
|
|
|
|
|
|
|
|
item->type = type;
|
|
|
|
switch (type) {
|
|
|
|
case MENUITEM_SUBMENU:
|
|
|
|
item->action.submenu = find_menu_by_title(menu_list, action);
|
|
|
|
break;
|
|
|
|
case MENUITEM_STRING:
|
|
|
|
case MENUITEM_ECHO:
|
1999-09-16 15:40:44 -07:00
|
|
|
item->action.string = (char *) MALLOC(strlen(action) + 2);
|
|
|
|
strcpy(item->action.string, action);
|
1999-08-17 18:12:47 -07:00
|
|
|
parse_escaped_string(item->action.string);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char
|
|
|
|
menuitem_set_rtext(menuitem_t * item, char *rtext)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT_RVAL(item != NULL, 0);
|
|
|
|
ASSERT_RVAL(rtext != NULL, 0);
|
|
|
|
|
|
|
|
item->rtext = StrDup(rtext);
|
|
|
|
item->rlen = strlen(rtext);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_reset(menu_t * menu)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT(menu != NULL);
|
|
|
|
|
|
|
|
D_MENU(("menu_reset() called for menu \"%s\" (window 0x%08x)\n", menu->title, menu->win));
|
|
|
|
menu->state &= ~(MENU_STATE_IS_CURRENT | MENU_STATE_IS_DRAGGING);
|
|
|
|
XUnmapWindow(Xdisplay, menu->swin);
|
|
|
|
if (menu->state & MENU_STATE_IS_MAPPED) {
|
|
|
|
XUnmapWindow(Xdisplay, menu->win);
|
|
|
|
menu->state &= ~(MENU_STATE_IS_MAPPED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_reset_all(menulist_t * list)
|
|
|
|
{
|
|
|
|
|
|
|
|
register unsigned short i;
|
|
|
|
register menu_t *menu;
|
|
|
|
|
|
|
|
ASSERT(list != NULL);
|
|
|
|
|
|
|
|
if (list->nummenus == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
D_MENU(("menu_reset_all() called\n"));
|
|
|
|
if (current_item != NULL) {
|
|
|
|
menuitem_deselect(current_menu, current_item);
|
|
|
|
current_item = NULL;
|
|
|
|
}
|
|
|
|
for (i = 0; i < list->nummenus; i++) {
|
|
|
|
menu = list->menus[i];
|
|
|
|
menu->state &= ~(MENU_STATE_IS_CURRENT | MENU_STATE_IS_DRAGGING);
|
|
|
|
XUnmapWindow(Xdisplay, menu->swin);
|
|
|
|
if (menu->state & MENU_STATE_IS_MAPPED) {
|
|
|
|
XUnmapWindow(Xdisplay, menu->win);
|
|
|
|
menu->state &= ~(MENU_STATE_IS_MAPPED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
current_menu = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_reset_tree(menu_t * menu)
|
|
|
|
{
|
|
|
|
|
|
|
|
register unsigned short i;
|
|
|
|
register menuitem_t *item;
|
|
|
|
|
|
|
|
ASSERT(menu != NULL);
|
|
|
|
|
|
|
|
D_MENU(("menu_reset_tree() called for menu \"%s\" (window 0x%08x)\n", menu->title, menu->win));
|
|
|
|
for (i = 0; i < menu->numitems; i++) {
|
|
|
|
item = menu->items[i];
|
|
|
|
if (item->type == MENUITEM_SUBMENU && item->action.submenu != NULL) {
|
|
|
|
menu_reset_tree(item->action.submenu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
menu->state &= ~(MENU_STATE_IS_CURRENT | MENU_STATE_IS_DRAGGING);
|
|
|
|
XUnmapWindow(Xdisplay, menu->swin);
|
|
|
|
if (menu->state & MENU_STATE_IS_MAPPED) {
|
|
|
|
XUnmapWindow(Xdisplay, menu->win);
|
|
|
|
menu->state &= ~(MENU_STATE_IS_MAPPED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_reset_submenus(menu_t * menu)
|
|
|
|
{
|
|
|
|
|
|
|
|
register unsigned short i;
|
|
|
|
register menuitem_t *item;
|
|
|
|
|
|
|
|
ASSERT(menu != NULL);
|
|
|
|
|
|
|
|
D_MENU(("menu_reset_submenus() called for menu \"%s\" (window 0x%08x)\n", menu->title, menu->win));
|
|
|
|
for (i = 0; i < menu->numitems; i++) {
|
|
|
|
item = menu->items[i];
|
|
|
|
if (item->type == MENUITEM_SUBMENU && item->action.submenu != NULL) {
|
|
|
|
menu_reset_tree(item->action.submenu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menuitem_select(menu_t * menu, menuitem_t * item)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT(menu != NULL);
|
|
|
|
ASSERT(item != NULL);
|
|
|
|
|
|
|
|
D_MENU(("menuitem_select(): Selecting new current item \"%s\" within menu \"%s\" (window 0x%08x, selection window 0x%08x)\n",
|
|
|
|
item->text, menu->title, menu->win, menu->swin));
|
|
|
|
item->state |= MENU_STATE_IS_CURRENT;
|
|
|
|
XMoveWindow(Xdisplay, menu->swin, item->x, item->y);
|
|
|
|
XMapWindow(Xdisplay, menu->swin);
|
|
|
|
if (item->type == MENUITEM_SUBMENU) {
|
Mon Sep 20 18:32:01 PDT 1999 Michael Jennings <mej@eterm.org>
Lots of changes here. First off, this should fix the background draw
bug with transparency that several people pointed out. While I was
at it, I also cleaned up a lot of other related stuff. Three-state
images should be a lot more robust now.
Then again, some stuff may be broken entirely from this, so let me
know. :-)
For one thing, the various image modes should work as expected now.
You can allow and disallow modes for the various widgets. The
fallback mode is "solid" now, rather than "image," so you can cause
a certain widget to refuse to use an image if you want to. If you
specify an image without specifying a "mode" line that allows the
"image" mode, your image will not appear. <-- READ THIS TWICE! I
had to go back and fix all the theme files because of this, so you
will need to remove your current theme directory and allow Eterm's
"make install" to put the new ones in place; otherwise, everything
will go back to being solid colors. =]
Anytime something changes this drastically, there are bound to be
problems. Let me know if you find any of them. :)
SVN revision: 348
1999-09-20 18:16:46 -07:00
|
|
|
if (image_mode_is(image_submenu, MODE_IMAGE) && image_mode_is(image_submenu, ALLOW_IMAGE)) {
|
|
|
|
paste_simage(images[image_submenu].selected, menu->swin, 0, 0, item->w - MENU_VGAP, item->h);
|
|
|
|
}
|
1999-08-17 18:12:47 -07:00
|
|
|
} else {
|
|
|
|
render_simage(images[image_menu].selected, menu->swin, item->w - MENU_VGAP, item->h, image_menu, 0);
|
|
|
|
}
|
|
|
|
draw_string(menu->swin, menu->gc, MENU_HGAP, item->h - MENU_VGAP, item->text, item->len);
|
1999-08-20 13:25:04 -07:00
|
|
|
if (item->rtext) {
|
|
|
|
draw_string(menu->swin, menu->gc, item->w - XTextWidth(menu->font, item->rtext, item->rlen) - 2 * MENU_HGAP, item->h - MENU_VGAP, item->rtext, item->rlen);
|
|
|
|
}
|
1999-08-17 18:12:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menuitem_deselect(menu_t * menu, menuitem_t * item)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT(menu != NULL);
|
|
|
|
ASSERT(item != NULL);
|
|
|
|
|
|
|
|
D_MENU(("menuitem_deselect(): Deselecting item \"%s\"\n", item->text));
|
|
|
|
item->state &= ~(MENU_STATE_IS_CURRENT);
|
|
|
|
XUnmapWindow(Xdisplay, menu->swin);
|
|
|
|
if (find_item_in_menu(menu, item) != (unsigned short) -1) {
|
|
|
|
if (item->type == MENUITEM_SUBMENU) {
|
Mon Sep 20 18:32:01 PDT 1999 Michael Jennings <mej@eterm.org>
Lots of changes here. First off, this should fix the background draw
bug with transparency that several people pointed out. While I was
at it, I also cleaned up a lot of other related stuff. Three-state
images should be a lot more robust now.
Then again, some stuff may be broken entirely from this, so let me
know. :-)
For one thing, the various image modes should work as expected now.
You can allow and disallow modes for the various widgets. The
fallback mode is "solid" now, rather than "image," so you can cause
a certain widget to refuse to use an image if you want to. If you
specify an image without specifying a "mode" line that allows the
"image" mode, your image will not appear. <-- READ THIS TWICE! I
had to go back and fix all the theme files because of this, so you
will need to remove your current theme directory and allow Eterm's
"make install" to put the new ones in place; otherwise, everything
will go back to being solid colors. =]
Anytime something changes this drastically, there are bound to be
problems. Let me know if you find any of them. :)
SVN revision: 348
1999-09-20 18:16:46 -07:00
|
|
|
if (image_mode_is(image_submenu, MODE_IMAGE) && image_mode_is(image_submenu, ALLOW_IMAGE)) {
|
|
|
|
paste_simage(images[image_submenu].norm, menu->win, item->x, item->y, item->w - MENU_VGAP, item->h);
|
|
|
|
}
|
1999-08-17 18:12:47 -07:00
|
|
|
}
|
|
|
|
draw_string(menu->win, menu->gc, 2 * MENU_HGAP, item->y + item->h - MENU_VGAP, item->text, item->len);
|
1999-08-20 13:25:04 -07:00
|
|
|
if (item->rtext) {
|
|
|
|
draw_string(menu->win, menu->gc, item->x + item->w - XTextWidth(menu->font, item->rtext, item->rlen) - 2 * MENU_HGAP, item->y + item->h - MENU_VGAP,
|
|
|
|
item->rtext, item->rlen);
|
|
|
|
}
|
1999-08-17 18:12:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_display_submenu(menu_t * menu, menuitem_t * item)
|
|
|
|
{
|
|
|
|
|
|
|
|
menu_t *submenu;
|
|
|
|
|
|
|
|
ASSERT(menu != NULL);
|
|
|
|
ASSERT(item != NULL);
|
|
|
|
REQUIRE(item->action.submenu != NULL);
|
|
|
|
|
|
|
|
submenu = item->action.submenu;
|
|
|
|
D_MENU(("menu_display_submenu(): Displaying submenu \"%s\" (window 0x%08x) of menu \"%s\" (window 0x%08x)\n",
|
|
|
|
submenu->title, submenu->win, menu->title, menu->win));
|
|
|
|
menu_invoke(item->x + item->w, item->y, menu->win, submenu, CurrentTime);
|
|
|
|
|
|
|
|
/* Invoking the submenu makes it current. Undo that behavior. */
|
|
|
|
ungrab_pointer();
|
|
|
|
grab_pointer(menu->win);
|
|
|
|
current_menu->state &= ~(MENU_STATE_IS_CURRENT);
|
|
|
|
current_menu = menu;
|
|
|
|
menu->state |= MENU_STATE_IS_CURRENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_draw(menu_t * menu)
|
|
|
|
{
|
|
|
|
|
|
|
|
register unsigned short i, len;
|
|
|
|
unsigned long width, height;
|
|
|
|
#if 0
|
|
|
|
char *safeaction;
|
|
|
|
#endif
|
|
|
|
unsigned short str_x, str_y;
|
|
|
|
XGCValues gcvalue;
|
|
|
|
int ascent, descent, direction;
|
|
|
|
XCharStruct chars;
|
|
|
|
Screen *scr;
|
|
|
|
|
|
|
|
ASSERT(menu != NULL);
|
|
|
|
|
|
|
|
scr = ScreenOfDisplay(Xdisplay, Xscreen);
|
|
|
|
if (!menu->font) {
|
|
|
|
menu_set_font(menu, rs_font[0]);
|
|
|
|
}
|
|
|
|
gcvalue.foreground = PixColors[menuTextColor];
|
|
|
|
XChangeGC(Xdisplay, menu->gc, GCForeground, &gcvalue);
|
|
|
|
|
|
|
|
if (!menu->w) {
|
1999-08-20 13:25:04 -07:00
|
|
|
unsigned short longest;
|
|
|
|
|
1999-08-17 18:12:47 -07:00
|
|
|
len = strlen(menu->title);
|
1999-08-19 16:48:05 -07:00
|
|
|
longest = XTextWidth(menu->font, menu->title, len);
|
1999-08-17 18:12:47 -07:00
|
|
|
height = menu->fheight + 3 * MENU_VGAP;
|
|
|
|
for (i = 0; i < menu->numitems; i++) {
|
|
|
|
unsigned short j = menu->items[i]->len;
|
|
|
|
menuitem_t *item = menu->items[i];
|
|
|
|
|
1999-08-19 16:48:05 -07:00
|
|
|
width = XTextWidth(menu->font, item->text, j);
|
1999-08-17 18:12:47 -07:00
|
|
|
if (item->rtext) {
|
1999-08-20 13:25:04 -07:00
|
|
|
width += XTextWidth(menu->font, item->rtext, item->rlen) + (2 * MENU_HGAP);
|
1999-08-17 18:12:47 -07:00
|
|
|
}
|
1999-08-20 13:25:04 -07:00
|
|
|
longest = (longest > width) ? longest : width;
|
1999-08-17 18:12:47 -07:00
|
|
|
height += ((item->type == MENUITEM_SEP) ? (MENU_VGAP) : (menu->fheight)) + MENU_VGAP;
|
|
|
|
}
|
1999-08-19 16:48:05 -07:00
|
|
|
width = longest + (4 * MENU_HGAP);
|
1999-08-17 18:12:47 -07:00
|
|
|
if (images[image_submenu].selected->iml->pad) {
|
|
|
|
width += images[image_submenu].selected->iml->pad->left + images[image_submenu].selected->iml->pad->right;
|
|
|
|
}
|
|
|
|
menu->w = width;
|
|
|
|
menu->h = height;
|
|
|
|
|
|
|
|
/* Size and render menu window */
|
|
|
|
D_MENU((" -> width %hu, height %hu\n", menu->w, menu->h));
|
|
|
|
XResizeWindow(Xdisplay, menu->win, menu->w, menu->h);
|
|
|
|
render_simage(images[image_menu].norm, menu->win, menu->w, menu->h, image_menu, 0);
|
|
|
|
|
|
|
|
/* Size and render selected item window */
|
|
|
|
XResizeWindow(Xdisplay, menu->swin, menu->w - 2 * MENU_HGAP, menu->fheight + MENU_VGAP);
|
|
|
|
render_simage(images[image_menu].selected, menu->swin, menu->w - 2 * MENU_HGAP, menu->fheight + MENU_VGAP, image_menu, 0);
|
|
|
|
}
|
|
|
|
if (menu->w + menu->x > scr->width) {
|
|
|
|
menu->x = scr->width - menu->w;
|
|
|
|
}
|
|
|
|
if (menu->h + menu->y > scr->height) {
|
|
|
|
menu->y = scr->height - menu->h;
|
|
|
|
}
|
|
|
|
XMoveWindow(Xdisplay, menu->win, menu->x, menu->y);
|
|
|
|
XRaiseWindow(Xdisplay, menu->win);
|
|
|
|
|
|
|
|
str_x = 2 * MENU_HGAP;
|
|
|
|
if (images[image_menu].selected->iml->pad) {
|
|
|
|
str_x += images[image_menu].selected->iml->pad->left;
|
|
|
|
}
|
|
|
|
str_y = menu->fheight + MENU_VGAP;
|
|
|
|
len = strlen(menu->title);
|
|
|
|
XTextExtents(menu->font, menu->title, len, &direction, &ascent, &descent, &chars);
|
|
|
|
draw_string(menu->win, menu->gc, center_coords(2 * MENU_HGAP, menu->w - 2 * MENU_HGAP) - (chars.width >> 1),
|
|
|
|
str_y - chars.descent - MENU_VGAP / 2, menu->title, len);
|
|
|
|
Draw_Shadow(menu->win, topShadowGC, botShadowGC, str_x, str_y - chars.descent - MENU_VGAP / 2 + 1, menu->w - (4 * MENU_HGAP), MENU_VGAP);
|
|
|
|
str_y += MENU_VGAP;
|
|
|
|
|
|
|
|
for (i = 0; i < menu->numitems; i++) {
|
|
|
|
menuitem_t *item = menu->items[i];
|
|
|
|
|
|
|
|
if (item->type == MENUITEM_SEP) {
|
|
|
|
|
|
|
|
str_y += 2 * MENU_VGAP;
|
|
|
|
if (!item->x) {
|
|
|
|
item->x = MENU_HGAP;
|
|
|
|
item->y = str_y - 2 * MENU_VGAP;
|
|
|
|
item->w = menu->w - MENU_HGAP;
|
|
|
|
item->h = 2 * MENU_VGAP;
|
|
|
|
D_MENU((" -> Hot Area at %hu, %hu to %hu, %hu (width %hu, height %hu)\n", item->x, item->y, item->x + item->w, item->y + item->h,
|
|
|
|
item->w, item->h));
|
|
|
|
}
|
|
|
|
Draw_Shadow(menu->win, botShadowGC, topShadowGC, str_x, str_y - MENU_VGAP - MENU_VGAP / 2, menu->w - 4 * MENU_HGAP, MENU_VGAP);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
str_y += menu->fheight + MENU_VGAP;
|
|
|
|
if (!item->x) {
|
|
|
|
item->x = MENU_HGAP;
|
|
|
|
item->y = str_y - menu->fheight - MENU_VGAP / 2;
|
|
|
|
item->w = menu->w - MENU_HGAP;
|
|
|
|
item->h = menu->fheight + MENU_VGAP;
|
|
|
|
D_MENU((" -> Hot Area at %hu, %hu to %hu, %hu (width %hu, height %hu)\n", item->x, item->y, item->x + item->w, item->y + item->h,
|
|
|
|
item->w, item->h));
|
|
|
|
}
|
|
|
|
switch (item->type) {
|
|
|
|
case MENUITEM_SUBMENU:
|
Mon Sep 20 18:32:01 PDT 1999 Michael Jennings <mej@eterm.org>
Lots of changes here. First off, this should fix the background draw
bug with transparency that several people pointed out. While I was
at it, I also cleaned up a lot of other related stuff. Three-state
images should be a lot more robust now.
Then again, some stuff may be broken entirely from this, so let me
know. :-)
For one thing, the various image modes should work as expected now.
You can allow and disallow modes for the various widgets. The
fallback mode is "solid" now, rather than "image," so you can cause
a certain widget to refuse to use an image if you want to. If you
specify an image without specifying a "mode" line that allows the
"image" mode, your image will not appear. <-- READ THIS TWICE! I
had to go back and fix all the theme files because of this, so you
will need to remove your current theme directory and allow Eterm's
"make install" to put the new ones in place; otherwise, everything
will go back to being solid colors. =]
Anytime something changes this drastically, there are bound to be
problems. Let me know if you find any of them. :)
SVN revision: 348
1999-09-20 18:16:46 -07:00
|
|
|
if (image_mode_is(image_submenu, MODE_IMAGE) && image_mode_is(image_submenu, ALLOW_IMAGE)) {
|
|
|
|
paste_simage(images[image_submenu].norm, menu->win, item->x, item->y, item->w - MENU_VGAP, item->h);
|
|
|
|
}
|
1999-08-17 18:12:47 -07:00
|
|
|
break;
|
|
|
|
case MENUITEM_STRING:
|
|
|
|
#if 0
|
|
|
|
safeaction = StrDup(item->action.string);
|
|
|
|
SafeStr(safeaction, strlen(safeaction));
|
|
|
|
D_MENU((" Item %hu: %s (string %s)\n", i, item->text, safeaction));
|
|
|
|
FREE(safeaction);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case MENUITEM_ECHO:
|
|
|
|
#if 0
|
|
|
|
safeaction = StrDup(item->action.string);
|
|
|
|
SafeStr(safeaction, strlen(safeaction));
|
|
|
|
D_MENU((" Item %hu: %s (echo %s)\n", i, item->text, safeaction));
|
|
|
|
FREE(safeaction);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fatal_error("Internal Program Error: Unknown menuitem type: %u\n", item->type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
draw_string(menu->win, menu->gc, str_x, str_y - MENU_VGAP / 2, item->text, item->len);
|
1999-08-20 13:25:04 -07:00
|
|
|
if (item->rtext) {
|
|
|
|
draw_string(menu->win, menu->gc, str_x + item->w - XTextWidth(menu->font, item->rtext, item->rlen) - 3 * MENU_HGAP, str_y - MENU_VGAP / 2,
|
|
|
|
item->rtext, item->rlen);
|
|
|
|
}
|
1999-08-17 18:12:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_display(int x, int y, menu_t * menu)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT(menu != NULL);
|
|
|
|
|
|
|
|
menu->state |= (MENU_STATE_IS_CURRENT);
|
|
|
|
current_menu = menu;
|
|
|
|
|
|
|
|
/* Move, render, and map menu window */
|
|
|
|
menu->x = x;
|
|
|
|
menu->y = y;
|
|
|
|
D_MENU(("Displaying menu \"%s\" (window 0x%08x) at root coordinates %d, %d\n", menu->title, menu->win, menu->x, menu->y));
|
|
|
|
XMoveWindow(Xdisplay, menu->win, menu->x, menu->y);
|
|
|
|
XUnmapWindow(Xdisplay, menu->swin);
|
|
|
|
XMapWindow(Xdisplay, menu->win);
|
|
|
|
menu->state |= (MENU_STATE_IS_MAPPED);
|
|
|
|
|
|
|
|
menu_draw(menu);
|
|
|
|
|
|
|
|
/* Take control of the pointer so we get all events for it, even those outside the menu window */
|
|
|
|
grab_pointer(menu->win);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_action(menuitem_t * item)
|
|
|
|
{
|
|
|
|
|
|
|
|
ASSERT(item != NULL);
|
|
|
|
|
|
|
|
D_MENU(("menu_action() called to invoke %s\n", item->text));
|
|
|
|
switch (item->type) {
|
|
|
|
case MENUITEM_SEP:
|
|
|
|
D_MENU(("Internal Program Error: menu_action() called for a separator.\n"));
|
|
|
|
break;
|
|
|
|
case MENUITEM_SUBMENU:
|
|
|
|
D_MENU(("Internal Program Error: menu_action() called for a submenu.\n"));
|
|
|
|
break;
|
|
|
|
case MENUITEM_STRING:
|
|
|
|
cmd_write(item->action.string, strlen(item->action.string));
|
|
|
|
break;
|
|
|
|
case MENUITEM_ECHO:
|
|
|
|
tt_write(item->action.string, strlen(item->action.string));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fatal_error("Internal Program Error: Unknown menuitem type: %u\n", item->type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_invoke(int x, int y, Window win, menu_t * menu, Time time)
|
|
|
|
{
|
|
|
|
|
|
|
|
int root_x, root_y;
|
|
|
|
Window unused;
|
|
|
|
|
|
|
|
REQUIRE(menu != NULL);
|
|
|
|
|
|
|
|
if (time != CurrentTime) {
|
|
|
|
button_press_time = time;
|
|
|
|
}
|
|
|
|
if (win != Xroot) {
|
|
|
|
XTranslateCoordinates(Xdisplay, win, Xroot, x, y, &root_x, &root_y, &unused);
|
|
|
|
}
|
|
|
|
menu_display(root_x, root_y, menu);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
menu_invoke_by_title(int x, int y, Window win, char *title, Time time)
|
|
|
|
{
|
|
|
|
|
|
|
|
menu_t *menu;
|
|
|
|
|
|
|
|
REQUIRE(title != NULL);
|
|
|
|
REQUIRE(menu_list != NULL);
|
|
|
|
|
|
|
|
menu = find_menu_by_title(menu_list, title);
|
|
|
|
if (!menu) {
|
|
|
|
D_MENU(("Menu \"%s\" not found!\n", title));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
menu_invoke(x, y, win, menu, time);
|
|
|
|
}
|