Files
amiwm-neo/menu.c
Adrian Chadd def62797f9 [amiwm] Update to 0.22pl2
This notably includes full screen support!

Addresses Issue #12
2023-12-21 22:09:25 -08:00

1026 lines
29 KiB
C

#include <X11/Xlib.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "alloc.h"
#include "drawinfo.h"
#include "prefs.h"
#include "screen.h"
#include "client.h"
#include "icon.h"
#include "version.h"
#define ABOUT_STRING(LF) \
" " LF "version "VERSION LF "by Marcus Comstedt" LF \
"<marcus@lysator.liu.se>" LF " " LF \
"Contributions by Scott Lawrence" LF "<amiwm10@umlautllama.com>" LF \
"and Nicolas Sipieter " LF "<freeeaks@gmail.com>" LF " " LF \
"Some small contributions by redsPL" LF "<reds@sakamoto.pl>" LF " " LF
#ifdef AMIGAOS
#include <pragmas/xlib_pragmas.h>
extern struct Library *XLibBase;
#endif
#ifdef AMIGAOS
#define BIN_PREFIX AMIWM_HOME
#else
#define BIN_PREFIX AMIWM_HOME"/"
#endif
#define CHECKIT 1
#define CHECKED 2
#define DISABLED 4
char battery_status[128];
extern Display *dpy;
extern Cursor wm_curs;
extern XContext screen_context, client_context;
extern Client *activeclient;
extern void select_all_icons(Scrn *i);
extern void mod_menuselect(struct module *, int, int, int);
extern void setfocus(Window);
extern void flushmodules();
extern void wberror(Scrn *, char *);
Scrn *mbdclick=NULL, *mbdscr=NULL;
static struct ToolItem {
struct ToolItem *next;
const char *name, *cmd;
char hotkey;
int level;
struct Menu *submenu;
} *firsttoolitem=NULL, *lasttoolitem=NULL;
static struct Item {
struct Item *next;
Window win;
const char *text;
int textlen;
char hotkey, flags;
struct Menu *menu, *sub;
struct module *owner;
struct Item *mod_chain;
} *activeitem=NULL, *activesubitem=NULL;
static struct Menu {
struct Menu *next;
struct Item *item;
Window win, parent;
const char *title;
int titlelen;
int width, height;
char flags;
struct Item *firstitem, *lastitem;
} *activemenu=NULL, *activesubmenu=NULL;
#ifdef AMIGAOS
void spawn(const char *cmd)
{
char *line=malloc(strlen(cmd)+12);
if(line) {
sprintf(line, "RUN <>NIL: %s", cmd);
system(line);
free(line);
}
}
#else
void spawn(const char *cmd)
{
extern char *x_server;
#ifdef HAVE_ALLOCA
char *line=alloca(strlen(x_server)+strlen(cmd)+28);
#else
char *line=malloc(strlen(x_server)+strlen(cmd)+28);
if(line) {
#endif
char *dot;
sprintf(line, "DISPLAY='%s", x_server);
if(!(dot=strrchr(line, '.')) || strchr(dot, ':'))
dot=line+strlen(line);
sprintf(dot, ".%d' %s &", scr->number, cmd);
#ifdef __ultrix
{
int pid, status;
if ((pid = fork ()) == 0) {
(void) setsid();
execl ("/bin/sh", "sh", "-c", line, 0);
} else
waitpid (pid, &status, 0);
}
#else
system(line);
#endif
#ifndef HAVE_ALLOCA
free(line);
}
#endif
}
#endif
void add_toolitem(const char *n, const char *c, const char *k, int l)
{
struct ToolItem *ti;
if((ti=malloc(sizeof(struct ToolItem)))) {
ti->name=n;
ti->cmd=c;
if(k)
ti->hotkey=k[0];
else
ti->hotkey=0;
ti->level=l;
ti->next=NULL;
if(lasttoolitem)
lasttoolitem->next=ti;
else
firsttoolitem=ti;
lasttoolitem=ti;
}
}
static void menu_layout(struct Menu *menu)
{
XSetWindowAttributes attr;
XWindowAttributes attr2;
int w, x, y;
struct Item *item;
if(menu->win) {
XGetWindowAttributes(dpy, menu->win, &attr2);
x=attr2.x; y=scr->bh-2;
} else {
XGetWindowAttributes(dpy, menu->item->win, &attr2);
x=attr2.x+attr2.width-scr->hotkeyspace+9; y=attr2.y-2;
XGetWindowAttributes(dpy, menu->item->menu->parent, &attr2);
x+=attr2.x; y+=attr2.y;
}
menu->width=menu->height=0;
for(item=menu->firstitem; item; item=item->next) {
if(item->text)
menu->height+=scr->dri.dri_Ascent+scr->dri.dri_Descent+1;
else
menu->height+=6;
#ifdef USE_FONTSETS
w=XmbTextEscapement(scr->dri.dri_FontSet, item->text, item->textlen)+2;
#else
w=XTextWidth(scr->dri.dri_Font, item->text, item->textlen)+2;
#endif
if(item->hotkey)
w+=scr->hotkeyspace;
if(item->flags&CHECKIT)
w+=scr->checkmarkspace;
if(item->sub)
w+=scr->subspace;
if(w>menu->width)
menu->width=w;
}
menu->width+=6;
menu->height+=2;
attr.override_redirect=True;
attr.background_pixel=scr->dri.dri_Pens[BARBLOCKPEN];
attr.border_pixel=scr->dri.dri_Pens[BARDETAILPEN];
menu->parent=XCreateWindow(dpy, scr->back, x, y,
menu->width, menu->height, 1,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect|CWBackPixel|CWBorderPixel,
&attr);
XSaveContext(dpy, menu->parent, screen_context, (XPointer)scr);
XSelectInput(dpy, menu->parent, ExposureMask);
w=1;
for(item=menu->firstitem; item; item=item->next) {
int h=(item->text? scr->dri.dri_Ascent+scr->dri.dri_Descent+1:6);
item->win=XCreateWindow(dpy, menu->parent, 3, w, menu->width-6, h, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect|CWBackPixel, &attr);
XSaveContext(dpy, item->win, screen_context, (XPointer)scr);
w+=h;
XSelectInput(dpy, item->win, ExposureMask|ButtonReleaseMask|
EnterWindowMask|LeaveWindowMask);
}
XMapSubwindows(dpy, menu->parent);
}
static struct Menu *add_menu(const char *name, char flags)
{
struct Menu *menu=calloc(1, sizeof(struct Menu));
XSetWindowAttributes attr;
int w;
if(menu) {
attr.override_redirect=True;
attr.background_pixel=scr->dri.dri_Pens[BARBLOCKPEN];
#ifdef USE_FONTSETS
w=XmbTextEscapement(scr->dri.dri_FontSet, name, menu->titlelen=strlen(name))+8;
#else
w=XTextWidth(scr->dri.dri_Font, name, menu->titlelen=strlen(name))+8;
#endif
menu->win=XCreateWindow(dpy, scr->menubarparent, scr->menuleft, 0, w, scr->bh-1, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect|CWBackPixel, &attr);
XSaveContext(dpy, menu->win, screen_context, (XPointer)scr);
XMapWindow(dpy, menu->win);
XSelectInput(dpy, menu->win, ExposureMask|EnterWindowMask|LeaveWindowMask);
scr->menuleft+=w+6;
menu->flags=flags;
menu->title=name;
menu->item=NULL;
menu->firstitem=menu->lastitem=NULL;
menu->next=scr->firstmenu;
scr->firstmenu=menu;
}
return menu;
}
static struct Item *add_item(struct Menu *m, const char *name, char key,
char flags)
{
struct Item *item=calloc(1, sizeof(struct Item));
if(item) {
if(name) {
item->text=name;
item->textlen=strlen(name);
} else item->text=NULL;
item->hotkey=key;
item->flags=flags;
item->menu=m;
item->sub=NULL;
item->next=NULL;
if(m->lastitem)
m->lastitem->next=item;
else
m->firstitem=item;
m->lastitem=item;
}
return item;
}
static struct Menu *sub_menu(struct Item *i, char flags)
{
struct Menu *menu=calloc(1, sizeof(struct Menu));
if(menu) {
menu->flags=flags;
menu->title=NULL;
menu->firstitem=menu->lastitem=NULL;
menu->next=NULL;
menu->item=i;
i->sub=menu;
}
return menu;
}
void redraw_menu(struct Menu *m, Window w)
{
int active=(m==activemenu && !(m->flags & DISABLED));
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[active?BARBLOCKPEN:
BARDETAILPEN]);
XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[active?BARDETAILPEN:
BARBLOCKPEN]);
#ifdef USE_FONTSETS
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet,
scr->menubargc, 4, 1+scr->dri.dri_Ascent,
m->title, m->titlelen);
#else
XDrawImageString(dpy, w, scr->menubargc, 4, 1+scr->dri.dri_Ascent,
m->title, m->titlelen);
#endif
}
void redraw_item(struct Item *i, Window w)
{
struct Menu *m=i->menu;
int s=scr->dri.dri_Ascent>>1;
if((i==activeitem || i==activesubitem) && !(i->flags&DISABLED)) {
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]);
XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]);
} else {
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]);
XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]);
}
if(i->text) {
#ifdef USE_FONTSETS
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet,
scr->menubargc, (i->flags&CHECKIT)?1+scr->checkmarkspace:1,
scr->dri.dri_Ascent+1, i->text, i->textlen);
#else
XDrawImageString(dpy, w, scr->menubargc, (i->flags&CHECKIT)?1+scr->checkmarkspace:1,
scr->dri.dri_Ascent+1, i->text, i->textlen);
#endif
} else {
XFillRectangle(dpy, w, scr->menubargc, 2, 2, m->width-10, 2);
}
if(i->sub) {
int x=m->width-6-scr->hotkeyspace-1+8;
#ifdef USE_FONTSETS
#ifdef HAVE_XUTF8DRAWIMAGESTRING
Xutf8DrawImageString(dpy, w, scr->dri.dri_FontSet,
scr->menubargc, x+scr->dri.dri_Ascent+1,
1+scr->dri.dri_Ascent, "\302\273", 2);
#else
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet,
scr->menubargc, x+scr->dri.dri_Ascent+1,
1+scr->dri.dri_Ascent, "»", 1);
#endif
#else
XDrawImageString(dpy, w, scr->menubargc, x+scr->dri.dri_Ascent+1,
1+scr->dri.dri_Ascent, "»", 1);
#endif
} else if(i->hotkey) {
int x=m->width-6-scr->hotkeyspace-1+8;
XDrawLine(dpy, w, scr->menubargc, x, 1+s, x+s, 1);
XDrawLine(dpy, w, scr->menubargc, x+s, 1, x+s+s, 1+s);
XDrawLine(dpy, w, scr->menubargc, x+s+s, 1+s, x+s, 1+s+s);
XDrawLine(dpy, w, scr->menubargc, x+s, 1+s+s, x, 1+s);
#ifdef USE_FONTSETS
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet,
scr->menubargc, x+scr->dri.dri_Ascent+1,
1+scr->dri.dri_Ascent, &i->hotkey, 1);
#else
XDrawImageString(dpy, w, scr->menubargc, x+scr->dri.dri_Ascent+1,
1+scr->dri.dri_Ascent, &i->hotkey, 1);
#endif
}
if(i->flags&CHECKED) {
XDrawLine(dpy, w, scr->menubargc, 0, s, s, scr->dri.dri_Ascent);
XDrawLine(dpy, w, scr->menubargc, s, scr->dri.dri_Ascent, s+s, 0);
}
if(i->flags&DISABLED) {
XSetStipple(dpy, scr->menubargc, scr->disabled_stipple);
XSetFillStyle(dpy, scr->menubargc, FillStippled);
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]);
XFillRectangle(dpy, w, scr->menubargc, 0, 0,
m->width-6, scr->dri.dri_Ascent+scr->dri.dri_Descent+1);
XSetFillStyle(dpy, scr->menubargc, FillSolid);
}
}
void createmenubar()
{
XSetWindowAttributes attr;
struct Menu *m, *sm1;
// struct Menu *sm2, *sm3;
struct ToolItem *ti;
GC gc;
scr->firstmenu = NULL;
attr.override_redirect=True;
if (scr->deftitle) {
attr.background_pixel=scr->dri.dri_Pens[BARBLOCKPEN];
scr->menubar=XCreateWindow(dpy, scr->back, 0, 0, scr->width, scr->bh, 0,
CopyFromParent,
InputOutput, CopyFromParent,
CWOverrideRedirect|CWBackPixel,
&attr);
scr->menubarparent=XCreateWindow(dpy, scr->menubar, 0, 0, scr->width,
scr->bh-1, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect|CWBackPixel, &attr);
attr.background_pixel=scr->dri.dri_Pens[BACKGROUNDPEN];
scr->menubardepth=XCreateWindow(dpy, scr->menubar, scr->width-23,
0, 23, scr->bh, 0,
CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect|CWBackPixel, &attr);
} else {
scr->menubar=XCreateWindow(dpy, scr->back, 0, 0, scr->width, scr->bh, 0, 0,
InputOnly, CopyFromParent,
CWOverrideRedirect, &attr);
scr->menubarparent=None;
scr->menubardepth=XCreateWindow(dpy, scr->menubar, scr->width-23,
0, 23, scr->bh, 0, 0,
InputOnly, CopyFromParent,
CWOverrideRedirect, &attr);
}
XSaveContext(dpy, scr->menubar, screen_context, (XPointer)scr);
if (scr->menubarparent)
XSaveContext(dpy, scr->menubarparent, screen_context, (XPointer)scr);
XSaveContext(dpy, scr->menubardepth, screen_context, (XPointer)scr);
scr->disabled_stipple=XCreatePixmap(dpy, scr->back, 6, 2, 1);
gc=XCreateGC(dpy, scr->disabled_stipple, 0, NULL);
XSetForeground(dpy, gc, 0);
XFillRectangle(dpy, scr->disabled_stipple, gc, 0, 0, 6, 2);
XSetForeground(dpy, gc, 1);
XDrawPoint(dpy, scr->disabled_stipple, gc, 0, 0);
XDrawPoint(dpy, scr->disabled_stipple, gc, 3, 1);
XFreeGC(dpy, gc);
if (scr->deftitle) {
scr->menubargc=XCreateGC(dpy, scr->menubar, 0, NULL);
#ifndef USE_FONTSETS
XSetFont(dpy, scr->menubargc, scr->dri.dri_Font->fid);
#endif
XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]);
} else {
scr->menubargc = NULL;
}
XSelectInput(dpy, scr->menubar, ExposureMask|ButtonPressMask|ButtonReleaseMask);
XSelectInput(dpy, scr->menubardepth, ExposureMask|ButtonPressMask|
ButtonReleaseMask|EnterWindowMask|LeaveWindowMask);
XMapWindow(dpy, scr->menubardepth);
XMapWindow(dpy, scr->menubar);
scr->hotkeyspace=8+1+scr->dri.dri_MaxBoundsWidth+
scr->dri.dri_Ascent;
scr->checkmarkspace=4+scr->dri.dri_Ascent;
scr->subspace=scr->hotkeyspace-scr->dri.dri_Ascent;
scr->menuleft=4;
if (!scr->menubarparent)
return;
m=add_menu("Workbench", 0);
//add_item(m,"Backdrop",'B',CHECKIT|CHECKED|DISABLED);
add_item(m,"Execute Command...",'E',0);
add_item(m,"Configuration",'C',0);
add_item(m,"Redraw All",0,0);
//add_item(m,"Update All",0,DISABLED);
//add_item(m,"Last Message",0,DISABLED);
add_item(m,NULL,0,DISABLED);
add_item(m,"About...",'?',0);
add_item(m,"Quit...",'Q',0);
menu_layout(m);
/*m=add_menu("Window", 0);
add_item(m,"New Drawer",'N',DISABLED);
add_item(m,"Open Parent",0,DISABLED);
add_item(m,"Close",'K',DISABLED);
add_item(m,"Update",0,DISABLED);
add_item(m,"Select Contents",'A',0);
add_item(m,"Clean Up",'.',0);
sm1=sub_menu(add_item(m,"Snapshot",0,DISABLED),0);
add_item(sm1, "Window",0,DISABLED);
add_item(sm1, "All",0,DISABLED);
sm2=sub_menu(add_item(m,"Show",0,DISABLED),0);
add_item(sm2, "Only Icons",0,CHECKIT|CHECKED|DISABLED);
add_item(sm2, "All Files",'V',CHECKIT|DISABLED);
sm3=sub_menu(add_item(m,"View By",0,DISABLED),0);
add_item(sm3, "Icon",0,CHECKIT|CHECKED|DISABLED);
add_item(sm3, "Name",0,CHECKIT|DISABLED);
add_item(sm3, "Date",0,CHECKIT|DISABLED);
add_item(sm3, "Size",0,CHECKIT|DISABLED);
menu_layout(m);
menu_layout(sm1);
menu_layout(sm2);
menu_layout(sm3);*/
/*m=add_menu("Icons", DISABLED);
add_item(m,"Open",'O',DISABLED);
add_item(m,"Copy",'C',DISABLED);
add_item(m,"Rename...",'R',DISABLED);
add_item(m,"Information...",'I',DISABLED);
add_item(m,"Snapshot",'S',DISABLED);
add_item(m,"UnSnapshot",'U',DISABLED);
add_item(m,"Leave Out",'L',DISABLED);
add_item(m,"Put Away",'P',DISABLED);
add_item(m,NULL,0,DISABLED);
add_item(m,"Delete...",'D',DISABLED);
add_item(m,"Format Disk...",0,DISABLED);
add_item(m,"Empty Trash",0,DISABLED);
menu_layout(m);*/
m=add_menu("Tools", 0);
#ifdef AMIGAOS
add_item(m,"ResetWB",0,DISABLED);
#else
add_item(m,"ResetWB",0,0);
#endif
for(ti=firsttoolitem; ti; ti=ti->next)
if(ti->level<0)
ti->submenu=sm1=sub_menu(add_item(m,ti->name,ti->hotkey,0),0);
else {
ti->submenu=NULL;
add_item((ti->level? sm1:m), ti->name,ti->hotkey,(ti->cmd? 0:DISABLED));
}
menu_layout(m);
for(ti=firsttoolitem; ti; ti=ti->next)
if(ti->submenu) {
menu_layout(ti->submenu);
ti->submenu=NULL;
}
if(prefs.screenmenu) {
m=add_menu("Screens",0);
add_item(m,"New Screen",0,0);
add_item(m,"Delete Screen",0,0);
menu_layout(m);
}
}
/*
* Redraw the menu bar and its components.
*
* This takes in the target window, which may be the basic menubar,
* a clicked-on menu, or the depth widget.
*/
void redrawmenubar(Scrn *scr, Window w)
{
static const char defaultTimeFormat[] = "%c";
int widget_rhs;
struct Menu *m;
struct Item *item;
if(!w || !scr->menubargc)
return;
if(w==scr->menubar) {
/* Menubar itself */
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]);
XSetBackground(dpy, scr->menubargc, scr->dri.dri_Pens[BARBLOCKPEN]);
#ifdef USE_FONTSETS
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet,
scr->menubargc, 4, 1+scr->dri.dri_Ascent,
scr->title, strlen(scr->title));
#else
XDrawImageString(dpy, w, scr->menubargc, 4, 1+scr->dri.dri_Ascent,
scr->title, strlen(scr->title));
#endif
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARTRIMPEN]);
XDrawLine(dpy, w, scr->menubargc, 0, scr->bh-1, scr->width-1, scr->bh-1);
/* Widgets start here and move to the left */
widget_rhs = (scr->width - 30);
/*
* Update the title bar clock if it's enabled.
*/
if( prefs.titlebarclock )
{
char clockbuf[512];
const char * fmt = defaultTimeFormat;
time_t the_time;
int l;
if( prefs.titleclockformat ) fmt = prefs.titleclockformat;
time( &the_time );
strftime( clockbuf, 512, fmt, localtime( &the_time ) );
#ifdef USE_FONTSETS
l = XmbTextEscapement(scr->dri.dri_FontSet, clockbuf, strlen(clockbuf));
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet, scr->menubargc,
widget_rhs - l, 1+scr->dri.dri_Ascent,
clockbuf, strlen(clockbuf));
#else
l = XTextWidth(scr->dri.dri_Font, clockbuf, strlen(clockbuf));
XDrawImageString( dpy, w, scr->menubargc, widget_rhs - l,
1+scr->dri.dri_Ascent, clockbuf, strlen(clockbuf));
#endif
widget_rhs = widget_rhs - l - 8; // 8 = padding
}
/*
* Update the battery indicator if it's enabled.
*/
if (prefs.battery_info) {
char battery_buf[512];
int l;
sprintf(battery_buf, "| %s |", battery_status);
#ifdef USE_FONTSETS
l = XmbTextEscapement(scr->dri.dri_FontSet, battery_buf, strlen(battery_buf));
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet, scr->menubargc,
widget_rhs - l, 1+scr->dri.dri_Ascent,
battery_buf, strlen(battery_buf));
#else
l = XTextWidth(scr->dri.dri_Font, battery_buf, strlen(battery_buf));
XDrawImageString( dpy, w, scr->menubargc, widget_rhs - l,
1+scr->dri.dri_Ascent, battery_buf, strlen(battery_buf));
#endif
widget_rhs = widget_rhs - l - 8; // 8 = padding
}
} else if(w==scr->menubardepth) {
/* Menubar depth widget */
if(!mbdclick) {
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[SHADOWPEN]);
XDrawRectangle(dpy, w, scr->menubargc, 4, scr->h2, 10, scr->h6-scr->h2);
}
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[SHINEPEN]);
XFillRectangle(dpy, w, scr->menubargc, 8, scr->h4, 10, scr->h8-scr->h4);
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[SHADOWPEN]);
XDrawRectangle(dpy, w, scr->menubargc, 8, scr->h4, 10, scr->h8-scr->h4);
if(mbdclick)
XDrawRectangle(dpy, w, scr->menubargc, 4, scr->h2, 10, scr->h6-scr->h2);
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[mbdclick?SHADOWPEN:SHINEPEN]);
XDrawLine(dpy, w, scr->menubargc, 0, 0, 22, 0);
XDrawLine(dpy, w, scr->menubargc, 0, 0, 0, scr->bh-2);
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[mbdclick?SHINEPEN:SHADOWPEN]);
XDrawLine(dpy, w, scr->menubargc, 0, scr->bh-1, 22, scr->bh-1);
XDrawLine(dpy, w, scr->menubargc, 22, 0, 22, scr->bh-1);
} else {
/* One of the menus is being displayed */
for(m=scr->firstmenu; m; m=m->next)
if(m->win==w)
redraw_menu(m, w);
if(activemenu) {
for(item=activemenu->firstitem; item; item=item->next)
if(item->win==w)
redraw_item(item, w);
if(w==activemenu->parent) {
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]);
XDrawLine(dpy, w, scr->menubargc, 0, 0, 0, activemenu->height-1);
XDrawLine(dpy, w, scr->menubargc, activemenu->width-1, 0,
activemenu->width-1, activemenu->height-1);
}
}
if(activesubmenu) {
for(item=activesubmenu->firstitem; item; item=item->next)
if(item->win==w)
redraw_item(item, w);
if(w==activesubmenu->parent) {
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[BARDETAILPEN]);
XDrawLine(dpy, w, scr->menubargc, 0, 0, 0, activesubmenu->height-1);
XDrawLine(dpy, w, scr->menubargc, activesubmenu->width-1, 0,
activesubmenu->width-1, activesubmenu->height-1);
}
}
}
}
static void leave_item(struct Item *i, Window w)
{
if(i==activesubitem)
activesubitem=NULL;
if(i==activeitem) {
if(activesubmenu && i->sub==activesubmenu) {
return;
} else {
activeitem=NULL;
}
}
XSetWindowBackground(dpy, i->win, scr->dri.dri_Pens[BARBLOCKPEN]);
XClearWindow(dpy, i->win);
redraw_item(i, i->win);
}
static void enter_item(struct Item *i, Window w)
{
if(activesubitem)
leave_item(activesubitem, activesubitem->win);
if(activesubmenu!=i->sub && i->menu!=activesubmenu) {
if(activesubmenu)
XUnmapWindow(dpy, activesubmenu->parent);
if(i->sub)
XMapRaised(dpy, i->sub->parent);
activesubmenu=i->sub;
}
if(activeitem && !(activeitem->sub && i->menu==activeitem->sub))
leave_item(activeitem, activeitem->win);
if(!(i->flags&DISABLED)) {
if(activeitem)
activesubitem=i;
else
activeitem=i;
XSetWindowBackground(dpy, i->win, scr->dri.dri_Pens[BARDETAILPEN]);
XClearWindow(dpy, i->win);
redraw_item(i, i->win);
}
}
static void enter_menu(struct Menu *m, Window w)
{
if(m!=activemenu) {
struct Menu *oa=activemenu;
if(activesubitem)
leave_item(activeitem, activesubitem->win);
if(activesubmenu) {
XUnmapWindow(dpy, activesubmenu->parent);
activesubmenu=NULL;
}
if(activeitem)
leave_item(activeitem, activeitem->win);
if(!(m->flags & DISABLED))
XSetWindowBackground(dpy, w, scr->dri.dri_Pens[BARDETAILPEN]);
XClearWindow(dpy, w);
redraw_menu(activemenu=m, w);
if(m->parent)
XMapRaised(dpy, m->parent);
if(oa) {
if(oa->parent)
XUnmapWindow(dpy, oa->parent);
XSetWindowBackground(dpy, oa->win, scr->dri.dri_Pens[BARBLOCKPEN]);
XClearWindow(dpy, oa->win);
redraw_menu(oa, oa->win);
}
}
}
void menubar_enter(Window w)
{
struct Menu *m;
struct Item *i;
for(m=scr->firstmenu; m; m=m->next)
if(m->win==w) {
enter_menu(m, w);
return;
}
if((m=activemenu))
for(i=m->firstitem; i; i=i->next)
if(w==i->win) {
enter_item(i, w);
return;
}
if((m=activesubmenu))
for(i=m->firstitem; i; i=i->next)
if(w==i->win) {
enter_item(i, w);
return;
}
}
void menubar_leave(Window w)
{
if(activesubitem && activesubitem->win==w)
leave_item(activesubitem, w);
if(activeitem && activeitem->win==w)
leave_item(activeitem, w);
}
void menu_on()
{
Window r, c;
int rx, ry, x, y;
unsigned int m;
if(scr->menubarparent) {
XMapRaised(dpy, scr->menubarparent);
XRaiseWindow(dpy, scr->menubar);
XGrabPointer(dpy, scr->back, True, ButtonPressMask|ButtonReleaseMask|
EnterWindowMask|LeaveWindowMask, GrabModeAsync, GrabModeAsync,
scr->back, wm_curs, CurrentTime);
XSetInputFocus(dpy, scr->menubar, RevertToParent, CurrentTime);
if(XQueryPointer(dpy, scr->menubarparent, &r, &c, &rx, &ry, &x, &y, &m))
menubar_enter(c);
}
}
void menuaction(struct Item *i, struct Item *si)
{
extern void restart_amiwm(void);
extern int screen_has_clients(void);
struct Menu *m;
struct Item *mi;
struct ToolItem *ti;
int menu=0, item=0, sub=0;
for(m=i->menu->next; m; m=m->next) menu++;
for(mi=i->menu->firstitem; mi&&mi!=i; mi=mi->next) item++;
if(i->sub) {
for(mi=i->sub->firstitem; mi&&mi!=si; mi=mi->next) sub++;
if(!mi)
sub=-1;
} else
--sub;
mi=(sub>=0? si:i);
if(mi->flags & DISABLED)
return;
if(mi->owner) {
mod_menuselect(mi->owner, menu, item, sub);
return;
}
switch(menu) {
case 0: /* Workbench */
switch(item) {
case 0:
spawn(BIN_PREFIX"executecmd");
break;
case 1:
spawn(BIN_PREFIX"config_util");
case 2:
{
XSetWindowAttributes xswa;
unsigned long mask;
Window win;
xswa.background_pixmap = None;
xswa.override_redirect = True;
xswa.backing_store = NotUseful;
xswa.save_under = False;
mask = CWBackPixmap|CWOverrideRedirect|CWBackingStore|CWSaveUnder;
win = XCreateWindow(dpy, scr->back, 0, 0, scr->width, scr->height,
0, scr->depth, InputOutput,
scr->visual, mask, &xswa);
XMapWindow(dpy, win);
XDestroyWindow(dpy, win);
}
break;
case 4:
#ifdef AMIGAOS
spawn(BIN_PREFIX"requestchoice >NIL: amiwm \""
ABOUT_STRING("*N") "\" Ok");
#else
spawn(BIN_PREFIX"requestchoice >/dev/null amiwm '"
ABOUT_STRING("\n") "' Ok");
#endif
break;
case 5:
#ifndef AMIGAOS
if(prefs.fastquit) {
#endif
exit(0);
#ifndef AMIGAOS
} else {
#ifdef HAVE_ALLOCA
char *buf=alloca(256);
#else
char buf[256];
#endif
sprintf(buf, "; export DISPLAY; ( if [ `"BIN_PREFIX"requestchoice "
"Workbench 'Do you really want\nto quit workbench?' Ok Cancel`"
" = 1 ]; then kill %d; fi; )", (int)getpid());
spawn(buf);
}
#endif
break;
}
break;
/* case 1: // Window
switch(item) {
case 4:
select_all_icons(scr);
break;
case 5:
cleanupicons();
break;
}
break; */
// case 2: /* Icons */
// break;
case 1: /* Tools */
#ifndef AMIGAOS
if(item==0)
restart_amiwm();
#endif
if(item>0) {
int it=0, si=-1;
for(ti=firsttoolitem; ti; ti=ti->next) {
if(ti->level>0)
si++;
else {
it++;
si=-1;
}
if(it==item && si==sub) break;
}
if(ti && ti->cmd) spawn(ti->cmd);
}
break;
case 2: /* Screens */
if(item==0) {
openscreen("New Screen", DefaultRootWindow(dpy));
realizescreens();
scr = get_front_scr()->upfront;
screentoback();
}
if(item==1) {
if(scr->behind == scr)
wberror(scr,"Cannot close last Screen");
else if(screen_has_clients())
wberror(scr,"Can't close a screen with running programs on it");
else
closescreen();
}
break;
}
}
void menu_off()
{
struct Menu *oa;
struct Item *oi, *osi;
if(scr->menubarparent) {
Window r,p,*children;
unsigned int nchildren;
XUngrabPointer(dpy, CurrentTime);
setfocus((activeclient && activeclient->state==NormalState?
activeclient->window:None));
XUnmapWindow(dpy, scr->menubarparent);
if(XQueryTree(dpy, scr->back, &r, &p, &children, &nchildren)) {
int n;
Client *c2;
for(n=0; n<nchildren; n++)
if((!XFindContext(dpy, children[n], client_context, (XPointer*)&c2)) &&
children[n]==c2->parent)
break;
if(n<nchildren) {
Window ws[2];
ws[0]=children[n];
ws[1]=scr->menubar;
XRestackWindows(dpy, ws, 2);
}
if(children) XFree(children);
}
}
if((osi=activesubitem))
leave_item(osi, osi->win);
if((oi=activeitem))
leave_item(oi, oi->win);
if((oa=activesubmenu)) {
activesubmenu=NULL;
if(oa->parent)
XUnmapWindow(dpy, oa->parent);
}
if((oa=activemenu)) {
activemenu=NULL;
if(oa->parent)
XUnmapWindow(dpy, oa->parent);
XSetWindowBackground(dpy, oa->win, scr->dri.dri_Pens[BARBLOCKPEN]);
XClearWindow(dpy, oa->win);
redraw_menu(oa, oa->win);
}
if(oi) {
XSync(dpy, False);
menuaction(oi, osi);
}
}
struct Item *getitembyhotkey(KeySym key)
{
struct Menu *m;
struct Item *i;
if(key) {
if(key>='a' && key<='z')
key-=0x20;
for(m=scr->firstmenu; m; m=m->next)
for(i=m->firstitem; i; i=i->next)
if(i->hotkey==key)
return i;
}
return NULL;
}
static struct Item *own_item(struct module *m, struct Item *i, struct Item *c)
{
if(i->owner)
return NULL;
i->owner = m;
i->mod_chain = c;
i->flags &= ~DISABLED;
redraw_item(i, i->win);
return i;
}
void disown_item_chain(struct module *m, struct Item *i)
{
while(i)
if(i->owner == m) {
struct Item *c = i->mod_chain;
i->owner = NULL;
i->mod_chain = NULL;
i->flags |= DISABLED;
redraw_item(i, i->win);
i = c;
} else
i=i->mod_chain;
}
struct Item *own_items(struct module *m, Scrn *s,
int menu, int item, int sub, struct Item *c)
{
struct Item *cl, *chain = NULL, *endlink = NULL;
int m0, m1, mn;
struct Menu *mm;
if(!s) return NULL;
if(menu<0) {
m0 = 0; m1 = 65535;
} else m0 = m1 = menu;
for(mn=0, mm=s->firstmenu; mm && mn <= m1; mm=mm->next, mn++)
if(mn>=m0) {
int i0, i1, in;
struct Item *ii;
if(item<0) {
i0 = 0; i1 = 65535;
} else i0 = i1 = item;
for(in=0, ii=mm->firstitem; ii && in <= i1; ii=ii->next, in++)
if(in>=i0) {
int s0, s1, sn;
struct Item *ss;
if(!(cl=own_item(m, ii, chain))) {
disown_item_chain(m, chain);
return NULL;
} else chain=cl;
if(!endlink) endlink=chain;
if(ii->sub) {
if(sub<0) {
s0 = 0; s1 = 65535;
} else s0 = s1 = sub;
for(sn=0, ss=ii->sub->firstitem; ss && sn <= i1; ss=ss->next, sn++)
if(sn>=s0) {
if(!(cl=own_item(m, ss, chain))) {
disown_item_chain(m, chain);
return NULL;
} else chain=cl;
}
}
}
}
if(endlink)
endlink->next = c;
return chain;
}