dockapps/wmcp/wmcp.c
2017-02-21 11:15:02 +00:00

861 lines
24 KiB
C

/***********************************************************************
* Code is stol^H^H^H^Hbased on wmppp, wmload, and wmtme
*
* Author: Ben Cohen <buddog@aztec.asu.edu>
*
* Contributors:
* Thomas Nemeth <tnemeth@multimania.com> -- Pushed button highlighting
* Craig Maloney <craig@ic.net> -- CTRL + ALT + key option
*
*
* This program is distributed under the GPL license.
*
*
* Best viewed with tab = 4 ( in vi set ts=4 )
*
***********************************************************************/
#define VERSION "Ver 1.2.8 -- May 25, 1999"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#include <X11/keysym.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "backdrop.xpm"
#include "buttons.xpm"
#include "pushed_buttons.xpm"
#include "mask.xbm"
#define NO (0)
#define YES (1)
#define MAX_X_BUT 4
#define MAX_Y_BUT 4
/***********************************************************************
* Globals.. OK.. there's too many globals.. so sue me.
***********************************************************************/
Display * display;
int screen;
Window rootwin, win, iconwin;
GC gc;
int depth;
Pixel bg_pixel, fg_pixel;
XSizeHints xsizehints;
XWMHints * xwmhints;
XClassHint xclasshint;
typedef struct _XpmIcon {
Pixmap pixmap;
Pixmap mask;
XpmAttributes attributes;
} XpmIcon;
Pixmap pixmask;
typedef struct _button_region {
int x,y;
int i,j;
} ButtonArea;
ButtonArea button_region[16];
XpmIcon template, visible, buttons, pbuttons;
unsigned int control = 0;
int numb_of_workspaces = 16; /* Number of buttons to display.
Initially set high. Changed by
-n switch or button 2or3 */
int N = 1; /* Button number pressed to goto WS */
int B = 1; /* Button number pressed to number WS's */
int alt_key_type = 1;
int border = 5;
int Verbose = 0;
char * app_name = "wmcp";
/***********************************************************************
* Function Prototypes
***********************************************************************/
void switchToWorkspaceN( int workspace );
void redraw( int xbut, int ybut );
void getPixmaps();
int whichButton( int x, int y, int xbut, int ybut );
int flush_expose(Window w);
void show_usage();
/***********************************************************************
* main
***********************************************************************/
int main( int argc, char ** argv )
{
XEvent report;
XGCValues xgcValues;
XTextProperty app_name_atom;
int dummy = 0;
int i;
int xbut = 2;
int ybut = 2;
int is_shaped = YES;
int window_state = WithdrawnState;
char Geometry_str[64] = "64x64+5+5";
char Display_str[64] = "";
/* Parse Command Line Arguments */
for ( i=1; i<argc; i++ ) {
if ( *argv[i] == '-' ) {
switch ( *(argv[i]+1) ) {
case 'v':
Verbose = 1;
break;
case 'g':
if ( ++i >= argc ) show_usage();
sscanf(argv[i], "%s", Geometry_str);
if ( Verbose ) printf("Geometry is: %s\n", Geometry_str);
break;
case 'd':
if ( ++i >= argc ) show_usage();
sscanf(argv[i], "%s", Display_str);
if ( Verbose ) printf("Display is: %s\n", Display_str);
break;
case 'n':
if ( ++i >= argc ) show_usage();
sscanf(argv[i], "%d", &numb_of_workspaces);
if ( Verbose )
printf("Numb of Workspaces: %d\n", numb_of_workspaces);
break;
case 's':
if ( ++i >= argc ) show_usage();
if ( *argv[i] == 'n' ) {
is_shaped = NO;
} else {
is_shaped = YES;
}
break;
case 'w':
if ( ++i >= argc ) show_usage();
switch ( *argv[i] ) {
case 'i':
window_state = IconicState;
break;
case 'w':
window_state = WithdrawnState;
break;
case 'n':
window_state = NormalState;
break;
}
break;
case 'x':
if ( ++i >= argc ) show_usage();
sscanf(argv[i], "%d", &xbut);
if ( xbut < 1 || xbut > MAX_X_BUT ) xbut = 3;
if ( Verbose ) printf("Num X buttons=%d\n", xbut);
break;
case 'y':
if ( ++i >= argc ) show_usage();
sscanf(argv[i], "%d", &ybut);
if ( ybut < 1 || ybut > MAX_Y_BUT ) ybut = 3;
if ( Verbose ) printf("Num Y buttons=%d\n", ybut);
break;
case 'a':
if ( ++i >= argc ) show_usage();
sscanf(argv[i], "%d", &alt_key_type);
if ( Verbose ) printf("Alt Key is: %d\n", alt_key_type);
break;
case 'c':
control=ControlMask;
if ( Verbose ) printf ("Control Key Modifier added\n");
break;
case 'h':
show_usage();
break;
}
}
}
if ( (display = XOpenDisplay(Display_str)) == NULL ) {
fprintf(stderr,"Fail: XOpenDisplay for %s\n", Display_str);
exit(-1);
}
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,
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 ) {
fprintf(stderr,"Fail: XCreateSimpleWindow\n");
exit(-1);
}
if ( (iconwin = XCreateSimpleWindow(
display,
win,
xsizehints.x,
xsizehints.y,
xsizehints.width,
xsizehints.height,
border,
fg_pixel, bg_pixel) ) == 0 ) {
fprintf(stderr,"Fail: XCreateSimpleWindow\n");
exit(-1);
}
/* Set up shaped windows */
/* Gives the appicon a border so you can grab and move it. */
if ( is_shaped == YES ) {
if ( ( pixmask = XCreateBitmapFromData(display, win,
mask_bits, mask_width, mask_height) ) == 0 ) {
fprintf(stderr,"Fail: XCreateBitmapFromData\n");
}
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 */
xwmhints = XAllocWMHints();
xwmhints->flags = WindowGroupHint | IconWindowHint | StateHint;
xwmhints->icon_window = iconwin;
xwmhints->window_group = win;
xwmhints->initial_state = window_state;
XSetWMHints( display, win, xwmhints );
xclasshint.res_name = "wmcp";
xclasshint.res_class = "WMcp";
XSetClassHint( display, win, &xclasshint );
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 ) {
fprintf(stderr,"%s: Can't set up window name\n", app_name);
exit(-1);
}
XSetWMName( display, win, &app_name_atom );
/* Create Graphic Context */
if ( (gc = XCreateGC(
display,
win,
(GCForeground | GCBackground),
&xgcValues)) == NULL ) {
fprintf(stderr,"Fail: XCreateGC\n");
exit(-1);
}
/* XEvent Masks. We want both window to process X events */
XSelectInput(
display,
win,
ExposureMask |
ButtonPressMask |
PointerMotionMask |
StructureNotifyMask );
XSelectInput(
display,
iconwin,
ExposureMask |
ButtonPressMask |
PointerMotionMask |
StructureNotifyMask );
/* 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 );
/* X Event Loop */
while (1) {
XNextEvent(display, &report );
switch (report.type) {
case Expose:
if (report.xexpose.count != 0) {
break;
}
if ( Verbose ) fprintf(stdout,"Event: Expose\n");
redraw( xbut, ybut );
break;
case ConfigureNotify:
if ( Verbose ) fprintf(stdout,"Event: ConfigureNotify\n");
redraw( xbut, ybut );
break;
case ButtonPress:
if ( Verbose )
printf ("numb_of_workspaces=%d\n", numb_of_workspaces);
switch (report.xbutton.button) {
case Button1:
N = whichButton(report.xbutton.x, report.xbutton.y, xbut, ybut );
if ( N >= 0 && N <= numb_of_workspaces ) {
switchToWorkspaceN( N );
redraw(xbut, ybut);
}
if ( Verbose )
fprintf(stdout,"Button 1:x=%d y=%d N=%d\n",
report.xbutton.x, report.xbutton.y, N);
break;
case Button2:
case Button3:
B = whichButton(report.xbutton.x, report.xbutton.y, xbut, ybut );
if ( B >= 0 && B <= 9 ) {
numb_of_workspaces = B;
redraw(xbut, ybut);
}
if ( Verbose )
fprintf(stdout,"Button 2or3:x=%d y=%d B=%d\n",
report.xbutton.x, report.xbutton.y, B);
break;
}
break;
case DestroyNotify:
if ( Verbose )
fprintf(stdout, "Bye\n");
XFreeGC(display, gc);
XDestroyWindow(display,win);
XDestroyWindow(display,iconwin);
XCloseDisplay(display);
if ( Verbose )
fprintf(stdout, "Bye\n");
exit(0);
break;
}
}
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 xbut, int ybut )
{
int n;
int i,j;
int dest_x, dest_y; /* size of a whole button */
int step_x, step_y; /* size of half a button for corner copying */
int offset = 8; /* skip pixels past the window's border image */
int xbut_size;
int ybut_size;
xbut_size = 48 / xbut;
ybut_size = 48 / ybut;
XCopyArea( display,
template.pixmap, visible.pixmap,
gc,
0, 0,
template.attributes.width,
template.attributes.height,
0, 0 );
for ( j=0; j < ybut; j++ ) {
for ( i=0; i < xbut; i++ ) {
n = i + j * xbut;
dest_x = ( i * xbut_size ) + offset;
dest_y = ( j * ybut_size ) + offset;
step_x = 24 / xbut;
step_y = 24 / ybut;
/* Define button mouse coords */
button_region[n].x = dest_x;
button_region[n].y = dest_y;
button_region[n].i = dest_x + xbut_size - 1;
button_region[n].j = dest_y + ybut_size - 1;
/* Copy button images for valid workspaces */
if ( (n + 1) <= numb_of_workspaces ) {
/* Draw normal button */
/* Edited by Gert Beumer */
if ( (n + 1) != N ) {
/* upper left */
XCopyArea( display,
buttons.pixmap,
visible.pixmap,
gc,
0,0,
step_x, step_y,
dest_x,
dest_y);
/* lowwer left */
XCopyArea( display,
buttons.pixmap,
visible.pixmap,
gc,
0,48 - step_y,
step_x, step_y,
dest_x,
dest_y + step_y);
/* lowwer right */
XCopyArea( display,
buttons.pixmap,
visible.pixmap,
gc,
48 - step_x,48 - step_y,
step_x, step_y,
dest_x + step_x,
dest_y + step_y);
/* upper right */
XCopyArea( display,
buttons.pixmap,
visible.pixmap,
gc,
48 - step_x,0,
step_x, step_y,
dest_x + step_x,
dest_y);
/* Draw the numbers */
XCopyArea( display,
buttons.pixmap,
visible.pixmap,
gc,
n * 5,
48,
5,5,
dest_x + (48 - xbut * 5) / (2 * xbut),
dest_y + (48 - ybut * 5) / (2 * ybut));
}
/* Draw pushed button */
/* Added by Thomas Nemeth, Edited by Gert Beumer */
if ( (n + 1) == N ) {
/* draw the four parts */
/* upper left */
XCopyArea( display,
pbuttons.pixmap,
visible.pixmap,
gc,
0,0,
step_x, step_y,
dest_x,
dest_y);
/* lowwer left */
XCopyArea( display,
pbuttons.pixmap,
visible.pixmap,
gc,
0,48 - step_y,
step_x, step_y,
dest_x,
dest_y + step_y);
/* lowwer right */
XCopyArea( display,
pbuttons.pixmap,
visible.pixmap,
gc,
48 - step_x,48 - step_y,
step_x, step_y,
dest_x + step_x,
dest_y + step_y);
/* upper right */
XCopyArea( display,
pbuttons.pixmap,
visible.pixmap,
gc,
48 - step_x,0,
step_x, step_y,
dest_x + step_x,
dest_y);
/* Draw the numbers */
XCopyArea( display,
pbuttons.pixmap,
visible.pixmap,
gc,
n * 5,
48,
5,5,
dest_x + (48 - xbut * 5) / (2 * xbut),
dest_y + (48 - ybut * 5) / (2 * ybut));
}
}
}
}
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 );
if ( Verbose )
fprintf(stdout,"In Redraw()\n");
}
/***********************************************************************
* 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 xbut, int ybut )
{
int index;
for ( index=0; index< xbut*ybut; 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);
}
/***********************************************************************
* switchToWorkspaceN()
*
* Send the Synthetic Key Press event with the appropriate
* [ meta key + 1-4 key ] combo. Alt seems to usualy be Mod1Mask.
*
***********************************************************************/
void switchToWorkspaceN( int workspace ) {
XEvent sendEvent;
sendEvent.xkey.type = KeyPress;
sendEvent.xkey.window = rootwin;
sendEvent.xkey.root = rootwin;
sendEvent.xkey.subwindow = 0x0;
switch ( alt_key_type ) {
case 1:
sendEvent.xkey.state = Mod1Mask+control;
break;
case 2:
sendEvent.xkey.state = Mod2Mask+control;
break;
case 3:
sendEvent.xkey.state = Mod3Mask+control;
break;
case 4:
sendEvent.xkey.state = Mod4Mask+control;
break;
}
sendEvent.xkey.keycode = XKeysymToKeycode(display, 0x30 + workspace );
sendEvent.xkey.same_screen = True;
sendEvent.xkey.display = display;
sendEvent.xkey.send_event = False;
XSendEvent( display, rootwin, True, KeyPressMask, &sendEvent );
}
/***********************************************************************
* 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()
{
template.attributes.valuemask |=
(XpmReturnPixels | XpmReturnExtensions);
visible.attributes.valuemask |=
(XpmReturnPixels | XpmReturnExtensions);
buttons.attributes.valuemask |=
(XpmReturnPixels | XpmReturnExtensions);
/* Template Pixmap. Never Drawn To. */
if ( XpmCreatePixmapFromData( display,
rootwin,
backdrop_xpm,
&template.pixmap,
&template.mask,
&template.attributes) != XpmSuccess ) {
fprintf(stderr, "Can't Create 'template' Pixmap");
exit(1);
}
/* Visible Pixmap. Copied from template Pixmap and then drawn to. */
if ( XpmCreatePixmapFromData( display,
rootwin,
backdrop_xpm,
&visible.pixmap,
&visible.mask,
&visible.attributes) != XpmSuccess ) {
fprintf(stderr, "Can't Create 'visible' Pixmap");
exit(1);
}
/* Buttons Pixmap. */
if ( XpmCreatePixmapFromData( display,
rootwin,
buttons_xpm,
&buttons.pixmap,
&buttons.mask,
&buttons.attributes) != XpmSuccess ) {
fprintf(stderr, "Can't Create 'buttons' Pixmap");
exit(1);
}
/* Pushed Buttons Pixmap. */
if ( XpmCreatePixmapFromData( display,
rootwin,
pushed_buttons_xpm,
&pbuttons.pixmap,
&pbuttons.mask,
&pbuttons.attributes) != XpmSuccess ) {
fprintf(stderr, "Can't Create 'pbuttons' Pixmap");
exit(1);
}
}
/***********************************************************************
* flush_expose
*
* Everyone else has one of these... Can't hurt to throw it in.
*
***********************************************************************/
int flush_expose(Window w) {
XEvent dummy;
int i=0;
while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
i++;
return i;
}
/***********************************************************************
* show_usage
*
***********************************************************************/
void show_usage()
{
fprintf(stderr,"\n\
\n\
%s\n\
This software is GPL -- do as you wish with it.\n\
\n\
Origional Author:\n\
Ben Cohen <buddog@aztec.asu.edu>\n\
\n\
Contributors:\n\
Thomas Nemeth <tnemeth@multimania.com>\n\
Craig Maloney <craig@ic.net>\n\
Gert Beumer <Gert@scintilla.utwente.nl>\n\
\n\
\n\
\n\
usage: wmcp [-g geometry] [-d dpy] [-n workspaces] [-a alt key] [-v]\n\
[-c] [-w i/n/w] [-s y/n] [-x #] [-y #] [-h]\n\
\n\
\n\
-g geometry: ie: 64x64+10+10\n\
-d dpy: Display. ie: 127.0.0.1:0.0\n\
-n workspaces: How many buttons to start with.\n\
-a alt key: integer 1-4 defining ModXMask (default 1 Mod1Mask).\n\
-w i/n/w: Window State: Iconic, Normal, Withdrawn (default Withdrawn)\n\
-s y/n: Shaped window: yes or no (default y)\n\
-c Sends CTRL + ALT + Key (default only sends ALT + key)\n\
-v Verbose. 0=off, 1=on (default 0)\n\
-x Number of buttons on the x-direction (1,2,3, or 4)\n\
-y Number of buttons in the y-direction (1,2,3, or 4)\n\
-h Help. This screen.\n\
\n\
\n\
",VERSION);
exit(-1);
}
/*
KeyPress event, serial 13, synthetic NO, window 0x25,
root 0x25, subw 0x0, time 3340683384, (37,254), root:(37,254),
state 0x8, keycode 10 (keysym 0x31, 1), same_screen YES,
XLookupString gives 1 characters: "1"
KeyPress event, serial 13, synthetic YES, window 0xbffff9ac,
root 0x40009b48, subw 0x4000a670, time 2, (26460,-1352), root:(-1146,7),
state 0x7de0, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
XLookupString gives 0 characters: ""
*/