/****************************************************************************
*
* This mostly original code by Robert Nation
* which reads motif mwm window manager
* hints from a window, and makes necessary adjustments for afterstep.
*
* Slight modifications made by Frank Fejes for AfterStep
*
* Some additions by Alfredo Kojima
*
* Definitions of the hint structure and the constants are courtesy of
* mitnits@bgumail.bgu.ac.il (Roman Mitnitski ), who sent this note,
* after conferring with a friend at the OSF:
* Hi, Rob.
*
*I'm happy to announce, that you can use motif public
*headers in any way you can... I just got the letter from
*my friend, it says literally:
*
*> Hi.
*>
*> Yes, you can use motif public header files, in particular
*> because there is NO limitation on inclusion of this files
*> in your programms....Also, no one can put copyright to the NUMBERS
*> (I mean binary flags for decorations) or DATA STRUCTURES
*> (I mean little structure used by motif to pass description
*> of the decorations to the mwm). Call it another name, if you are
*> THAT MUCH concerned.
*>
*> You can even use the little piece of code I've passed to you -
*> we are talking about 10M distribution against two pages of code.
*> Don't be silly.
*>
*> Best wishes.
*> Eli.
*
*
****************************************************************************
* later modified for Bowman
* by Bo Yang
****************************************************************************/
#include "../configure.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "afterstep.h"
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "screen.h"
#include "parse.h"
#include "menus.h"
#ifdef ENABLE_TEXTURE
#include "stepgfx.h"
#endif
extern Atom _XA_MwmAtom;
/* Motif window hints */
typedef struct
{
CARD32 flags;
CARD32 functions;
CARD32 decorations;
INT32 inputMode;
} PropMotifWmHints;
typedef PropMotifWmHints PropMwmHints;
PropMwmHints prop;
/* Motif window hints */
#define MWM_HINTS_FUNCTIONS (1L << 0)
#define MWM_HINTS_DECORATIONS (1L << 1)
/* bit definitions for MwmHints.functions */
#define MWM_FUNC_ALL (1L << 0)
#define MWM_FUNC_RESIZE (1L << 1)
#define MWM_FUNC_MOVE (1L << 2)
#define MWM_FUNC_MINIMIZE (1L << 3)
#define MWM_FUNC_MAXIMIZE (1L << 4)
#define MWM_FUNC_CLOSE (1L << 5)
/* bit definitions for MwmHints.decorations */
#define MWM_DECOR_ALL (1L << 0)
#define MWM_DECOR_BORDER (1L << 1)
#define MWM_DECOR_RESIZEH (1L << 2)
#define MWM_DECOR_TITLE (1L << 3)
#define MWM_DECOR_MENU (1L << 4)
#define MWM_DECOR_MINIMIZE (1L << 5)
#define MWM_DECOR_MAXIMIZE (1L << 6)
#define PROP_MOTIF_WM_HINTS_ELEMENTS 4
#define PROP_MWM_HINTS_ELEMENTS PROP_MOTIF_WM_HINTS_ELEMENTS
extern ASWindow *Tmp_win;
/****************************************************************************
*
* Reads the property MOTIF_WM_HINTS
*
*****************************************************************************/
void GetMwmHints(ASWindow *t)
{
int actual_format;
Atom actual_type;
unsigned long nitems, bytesafter;
/*
if((Scr.flags & (MWMDecorHints|MWMFunctionHints))&&
(XGetWindowProperty (dpy, t->w, _XA_MwmAtom, 0L, 20L, False,
_XA_MwmAtom, &actual_type, &actual_format, &nitems,
&bytesafter,(unsigned char **)&t->mwm_hints)==Success))
{
if(nitems >= PROP_MOTIF_WM_HINTS_ELEMENTS)
{
return;
}
}
*/
t->mwm_hints = NULL;
}
/****************************************************************************
*
* Interprets the property MOTIF_WM_HINTS, sets decoration and functions
* accordingly
*
*****************************************************************************/
void SelectDecor(ASWindow *t, unsigned long tflags, int border_width,
int resize_width)
{
int decor,i;
PropMwmHints *prop;
if(!(tflags & BW_FLAG))
border_width = Scr.NoBoundaryWidth;
if(!(tflags & NOBW_FLAG))
resize_width = Scr.BoundaryWidth;
for(i=0;i<5;i++)
{
t->left_w[i] = 1;
t->right_w[i] = 1;
}
decor = MWM_DECOR_ALL;
t->functions = MWM_FUNC_ALL;
if(t->mwm_hints)
{
prop = (PropMwmHints *)t->mwm_hints;
/*
if(Scr.flags & MWMDecorHints)
if(prop->flags & MWM_HINTS_DECORATIONS)
decor = prop->decorations;
if(Scr.flags & MWMFunctionHints)
if(prop->flags & MWM_HINTS_FUNCTIONS)
t->functions = prop->functions;
*/
}
/* functions affect the decorations! if the user says
* no iconify function, then the iconify button doesn't show
* up. */
if(t->functions & MWM_FUNC_ALL)
{
/* If we get ALL + some other things, that means to use
* ALL except the other things... */
t->functions &= ~MWM_FUNC_ALL;
t->functions = (MWM_FUNC_RESIZE | MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE |
MWM_FUNC_MAXIMIZE | MWM_FUNC_CLOSE) & (~(t->functions));
}
/*
if((Scr.flags & MWMFunctionHints) && (t->flags & TRANSIENT))
{
t->functions &= ~(MWM_FUNC_MAXIMIZE|MWM_FUNC_MINIMIZE);
}
*/
if(decor & MWM_DECOR_ALL)
{
/* If we get ALL + some other things, that means to use
* ALL except the other things... */
decor &= ~MWM_DECOR_ALL;
decor = (MWM_DECOR_BORDER | MWM_DECOR_RESIZEH | MWM_DECOR_TITLE |
MWM_DECOR_MENU | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE)
& (~decor);
}
/* Now I have the un-altered decor and functions, but with the
* ALL attribute cleared and interpreted. I need to modify the
* decorations that are affected by the functions */
if(!(t->functions & MWM_FUNC_RESIZE))
decor &= ~MWM_DECOR_RESIZEH;
/* MWM_FUNC_MOVE has no impact on decorations. */
if(!(t->functions & MWM_FUNC_MINIMIZE))
decor &= ~MWM_DECOR_MINIMIZE;
if(!(t->functions & MWM_FUNC_MAXIMIZE))
decor &= ~MWM_DECOR_MAXIMIZE;
/* MWM_FUNC_CLOSE has no impact on decorations. */
/* This rule is implicit, but its easier to deal with if
* I take care of it now */
if(decor & (MWM_DECOR_MENU| MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE))
decor |= MWM_DECOR_TITLE;
/* Selected the mwm-decor field, now trim down, based on
* .steprc entries */
if ((tflags & NOTITLE_FLAG)
|| ((!(Scr.flags & DecorateTransients)) && (t->flags & TRANSIENT)))
decor &= ~MWM_DECOR_TITLE;
if ((tflags & NOBORDER_FLAG)
|| ((!(Scr.flags&DecorateTransients)) && (t->flags & TRANSIENT)))
decor &= ~MWM_DECOR_RESIZEH;
/*
if((Scr.flags & MWMDecorHints) && (t->flags & TRANSIENT))
{
decor &= ~(MWM_DECOR_MAXIMIZE|MWM_DECOR_MINIMIZE);
}
*/
#ifdef SHAPE
if(t->wShaped)
decor &= ~(BORDER|MWM_DECOR_RESIZEH);
#endif
/* Assume no decorations, and build up */
t->flags &= ~(BORDER|TITLE);
t->boundary_width = 0;
t->boundary_height = 0;
t->corner_width = 0;
t->title_height = 0;
t->button_height = 0;
if(decor & MWM_DECOR_TITLE)
{
/* A title barm with no buttons in it
* window gets a 1 pixel wide black border. */
t->flags |= TITLE;
t->title_height = Scr.TitleHeight;
}
if(decor & MWM_DECOR_RESIZEH)
{
/* A wide border, with corner tiles is desplayed
* (10 pixels - 2 relief, 2 shadow) */
t->flags |= BORDER;
}
if(!(decor & MWM_DECOR_MENU))
{
/* title-bar menu button omitted
* window gets 1 pixel wide black border */
t->left_w[0] = None;
}
if(!(decor & MWM_DECOR_MINIMIZE))
{
/* title-bar + iconify button, no menu button.
* window gets 1 pixel wide black border */
t->right_w[1] = None;
}
if(!(decor & MWM_DECOR_MAXIMIZE))
{
/* title-bar + maximize button, no menu button, no iconify.
* window has 1 pixel wide black border */
t->right_w[0] = None;
}
t->boundary_width = 0;
t->boundary_height = (t->flags & BORDER)?
Scr.BoundaryWidth : Scr.NoBoundaryWidth;
t->corner_width = Scr.TitleHeight + t->boundary_height;
if (t->buttons & BUTTON1) t->left_w[0]=None;
if (t->buttons & BUTTON3) t->left_w[1]=None;
if (t->buttons & BUTTON5) t->left_w[2]=None;
if (t->buttons & BUTTON7) t->left_w[3]=None;
if (t->buttons & BUTTON9) t->left_w[4]=None;
if (t->buttons & BUTTON2) t->right_w[0]=None;
if (t->buttons & BUTTON4) t->right_w[1]=None;
if (t->buttons & BUTTON6) t->right_w[2]=None;
if (t->buttons & BUTTON8) t->right_w[3]=None;
if (t->buttons & BUTTON10)t->right_w[4]=None;
t->nr_left_buttons = Scr.nr_left_buttons;
t->nr_right_buttons = Scr.nr_right_buttons;
for(i=0;i<Scr.nr_left_buttons;i++)
if(t->left_w[i] == None)
t->nr_left_buttons--;
for(i=0;i<Scr.nr_right_buttons;i++)
if(t->right_w[i] == None)
t->nr_right_buttons--;
t->bw = 1;
if(t->title_height > 0)
t->title_height += t->bw;
if(t->boundary_height == 0)
t->flags &= ~BORDER;
t->button_height = t->title_height- 7;
}
/****************************************************************************
*
* Checks the function described in menuItem mi, and sees if it
* is an allowed function for window Tmp_Win,
* according to the motif way of life.
*
* This routine is used to determine whether or not to grey out menu items.
*
****************************************************************************/
int check_allowed_function(MenuItem *mi)
{
/* Complex functions are a little tricky... ignore them for now */
if ((Tmp_win)&&
(!(Tmp_win->flags & DoesWmDeleteWindow))&&(mi->func == F_DELETE))
return 0;
/* Move is a funny hint. Keeps it out of the menu, but you're still allowed
* to move. */
if((mi->func == F_MOVE)&&(Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_MOVE)))
return 0;
if((mi->func == F_RESIZE)&&(Tmp_win)&&
(!(Tmp_win->functions & MWM_FUNC_RESIZE)))
return 0;
if((mi->func == F_ICONIFY)&&(Tmp_win)&&
(!(Tmp_win->flags & ICONIFIED))&&
(!(Tmp_win->functions & MWM_FUNC_MINIMIZE)))
return 0;
if((mi->func == F_MAXIMIZE)&&(Tmp_win)&&
(!(Tmp_win->functions & MWM_FUNC_MAXIMIZE)))
return 0;
if((mi->func == F_SHADE)&&(Tmp_win)&&
(!(Tmp_win->functions & MWM_FUNC_MAXIMIZE)))
return 0;
if((mi->func == F_DELETE)&&(Tmp_win)&&
(!(Tmp_win->functions & MWM_FUNC_CLOSE)))
return 0;
if((mi->func == F_CLOSE)&&(Tmp_win)&&
(!(Tmp_win->functions & MWM_FUNC_CLOSE)))
return 0;
if((mi->func == F_DESTROY)&&(Tmp_win)&&
(!(Tmp_win->functions & MWM_FUNC_CLOSE)))
return 0;
if(mi->func == F_FUNCTION)
{
/* Hard part! What to do now? */
/* Hate to do it, but for lack of a better idea,
* check based on the menu entry name */
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_MOVE))&&
(mystrncasecmp(mi->item,MOVE_STRING,strlen(MOVE_STRING))==0))
return 0;
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_RESIZE))&&
(mystrncasecmp(mi->item,RESIZE_STRING1,strlen(RESIZE_STRING1))==0))
return 0;
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_RESIZE))&&
(mystrncasecmp(mi->item,RESIZE_STRING2,strlen(RESIZE_STRING2))==0))
return 0;
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_MINIMIZE))&&
(!(Tmp_win->flags & ICONIFIED))&&
(mystrncasecmp(mi->item,MINIMIZE_STRING,strlen(MINIMIZE_STRING))==0))
return 0;
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_MINIMIZE))&&
(mystrncasecmp(mi->item,MINIMIZE_STRING2,strlen(MINIMIZE_STRING2))==0))
return 0;
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_MAXIMIZE))&&
(mystrncasecmp(mi->item,MAXIMIZE_STRING,strlen(MAXIMIZE_STRING))==0))
return 0;
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_CLOSE))&&
(mystrncasecmp(mi->item,CLOSE_STRING1,strlen(CLOSE_STRING1))==0))
return 0;
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_CLOSE))&&
(mystrncasecmp(mi->item,CLOSE_STRING2,strlen(CLOSE_STRING2))==0))
return 0;
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_CLOSE))&&
(mystrncasecmp(mi->item,CLOSE_STRING3,strlen(CLOSE_STRING3))==0))
return 0;
if((Tmp_win)&&(!(Tmp_win->functions & MWM_FUNC_CLOSE))&&
(mystrncasecmp(mi->item,CLOSE_STRING4,strlen(CLOSE_STRING4))==0))
return 0;
}
return 1;
}
/****************************************************************************
*
* Checks the function "function", and sees if it
* is an allowed function for window t, according to the motif way of life.
* This routine is used to decide if we should refuse to perform a function.
*
****************************************************************************/
int check_allowed_function2(int function, ASWindow *t)
{
/*
if(Scr.flags & MWMHintOverride)
return 1;
*/
if ((t)&&(!(t->flags & DoesWmDeleteWindow))&&(function == F_DELETE))
return 0;
if((function == F_RESIZE)&&(t)&&
(!(t->functions & MWM_FUNC_RESIZE)))
return 0;
if((function == F_ICONIFY)&&(t)&&
(!(t->flags & ICONIFIED))&&
(!(t->functions & MWM_FUNC_MINIMIZE)))
return 0;
if((function == F_MAXIMIZE)&&(t)&&
(!(t->functions & MWM_FUNC_MAXIMIZE)))
return 0;
if((function == F_SHADE)&&(t)&&
(!(t->functions & MWM_FUNC_MAXIMIZE)))
return 0;
if((function == F_DELETE)&&(t)&&
(!(t->functions & MWM_FUNC_CLOSE)))
return 0;
if((function == F_DESTROY)&&(t)&&
(!(t->functions & MWM_FUNC_CLOSE)))
return 0;
return 1;
}
#ifdef ENABLE_TEXTURE
/***************************************************
*
* Parse and fill color configuration
*
* Returns 1 for success, 0 for syntax error
***************************************************/
int ParseColor(char *input, int from[3], int to[3])
{
char *sfrom, *sto;
XColor color;
if (!input)
return 0;
sfrom=malloc(strlen(input));
sto=malloc(strlen(input));
sscanf(input, "%s %s", sfrom, sto);
if (XParseColor(dpy, DefaultColormap(dpy, Scr.screen), sfrom, &color)) {
from[0] = color.red;
from[1] = color.green;
from[2] = color.blue;
} else {
return 0;
}
if (XParseColor(dpy, DefaultColormap(dpy, Scr.screen), sto, &color)) {
to[0] = color.red;
to[1] = color.green;
to[2] = color.blue;
} else {
return 0;
}
free(sfrom);
free(sto);
return 1;
}
/**********************************************************************
*
* Initializes information for background texture rendering.
* Set's colors for gradient if defined or default if not.
* Set's the default number of colors to be used too.
*
**********************************************************************/
#define XCOL(v) ((v)*(65535/256))
void InitTextureData(TextureInfo *info, char *title, char *utitle,
char *mtitle, char *item, char *sticky, char *text)
{
char *sfrom, *sto;
XColor color;
if (!title) {
info->Tfrom[0] = XCOL(0x10);
info->Tfrom[1] = XCOL(0x10);
info->Tfrom[2] = XCOL(0x30);
info->Tto[0] = XCOL(0x30);
info->Tto[1] = XCOL(0x30);
info->Tto[2] = XCOL(0x80);
} else if (!ParseColor(title, info->Tfrom, info->Tto)) {
afterstep_err("Invalid TitleTextureColor %s\n",title,NULL,NULL);
}
if (!item) {
info->Ifrom[0] = XCOL(0x86);
info->Ifrom[1] = XCOL(0x86);
info->Ifrom[2] = XCOL(0x8a);
info->Ito[0] = XCOL(0xc0);
info->Ito[1] = XCOL(0xb8);
info->Ito[2] = XCOL(0xc3);
/*
info->Ifrom[0] = XCOL(0xd0);
info->Ifrom[1] = XCOL(0xd0);
info->Ifrom[2] = XCOL(0xd0);
info->Ito[0] = XCOL(0x60);
info->Ito[1] = XCOL(0x60);
info->Ito[2] = XCOL(0x60);
*/
} else if (!ParseColor(item, info->Ifrom, info->Ito)) {
afterstep_err("Invalid MenuTextureColor %s\n", item,NULL,NULL);
}
if (!mtitle) {
info->Mfrom[0] = XCOL(0x10);
info->Mfrom[1] = XCOL(0x10);
info->Mfrom[2] = XCOL(0x30);
info->Mto[0] = XCOL(0x30);
info->Mto[1] = XCOL(0x30);
info->Mto[2] = XCOL(0x80);
} else if (!ParseColor(mtitle, info->Mfrom, info->Mto)) {
if (mtitle) {
afterstep_err("Invalid MTitleTextureColor %s\n", mtitle,NULL,NULL);
}
}
if (!utitle) {
info->Ufrom[0] = XCOL(0x86);
info->Ufrom[1] = XCOL(0x86);
info->Ufrom[2] = XCOL(0x8a);
info->Uto[0] = XCOL(0xc0);
info->Uto[1] = XCOL(0xb8);
info->Uto[2] = XCOL(0xc3);
} else if (!ParseColor(utitle, info->Ufrom, info->Uto)) {
if (utitle) {
afterstep_err("Invalid UTitleTextureColor %s\n", utitle,NULL,NULL);
}
}
if (!sticky) {
info->Sfrom[0] = XCOL(0x30);
info->Sfrom[1] = XCOL(0x10);
info->Sfrom[2] = XCOL(0x10);
info->Sto[0] = XCOL(0x90);
info->Sto[1] = XCOL(0x40);
info->Sto[2] = XCOL(0x40);
} else if (!ParseColor(sticky, info->Sfrom, info->Sto)) {
afterstep_err("Invalid STitleTextureColor %s\n",sticky,NULL,NULL);
}
if (!text) {
info->TGfrom[0] = XCOL(0xff);
info->TGfrom[1] = XCOL(0xff);
info->TGfrom[2] = XCOL(0xff);
info->TGto[0] = XCOL(0x40);
info->TGto[1] = XCOL(0x40);
info->TGto[2] = XCOL(0x40);
} else if (!ParseColor(text, info->TGfrom, info->TGto)) {
afterstep_err("Invalid TextGradientColor %s\n",text,NULL,NULL);
}
}
#undef XCOL
#endif /* ENABLE_TEXTURE */
syntax highlighted by Code2HTML, v. 0.9.1