dockapps/wmbutton/wmbutton.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

580 lines
17 KiB
C

/***********************************************************************
* Code is based on wmppp, wmload, wmtime, wmcp, and asbutton
* Author: Edward H. Flora <ehflora@ksu.edu>
* Ver 0 Rel 6.1 Jan 23, 2005
*
* Contributors:
* Christian 'Greek0' Aichinger <Greek0@gmx.net>
* Did some code cleanup and fixed several memory leaks.
* Ralf Horstmann <ralf.horstmann@gmx.de>
* Added ability to load pixmaps at startup,
* without having to re-compile
* Michael Cohrs <camico@users.sourceforge.net>
* Added Tool Tips, and updated graphics
* Bruno Essmann <essmann@users.sourceforge.net>)
* Creator of wmpager
* Casey Harkins <charkins@cs.wisc.edu>
* Bug fix reading config file path - 3/6/99
* Added button-presses, and other - denoted by *charkins*
* Ben Cohen <buddog@aztec.asu.edu>
* original author of wmcp (et al.)
* Thomas Nemeth <tnemeth@multimania.com>
* contributor to wmcp
* Michael Henderson <mghenderson@lanl.gov>
* Application ideas, suggestions
* Ryan ?? <pancake@mindspring.com>
* Modified wmbutton to asbutton.
* Note: asbutton is a seperate program, not associated
* with wmbutton (just as wmbutton is not associated
* with wmcp)
* Jon Bruno
* Web Page Development
* The contributors listed above are not necessarily involved with the
* development of wmbutton. I'm listing them here partially as thanks for
* helping out, catching bugs in the code, etc.
***********************************************************************/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "wmbutton.h"
#include "backdrop.xpm" /* background graphic */
#include "buttons.xpm" /* graphic of 9 buttons */
#include "mask.xbm" /* Border Graphic */
/*************** Function Prototypes ***********************************/
void redraw(void);
void getPixmaps(void);
int whichButton(int x, int y); // determine which button has been pressed
void SetWmHints();
void SetClassHints();
/***********************************************************************
* Globals.. OK.. there's too many globals.
* Feel free and fix it, if you'd like.
***********************************************************************/
Display *display;
int screen;
Window rootwin, win, iconwin;
GC gc;
int depth;
Pixel bg_pixel, fg_pixel;
struct Config_t Config;
typedef struct _XpmIcon {
Pixmap pixmap;
Pixmap mask;
XpmAttributes attributes;
} XpmIcon;
typedef struct _button_region {
int x, y;
int i, j;
} ButtonArea;
ButtonArea button_region[9];
XpmIcon template, visible, buttons;
int border = 0;
int button_pressed = -1; /* button to be drawn pressed *charkins*/
char *app_name = "wmbutton";
/***********************************************************************
* Main
***********************************************************************/
int main(int argc, char **argv)
{
XEvent report;
XGCValues xgcValues;
XTextProperty app_name_atom;
XSizeHints xsizehints;
Pixmap pixmask;
int dummy = 0;
int N = 1; /* Button number pressed to goto app # */
/* Added for Tool Tip Support */
long nTooltipShowDelay = TOOLTIP_SHOW_DELAY;
long nTooltipReshowDelay = TOOLTIP_RESHOW_DELAY;
long nTooltipTimer = -1;
long nTooltipHideTimer = -1;
long nNow;
int nTooltipButton = 0, nTooltipX = 0, nTooltipY = 0;
/* Parse Command Line Arguments */
parseargs(argc, argv);
/* Open Display */
if ((display = XOpenDisplay(Config.Display_str)) == NULL)
err_mess(FAILDISP, Config.Display_str);
screen = DefaultScreen(display);
rootwin = RootWindow(display, screen);
depth = DefaultDepth(display, screen);
bg_pixel = WhitePixel(display, screen);
fg_pixel = BlackPixel(display, screen);
xsizehints.flags = USSize | USPosition;
xsizehints.width = 64;
xsizehints.height = 64;
/* Parse Geometry string and fill in sizehints fields */
XWMGeometry(display, screen,
Config.Geometry_str,
NULL,
border,
&xsizehints,
&xsizehints.x,
&xsizehints.y,
&xsizehints.width,
&xsizehints.height,
&dummy);
if ((win = XCreateSimpleWindow(display,
rootwin,
xsizehints.x,
xsizehints.y,
xsizehints.width,
xsizehints.height,
border,
fg_pixel, bg_pixel)) == 0)
err_mess(FAILSWIN, NULL);
if ((iconwin = XCreateSimpleWindow(display,
win,
xsizehints.x,
xsizehints.y,
xsizehints.width,
xsizehints.height,
border,
fg_pixel, bg_pixel)) == 0)
err_mess(FAILICON, NULL);
/* Set up shaped windows */
/* Gives the appicon a border so you can grab and move it. */
if ((pixmask = XCreateBitmapFromData(display,
win,
mask_bits,
mask_width,
mask_height)) == 0)
err_mess(FAILXPM, NULL);
XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
/* Convert in pixmaps from .xpm includes. */
getPixmaps();
/* Interclient Communication stuff */
/* Appicons don't work with out this stuff */
SetWmHints();
SetClassHints();
XSetWMNormalHints(display, win, &xsizehints);
/* Tell window manager what the title bar name is. We never see */
/* this anyways in the WithdrawnState */
if (XStringListToTextProperty(&app_name, 1, &app_name_atom) == 0)
err_mess(FAILWNAM, app_name);
XSetWMName(display, win, &app_name_atom);
/* Create Graphic Context */
if ((gc = XCreateGC(display, win, (GCForeground | GCBackground),
&xgcValues)) == NULL)
err_mess(FAILGC, NULL);
/* XEvent Masks. We want both window to process X events */
XSelectInput(display, win,
ExposureMask |
ButtonPressMask |
ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
PointerMotionMask |
StructureNotifyMask |
LeaveWindowMask);
XSelectInput(display, iconwin,
ExposureMask |
ButtonPressMask |
ButtonReleaseMask | /* added ButtonReleaseMask *charkins*/
PointerMotionMask |
StructureNotifyMask |
LeaveWindowMask);
/* Store the 'state' of the application for restarting */
XSetCommand(display, win, argv, argc);
/* Window won't ever show up until it is mapped.. then drawn after a */
/* ConfigureNotify */
XMapWindow(display, win);
/* Initialize Tooltip Support */
initTime();
initTooltip(!Config.bTooltipDisable, Config.szTooltipFont, Config.bTooltipSwapColors);
/* X Event Loop */
while (1) {
while (XPending(display) || nTooltipTimer == -1) {
XNextEvent(display, &report);
switch (report.type) {
case Expose:
if (report.xexpose.count != 0)
break;
if (Config.Verbose)
fprintf(stdout, "Event: Expose\n");
redraw();
break;
case ConfigureNotify:
if (Config.Verbose)
fprintf(stdout, "Event: ConfigureNotify\n");
redraw();
break;
case MotionNotify:
if (hasTooltipSupport()) {
if (!hasTooltip()) {
nTooltipTimer = currentTimeMillis();
nTooltipX = report.xbutton.x;
nTooltipY = report.xbutton.y;
nTooltipButton = whichButton(report.xbutton.x, report.xbutton.y);
} else {
int nButton = whichButton(report.xbutton.x, report.xbutton.y);
if (nButton != nTooltipButton) {
hideTooltip();
nTooltipTimer = -1;
nTooltipX = report.xbutton.x;
nTooltipY = report.xbutton.y;
nTooltipButton = nButton;
showTooltip(nTooltipButton, nTooltipX, nTooltipY);
}
}
}
break;
case LeaveNotify:
if (Config.Verbose)
fprintf(stdout, "Event: LeaveNotify\n");
if (hasTooltip()) {
hideTooltip();
nTooltipHideTimer = currentTimeMillis();
}
nTooltipTimer = -1;
break;
case ButtonPress: /* draw button pressed, don't launch *charkins*/
if (hasTooltip()) {
hideTooltip();
nTooltipHideTimer = currentTimeMillis();
}
switch (report.xbutton.button) {
case Button1:
N = whichButton(report.xbutton.x, report.xbutton.y);
if ((N >= 0) && (N <= NUMB_OF_APPS)) {
button_pressed = N + LMASK;
redraw();
}
if (Config.Verbose)
fprintf(stdout, "Button 1:x=%d y=%d N=%d\n",
report.xbutton.x, report.xbutton.y, N+LMASK);
break;
case Button2:
if (!Config.mmouse) {
N = whichButton(report.xbutton.x, report.xbutton.y);
if ((N >= 0) && (N <= NUMB_OF_APPS)) {
button_pressed = N + MMASK;
redraw();
}
if (Config.Verbose)
fprintf(stdout, "Button 2:x=%d y=%d N=%d\n",
report.xbutton.x, report.xbutton.y, N+MMASK);
}
break;
case Button3:
N = whichButton(report.xbutton.x, report.xbutton.y);
if ((N >= 0) && (N <= NUMB_OF_APPS)) {
button_pressed = N + RMASK;
redraw();
}
if (Config.Verbose)
fprintf(stdout, "Button 3:x=%d y=%d N=%d\n",
report.xbutton.x, report.xbutton.y, N+RMASK);
break;
}
break;
case ButtonRelease: /* launch app here if still over button *charkins*/
switch (report.xbutton.button) {
case Button1:
N = whichButton(report.xbutton.x, report.xbutton.y);
if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
RunAppN(N + LMASK);
button_pressed = -1;
redraw();
if (Config.Verbose)
fprintf(stdout, "Button 1:x=%d y=%d N=%d\n",
report.xbutton.x, report.xbutton.y, N+LMASK);
break;
case Button2:
if (!Config.mmouse) {
N = whichButton(report.xbutton.x, report.xbutton.y);
if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
RunAppN(N + MMASK);
button_pressed = -1;
redraw();
if (Config.Verbose)
fprintf(stdout, "Button 2:x=%d y=%d N=%d\n",
report.xbutton.x, report.xbutton.y, N+MMASK);
}
break;
case Button3:
N = whichButton(report.xbutton.x, report.xbutton.y);
if ((N >= 0) && (N <= NUMB_OF_APPS) && (N == button_pressed))
RunAppN(N + RMASK);
button_pressed = -1;
redraw();
if (Config.Verbose)
fprintf(stdout, "Button 3:x=%d y=%d N=%d\n",
report.xbutton.x, report.xbutton.y, N+RMASK);
break;
}
break;
case DestroyNotify:
if (Config.Verbose)
fprintf(stdout, "Bye\n");
destroyTooltip();
XFreeGC(display, gc);
XDestroyWindow(display, win);
XDestroyWindow(display, iconwin);
XCloseDisplay(display);
exit(0);
break;
}
}
usleep(50000);
nNow = currentTimeMillis();
if (nTooltipTimer != -1 &&
((nNow > nTooltipTimer + nTooltipShowDelay) ||
(nNow < nTooltipHideTimer + nTooltipReshowDelay))) {
showTooltip(nTooltipButton, nTooltipX, nTooltipY);
nTooltipTimer = -1;
}
}
return (0);
}
/***********************************************************************/
/***********************************************************************
* redraw
*
* Map the button region coordinates.
*
* Draw the appropriate number of buttons on the 'visible' Pixmap
* using data from the 'buttons' pixmap.
*
* Then, copy the 'visible' pixmap to the two windows ( the withdrawn
* main window and the icon window which is the main window's icon image.)
***********************************************************************/
void redraw() {
int n, i, j, dest_x, dest_y, space, offset, bsize = 18;
if (Config.Verbose)
fprintf(stdout, "In Redraw()\n");
space = 0;
offset = 5;
XCopyArea(display, template.pixmap, visible.pixmap, gc, 0, 0,
template.attributes.width, template.attributes.height, 0, 0);
for (j = 0; j < 3; j++) {
for (i = 0; i < 3; i++) {
n = i + j * 3;
dest_x = i * (bsize + space) + offset + space;
dest_y = j * (bsize + space) + offset + space;
/* Define button mouse coords */
button_region[n].x = dest_x;
button_region[n].y = dest_y;
button_region[n].i = dest_x + bsize - 1;
button_region[n].j = dest_y + bsize - 1;
/* Copy button images for valid apps */
if ((n + 1) <= NUMB_OF_APPS)
XCopyArea(display, buttons.pixmap, visible.pixmap, gc,
i * bsize, j * bsize, bsize, bsize, dest_x, dest_y);
}
}
if (button_pressed > 0) { /* draw pressed button *charkins*/
if (button_pressed > RMASK)
button_pressed -= RMASK;
else if (button_pressed > MMASK)
button_pressed -= MMASK;
else if (button_pressed > LMASK)
button_pressed -= LMASK;
i = (button_pressed - 1) % 3; /* get col of button */
j = (button_pressed - 1) / 3; /* get row of button */
dest_x = i * (bsize + space) + offset + space;
dest_y = j * (bsize + space) + offset + space;
XSetForeground(display, gc, bg_pixel);
XDrawLine(display, visible.pixmap, gc,
dest_x + 1, dest_y + bsize - 1,
dest_x + bsize - 1, dest_y + bsize - 1);
XDrawLine(display, visible.pixmap, gc,
dest_x + bsize - 1, dest_y + bsize - 1,
dest_x + bsize - 1, dest_y + 1);
XSetForeground(display, gc, fg_pixel);
XDrawLine(display, visible.pixmap, gc,
dest_x, dest_y, dest_x + bsize - 2, dest_y);
XDrawLine(display, visible.pixmap, gc,
dest_x, dest_y, dest_x, dest_y + bsize - 2);
} /*charkins*/
flush_expose(win);
XCopyArea(display, visible.pixmap, win, gc, 0, 0,
visible.attributes.width, visible.attributes.height, 0, 0);
flush_expose(iconwin);
XCopyArea(display, visible.pixmap, iconwin, gc, 0, 0,
visible.attributes.width, visible.attributes.height, 0, 0);
}
/***********************************************************************/
/***********************************************************************
* whichButton
*
* Return the button that at the x,y coordinates. The button need not
* be visible ( drawn ). Return -1 if no button match.
***********************************************************************/
int whichButton(int x, int y)
{
int index;
for (index = 0; index < NUMB_OF_APPS; index++) {
if (x >= button_region[index].x &&
x <= button_region[index].i &&
y >= button_region[index].y &&
y <= button_region[index].j)
return(index + 1);
}
return -1;
}
/***********************************************************************/
/***********************************************************************
* getPixmaps
*
* Load XPM data into X Pixmaps.
*
* Pixmap template contains the untouched window backdrop image.
* Pixmap visible is the template pixmap with buttons drawn on it.
* -- what is seen by the user.
* Pixmap buttons holds the images for individual buttons that are
* later copied onto Pixmap visible.
***********************************************************************/
void getPixmaps()
{
int loaded = 0;
template.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
buttons.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
if (Config.Verbose)
fprintf(stdout, "In getPixmaps\n");
/* Template Pixmap. Never Drawn To. */
if (XpmCreatePixmapFromData(display, rootwin, backdrop_xpm,
&template.pixmap, &template.mask,
&template.attributes) != XpmSuccess)
err_mess(FAILTMPL, NULL);
/* Visible Pixmap. Copied from template Pixmap and then drawn to. */
if (XpmCreatePixmapFromData(display, rootwin, backdrop_xpm,
&visible.pixmap, &visible.mask,
&visible.attributes) != XpmSuccess)
err_mess(FAILVIS, NULL);
/* Button Pixmap. */
if (access(Config.buttonfile, R_OK) == 0) {
/* load buttons from file */
if (XpmReadFileToPixmap(display, rootwin, Config.buttonfile,
&buttons.pixmap, &buttons.mask,
&buttons.attributes) != XpmSuccess)
err_mess(FAILBUT, NULL);
else
loaded = 1;
}
if (!loaded) {
/* Use Builtin Button Pixmap. */
if (Config.Verbose)
fprintf(stdout, "Using builtin buttons pixmap\n");
if (XpmCreatePixmapFromData(display, rootwin, buttons_xpm,
&buttons.pixmap, &buttons.mask,
&buttons.attributes) != XpmSuccess)
err_mess(FAILBUT, NULL);
}
if (Config.Verbose)
fprintf(stdout, "Leaving getPixmaps\n");
}
/*********************************************************************/
void SetWmHints()
{
XWMHints *xwmhints;
xwmhints = XAllocWMHints();
xwmhints->flags = WindowGroupHint | IconWindowHint | StateHint;
xwmhints->icon_window = iconwin;
xwmhints->window_group = win;
xwmhints->initial_state = WithdrawnState;
XSetWMHints(display, win, xwmhints);
XFree(xwmhints);
xwmhints = NULL;
}
void SetClassHints()
{
XClassHint xclasshint;
xclasshint.res_name = "wmbutton";
xclasshint.res_class = "Wmbutton";
XSetClassHint(display, win, &xclasshint);
}