dockapps/wmbutton/wmb_libs.c
Rodolfo García Peñas (kix) cc68392ccb wmbutton: Middle button enabled by default
The mouse middle button should be enabled by default (see the help
and the manpage). This patch solves this bug.

The MIDMOUSE definition is removed because the value of MIDMOUSE
changes the middle button behaviour. Now, the middle button always works,
except if the user uses the -m argument.

Now the manpage and the help show the same info.
2012-08-21 20:52:12 +01:00

692 lines
19 KiB
C

/* wmb_libs.c - Edward H. Flora - ehf_dockapps@cox.net */
/* Last Modified: 4/3/04 */
/*
* These functions are designed to work with wmbutton.
*/
/* PORTABILITY:
******************
* Coded in ANSI C, using ANSI prototypes.
*/
/****** Include Files *************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wmbutton.h"
/****** ToolTip Globals ***********************************************/
static struct timeval _tStart;
extern struct Config_t Config;
int _bTooltip = 0;
XFontStruct* _fTooltip;
int _nFontHeight, _nFontY;
int _nScreenWidth, _nScreenHeight;
GC _gcMono= 0;
Window _wTooltip;
/****** Parse Command Line ********************************************/
void parseargs(int argc, char **argv) {
int current;
char *Home = getenv("HOME");
while (-1 != (current = getopt(argc, argv, "vhnmsF:b:g:d:f:"))) {
switch (current) {
case 'v':
Config.Verbose = 1;
break;
case '?':
case 'h':
show_usage();
break;
case 'm':
Config.mmouse = 1;
break;
case 'n':
Config.bTooltipDisable = 1;
break;
case 's':
Config.bTooltipSwapColors = 1;
break;
case 'g':
Config.Geometry_str = strdup(optarg);
break;
case 'd':
Config.Display_str = strdup(optarg);
break;
case 'f':
Config.configfile = strdup(optarg);
break;
case 'F':
Config.szTooltipFont = strdup(optarg);
break;
case 'b':
Config.buttonfile = strdup(optarg);
break;
}
}
if (!Config.configfile) {
if (Home != NULL) {
Config.configfile = malloc(
strlen(Home) + strlen(CONFFILENAME) + 1);
sprintf(Config.configfile, "%s%s", Home, CONFFILENAME);
}
}
if (!Config.buttonfile) {
if (Home != NULL) {
Config.buttonfile = malloc(
strlen(Home) + strlen(BUTTONFILENAME) + 1);
sprintf(Config.buttonfile, "%s%s", Home, BUTTONFILENAME);
}
}
if (!Config.Geometry_str)
Config.Geometry_str = "64x64+0+0";
if (!Config.Display_str)
Config.Display_str = "";
if (!Config.szTooltipFont)
Config.szTooltipFont = TOOLTIP_FONT;
if (!Config.bTooltipDisable)
Config.bTooltipDisable = !TOOLTIP_SUPPORT;
}
/****** Show Usage Information ****************************************/
void show_usage() {
extern char *app_name;
fprintf(stderr,"\n");
fprintf(stderr,"usage: %s [-g geom] [-d dpy] [-f cfgfile] [-b btnfile] "\
"[-F <font>] [-v] [-s] [-n]\n",app_name);
fprintf(stderr,"\n");
fprintf(stderr," wmbutton version %s\n", VER_STR);
fprintf(stderr,"\n");
fprintf(stderr,"-g <geometry> Window Geometry - ie: 64x64+10+10\n");
fprintf(stderr,"-d <display> Display - ie: 127.0.0.1:0.0\n");
fprintf(stderr,"-f <filename> Full path to configuration file.\n");
fprintf(stderr,"-b <filename> Full path to button xpm.\n");
fprintf(stderr,"-F <font> Custom tooltip font (e.g. -b\\&h-lucidatypewriter-medium-*-*-*-12-*)\n");
fprintf(stderr,"-v Verbose Mode.\n");
fprintf(stderr,"-h Help. This message.\n");
fprintf(stderr,"-m Disable Middle Mouse functionality.\n");
fprintf(stderr,"-s Swap tooltip colors.\n");
fprintf(stderr,"-n Turn off tooltips.\n");
fprintf(stderr,"\n");
exit(0);
}/***********************************************************************/
/****** Error Handler Routine *****************************************/
void err_mess(int err, char *str) {
switch (err) {
case FAILDISP:
fprintf(stderr,"Fail: XOpenDisplay for %s\n", str);
exit(err);
case FAILSWIN:
fprintf(stderr,"Fail: XCreateSimpleWindow\n");
exit(err);
case FAILICON:
fprintf(stderr,"Fail: XCreateSimpleWindow\n");
exit(err);
case FAILXPM:
fprintf(stderr,"Fail: XCreateBitmapFromData\n");
break;
case FAILWNAM:
fprintf(stderr,"%s: Can't set up window name\n", str);
exit(err);
case FAILGC:
fprintf(stderr,"Fail: XCreateGC\n");
exit(err);
case FAILCONF:
fprintf(stderr, "Fail: Can't Find user or system configuration file.\n");
fprintf(stderr, "Fail: User Config: '%s'\n", str);
fprintf(stderr, "Fail: System Config: '%s'\n", CONFIGGLOBAL);
exit(err);
case FAILTMPL:
fprintf(stderr, "Fail: Can't Create 'template' Pixmap\n");
exit(err);
case FAILVIS:
fprintf(stderr, "Fail: Can't Create 'visible' Pixmap\n");
exit(err);
case FAILBUT:
fprintf(stderr, "Fail: Can't Create 'buttons' Pixmap\n");
exit(err);
default:
fprintf(stderr, "Fail: UnSpecified Error: %d\n",err);
fprintf(stderr, "Fail: %s\n",str);
exit(err);
}
}/***********************************************************************/
/***********************************************************************
* RunAppN(int app)
*
* Run the command given in the configuration file 'configfile'
***********************************************************************/
void RunAppN( int app ) {
char *cmndstr;
extern struct Config_t Config;
cmndstr = Parse(app); // Get command to pass to system
if (Config.Verbose) fprintf(stderr, "Command String: %s", cmndstr);
if (cmndstr != NULL) {
system(cmndstr); // if there's a command, run it
free(cmndstr);
}
}/***********************************************************************/
/***********************************************************************
* Parse(int app)
*
* Parses the file 'configfile' for command to execute.
***********************************************************************/
char *Parse(int app) {
FILE *fp;
char Buf[BUFFER_SIZE];
char *Ptr;
if ((fp = fopen(Config.configfile, "r")) == NULL)
if ((fp = fopen(CONFIGGLOBAL, "r")) == NULL)
err_mess(FAILCONF,Config.configfile);
while ((Ptr = fgets(Buf, BUFFER_SIZE, fp))) {
if (atoi(Buf) == app)
break;
}
fclose(fp);
if (!Ptr)
return Ptr;
Ptr = strchr(Buf, '\t'); // find first tab
if (Ptr == NULL) Ptr = strchr(Buf, ' '); // or space charater
if (Ptr == NULL) return(NULL);
Ptr++;
Ptr = strdup(Ptr);
return(Ptr);
}/**********************************************************************/
/***********************************************************************
* initTime
*
* Copyright (c) 2001 Bruno Essmann <essmann@users.sourceforge.net>
***********************************************************************/
void initTime () {
extern struct Config_t Config;
if (Config.Verbose) {
fprintf(stdout, "[ ] initializing time\n");
}
gettimeofday(&_tStart, NULL);
}/**********************************************************************/
long currentTimeMillis () {
struct timeval tNow;
struct timeval tElapsed;
gettimeofday(&tNow, NULL);
if (_tStart.tv_usec > tNow.tv_usec) {
tNow.tv_usec+= 1000000;
tNow.tv_sec--;
}
tElapsed.tv_sec= tNow.tv_sec - _tStart.tv_sec;
tElapsed.tv_usec= tNow.tv_usec - _tStart.tv_usec;
return (tElapsed.tv_sec * 1000) + (tElapsed.tv_usec / 1000);
}/**********************************************************************/
void getWindowOrigin (Window w, int* nX, int* nY) {
extern Display *display;
Window wWindow, wParent, wRoot;
Window* wChildren;
unsigned int nChildren;
unsigned int ww, wh, wb, wd;
int wx, wy;
wParent= w;
do {
wWindow= wParent;
if (!XQueryTree(display, wParent, &wRoot, &wParent, &wChildren, &nChildren))
return;
if (wChildren)
XFree(wChildren);
} while (wParent != wRoot);
if (XGetGeometry(display, wWindow, &wRoot, &wx, &wy, &ww, &wh, &wb, &wd)) {
if (nX) {
*nX= wx;
}
if (nY) {
*nY= wy;
}
}
}/**********************************************************************/
/***********************************************************************
* getButtonLocation
*
* compute location for each button's tooltip (not perfect)
***********************************************************************/
void getButtonLocation (int nButton, int* nLocationX, int* nLocationY) {
*nLocationX = 0;
*nLocationY = 8;
while (nButton > BUTTON_COLS) {
*nLocationY += BUTTON_SIZE;
nButton -= BUTTON_COLS;
}
while (nButton > 0) {
*nLocationX += BUTTON_SIZE - 1;
nButton--;
}
}/**********************************************************************/
/* SkipWord & SkipSpaces: utility functions for getNicenedString */
char *SkipWord(char *Text) {
char *Result = Text;
while ((*Result != ' ')&&(*Result != '\t')&&
(*Result != '\n')&&(*Result != 0x00))
Result++;
return Result;
}
char *SkipSpaces(char *Text) {
char *Result = Text;
while ((*Result == ' ')||(*Result == '\t')||(*Result == '\n'))
Result++;
return Result;
}
/***********************************************************************
* getNicenedString
*
* nicen the parsed command from the .wmbutton config file
* - cut if too long
* - remove parameters, whitespace and the '&'...
***********************************************************************/
char* getNicenedString (char *old, int andAddSeparator) {
char *WorkStr;
char *WorkStrEnd;
char *StartPtr;
char *EndPtr;
char *RetStr;
if (!old) {
if (andAddSeparator)
return strdup("-- | ");
else
return strdup("--");
}
RetStr = malloc(strlen(old) + 3 + 1); // 3 for Seperator
*RetStr = 0x00;
WorkStr = strdup(old);
WorkStrEnd = strchr(WorkStr, 0x00);
StartPtr = WorkStr;
while(StartPtr < WorkStrEnd) {
StartPtr = SkipSpaces(StartPtr);
EndPtr = SkipWord(StartPtr);
*EndPtr = 0x00;
if ((*StartPtr == '&')||(*StartPtr == '-'))
break;
strcat(RetStr, StartPtr);
strcat(RetStr, " ");
StartPtr = EndPtr+1;
}
free(WorkStr);
if (andAddSeparator) {
strcat(RetStr, "| ");
}
return RetStr;
}
/***********************************************************************
* getButtonAppNames
*
* returns the 1..3 application names / commands to be shown in tooltip
***********************************************************************/
char* getButtonAppNames (int nButton) {
char *str = NULL;
char *tmp1,*tmp2;
if (!( nButton < 0 || nButton > 9 )) {
// FIXME: _Might_ overflow, but it's unlikely.
// Perhaps one should fix this sometime ;)
str = (char*) calloc (sizeof(char), BUFFER_SIZE);
tmp1 = Parse(nButton + LMASK);
tmp2 = getNicenedString(tmp1, 1);
strcat(str, tmp2);
free(tmp1);
free(tmp2);
tmp1 = Parse(nButton + MMASK);
tmp2 = getNicenedString(tmp1, 1);
strcat(str, tmp2);
free(tmp1);
free(tmp2);
tmp1 = Parse(nButton + RMASK);
tmp2 = getNicenedString(tmp1, 0);
strcat(str, tmp2);
free(tmp1);
free(tmp2);
}
return(str);
}/**********************************************************************/
int hasTooltipSupport () {
return !Config.bTooltipDisable;
}/**********************************************************************/
void showTooltip (int nButton, int nMouseX, int nMouseY) {
Pixmap pixmap, mask;
int nMainWinX, nMainWinY;
int nButtonX = 0, nButtonY = 0, nButtonWidth = 0, nButtonHeight = 0;
int nTextY, nX, nY, nWidth, nHeight, nSide;
char* szText;
extern struct Config_t Config;
extern Window iconwin;
extern Pixel bg_pixel, fg_pixel;
extern Display *display;
extern GC gc;
if (Config.bTooltipDisable || nButton == -1) {
return;
}
if (_bTooltip) {
hideTooltip();
}
if (Config.Verbose) {
fprintf(stdout, "[%8ld] showing tooltip for button %d at %d, %d\n",
currentTimeMillis(),
nButton, nMouseX, nMouseY);
}
szText = getButtonAppNames(nButton);
if(!szText)
return;
_bTooltip= 1;
nWidth= XTextWidth(_fTooltip, szText, strlen(szText)) + 16;
nHeight= _nFontHeight + 4;
if (nHeight < 16) {
nHeight= 16;
}
if (nWidth < nHeight) {
nWidth= nHeight;
}
if (Config.Verbose) {
fprintf(stdout, "[%8ld] tooltip size: %d, %d\n",
currentTimeMillis(), nWidth, nHeight);
}
getWindowOrigin(iconwin, &nMainWinX, &nMainWinY);
getButtonLocation(nButton, &nButtonX, &nButtonY);
nButtonX+= nMainWinX;
nButtonY+= nMainWinY;
nButtonWidth = BUTTON_SIZE;
nButtonHeight = BUTTON_SIZE;
if (nButtonX + nWidth > _nScreenWidth) {
nSide= TOOLTIP_RIGHT;
nX= nButtonX - nWidth + nButtonWidth / 2;
if (nX < 0) {
nX= 0;
}
} else {
nSide= TOOLTIP_LEFT;
nX= nButtonX + nButtonWidth / 2;
}
if (nX + nWidth > _nScreenWidth) {
nX= _nScreenWidth - nWidth;
}
if (nButtonY - (nHeight + TOOLTIP_SPACE) < 0) {
nSide|= TOOLTIP_TOP;
nY= nButtonY + nButtonHeight - 1;
nTextY= TOOLTIP_SPACE;
} else {
nSide|= TOOLTIP_BOTTOM;
nY= nButtonY - (nHeight + TOOLTIP_SPACE);
nTextY= 0;
}
pixmap= createTooltipPixmap(nWidth, nHeight, nSide, &mask);
XSetForeground(display, gc, Config.bTooltipSwapColors ? fg_pixel : bg_pixel);
XSetFont(display, gc, _fTooltip->fid);
XDrawString(display, pixmap, gc,
8, nTextY + (nHeight - _nFontHeight) / 2 + _nFontY,
szText, strlen(szText));
XSetWindowBackgroundPixmap(display, _wTooltip, pixmap);
XResizeWindow(display, _wTooltip, nWidth, nHeight + TOOLTIP_SPACE);
XShapeCombineMask(display, _wTooltip, ShapeBounding, 0, 0, mask, ShapeSet);
XFreePixmap(display, mask);
XMoveWindow(display, _wTooltip, nX, nY);
XMapRaised(display, _wTooltip);
XFreePixmap(display, pixmap);
free(szText);
}/**********************************************************************/
void hideTooltip () {
extern struct Config_t Config;
extern Display *display;
if (Config.bTooltipDisable) {
return;
}
if (_bTooltip) {
if (Config.Verbose) {
fprintf(stdout, "[%8ld] hiding tooltip\n", currentTimeMillis());
}
XUnmapWindow(display, _wTooltip);
_bTooltip= 0;
}
}/**********************************************************************/
int hasTooltip () {
if (Config.bTooltipDisable) {
return 0;
}
return _bTooltip;
}/**********************************************************************/
void initTooltip () {
XSetWindowAttributes attribs;
unsigned long vmask;
extern Display *display;
extern char *app_name;
extern int screen;
extern Window rootwin, win;
if (Config.bTooltipDisable) {
if (Config.Verbose) {
fprintf(stdout, "[%8ld] initializing tooltips (disabled)\n",
currentTimeMillis());
}
return;
}
if (Config.Verbose) {
fprintf(stdout, "[%8ld] initializing tooltips\n", currentTimeMillis());
}
_fTooltip= XLoadQueryFont(display, Config.szTooltipFont);
if (!_fTooltip) {
fprintf(stderr, "%s: couldn't allocate font '%s'.\n", app_name, Config.szTooltipFont);
if (!strcmp(Config.szTooltipFont, TOOLTIP_FONT))
fprintf(stderr, "%s: Use option -F <font>\n", app_name);
exit(-1);
}
_nFontHeight= _fTooltip->ascent + _fTooltip->descent;
_nFontY= _fTooltip->ascent;
_nScreenWidth= WidthOfScreen(ScreenOfDisplay(display, screen));
_nScreenHeight= HeightOfScreen(ScreenOfDisplay(display, screen));
if (Config.Verbose) {
fprintf(stdout, "[%8ld] configuring tooltip font:\n" \
"[%8ld] - '%s'\n" \
"[%8ld] - font-height= %d, font-ascent= %d\n" \
"[%8ld] configuring screen size: %dx%d\n",
currentTimeMillis(),
currentTimeMillis(), Config.szTooltipFont,
currentTimeMillis(), _nFontHeight, _nFontY,
currentTimeMillis(), _nScreenWidth, _nScreenHeight );
}
vmask= CWSaveUnder | CWOverrideRedirect | CWBorderPixel;
attribs.save_under= True;
attribs.override_redirect= True;
attribs.border_pixel= 0;
_wTooltip= XCreateWindow(display, rootwin, 1, 1, 10, 10, 1,
CopyFromParent, CopyFromParent,
CopyFromParent, vmask, &attribs);
if (win == 0) {
fprintf(stderr, "Cannot create tooltip window.\n");
exit(-1);
}
}/**********************************************************************/
void destroyTooltip () {
extern Display *display;
if (Config.bTooltipDisable) {
return;
}
if (_gcMono) {
XFreeGC(display, _gcMono);
_gcMono= 0;
}
XDestroyWindow(display, _wTooltip);
}/**********************************************************************/
void drawTooltipBalloon (Pixmap pix, GC gc, int x, int y, int w, int h, int side) {
extern Display *display;
int rad = h*3/10;
XPoint pt[3];
XFillArc(display, pix, gc, x, y, rad, rad, 90*64, 90*64);
XFillArc(display, pix, gc, x, y+h-1-rad, rad, rad, 180*64, 90*64);
XFillArc(display, pix, gc, x+w-1-rad, y, rad, rad, 0*64, 90*64);
XFillArc(display, pix, gc, x+w-1-rad, y+h-1-rad, rad, rad, 270*64, 90*64);
XFillRectangle(display, pix, gc, x, y+rad/2, w, h-rad);
XFillRectangle(display, pix, gc, x+rad/2, y, w-rad, h);
if (side & TOOLTIP_BOTTOM) {
pt[0].y = y+h-1;
pt[1].y = y+h-1+TOOLTIP_SPACE;
pt[2].y = y+h-1;
} else {
pt[0].y = y;
pt[1].y = y-TOOLTIP_SPACE;
pt[2].y = y;
}
if (side & TOOLTIP_RIGHT) {
pt[0].x = x+w-h+2*h/16;
pt[1].x = x+w-h+11*h/16;
pt[2].x = x+w-h+7*h/16;
} else {
pt[0].x = x+h-2*h/16;
pt[1].x = x+h-11*h/16;
pt[2].x = x+h-7*h/16;
}
XFillPolygon(display, pix, gc, pt, 3, Convex, CoordModeOrigin);
}/**********************************************************************/
Pixmap createTooltipPixmap (int width, int height, int side, Pixmap *mask) {
extern Display *display;
extern GC gc;
extern Pixel bg_pixel, fg_pixel;
extern int depth;
extern Window rootwin;
Pixmap bitmap;
Pixmap pixmap;
int x, y;
bitmap = XCreatePixmap(display, rootwin,
width+TOOLTIP_SPACE, height+TOOLTIP_SPACE, 1);
if (!_gcMono) {
_gcMono= XCreateGC(display, bitmap, 0, NULL);
}
XSetForeground(display, _gcMono, 0);
XFillRectangle(display, bitmap, _gcMono, 0, 0,
width+TOOLTIP_SPACE, height+TOOLTIP_SPACE);
pixmap = XCreatePixmap(display, rootwin,
width+TOOLTIP_SPACE, height+TOOLTIP_SPACE, depth);
XSetForeground(display, gc, Config.bTooltipSwapColors ? fg_pixel : bg_pixel);
XFillRectangle(display, pixmap, gc, 0, 0,
width+TOOLTIP_SPACE, height+TOOLTIP_SPACE);
if (side & TOOLTIP_BOTTOM) {
y = 0;
} else {
y = TOOLTIP_SPACE;
}
x = 0;
XSetForeground(display, _gcMono, 1);
drawTooltipBalloon(bitmap, _gcMono, x, y, width, height, side);
XSetForeground(display, gc, Config.bTooltipSwapColors ? bg_pixel : fg_pixel);
drawTooltipBalloon(pixmap, gc, x+1, y+1, width-2, height-2, side);
*mask = bitmap;
return pixmap;
}/***********************************************************************/
/***********************************************************************
* flush_expose
*
* Everyone else has one of these... Can't hurt to throw it in.
***********************************************************************/
int flush_expose(Window w) {
extern Display *display;
XEvent dummy;
int i=0;
while (XCheckTypedWindowEvent(display, w, Expose, &dummy)) i++;
return(i);
}/***********************************************************************/