/**************************************************************************** * * 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 #include #include #include "afterstep.h" #include #include #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;ileft_w[i] == None) t->nr_left_buttons--; for(i=0;iright_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 */