mirror of
https://github.com/amiwm/amiwm.git
synced 2026-03-24 01:24:15 +00:00
Keep state local into click_*() for routines relating to button clicks than in global variables around frame.c and main.c
1026 lines
29 KiB
C
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;
|
|
|
|
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, "»", 2);
|
|
#else
|
|
XmbDrawImageString(dpy, w, scr->dri.dri_FontSet,
|
|
scr->menubargc, x+scr->dri.dri_Ascent+1,
|
|
1+scr->dri.dri_Ascent, "\xBB", 1);
|
|
#endif
|
|
#else
|
|
XDrawImageString(dpy, w, scr->menubargc, x+scr->dri.dri_Ascent+1,
|
|
1+scr->dri.dri_Ascent, "\xBB", 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 != scr) {
|
|
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 == scr)
|
|
XDrawRectangle(dpy, w, scr->menubargc, 4, scr->h2, 10, scr->h6-scr->h2);
|
|
XSetForeground(dpy, scr->menubargc, scr->dri.dri_Pens[mbdclick==scr?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==scr?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;
|
|
}
|