mirror of
https://github.com/gryf/wmdocklib.git
synced 2025-12-18 20:10:23 +01:00
1569327 release 1.1 is broken
cleaning up more things. MANIFEST.in includes ll readmes, wmdocklib correctly populated.
This commit is contained in:
8
MANIFEST
8
MANIFEST
@@ -1,6 +1,8 @@
|
||||
README.txt
|
||||
setup.py
|
||||
examples/README
|
||||
examples/pywmdatetime.py
|
||||
examples/pywmgeneric.py
|
||||
examples/pywmhdmon.py
|
||||
examples/pywmseti.py
|
||||
examples/pywmsysmon.py
|
||||
@@ -8,12 +10,8 @@ examples/sample.pywmdatetimerc
|
||||
examples/sample.pywmgenericrc
|
||||
examples/sample.pywmhdmonrc
|
||||
examples/sample.pywmsetirc
|
||||
examples/setup.py
|
||||
pywmgeneral/__init__.py
|
||||
pywmgeneral/pywmhelpers.py
|
||||
pywmgeneral/setup.py
|
||||
wmdocklib/README
|
||||
wmdocklib/__init__.py
|
||||
wmdocklib/pywmgeneral.c
|
||||
wmdocklib/pywmgeneral.h
|
||||
wmdocklib/pywmgeneric.py
|
||||
wmdocklib/pywmhelpers.py
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
include *.txt
|
||||
include */*.py */*.c */*.h */sample.pywm*rc
|
||||
include */*.py */*.c */*.h */sample.pywm*rc */README
|
||||
|
||||
97
examples/README
Normal file
97
examples/README
Normal file
@@ -0,0 +1,97 @@
|
||||
[Pywmdatetime]
|
||||
Pywmdatetime is a WindowMaker dockapp for displaying time, date and
|
||||
some other information. The colors and formats are easy to configure
|
||||
through the configuration file or as command line arguments. Invoke
|
||||
the program with --help or see the sample rc-file for more information.
|
||||
|
||||
[Pywmgeneric]
|
||||
Pywmgeneric is a dockapp with five entrys that display the first line of
|
||||
output from an external program, the returned string from an python
|
||||
method or an static string. Three mouse actions can be associated with
|
||||
each displayed entry.
|
||||
|
||||
[Pywmgeneric -- DETAILED]
|
||||
Five different entries can be defined in pywmgeneric. Every entry can
|
||||
have an action, an update_delay and up to three mouse actions associated
|
||||
with it. Some additional options are also available.
|
||||
|
||||
The associated action of an entry is executed with update_delay time
|
||||
between executions. The output from the action is stored. If no special
|
||||
display options are defined, the application will display the first line
|
||||
of output from the action. If it does not fit in the window, it will
|
||||
slowly scroll in the window. Clicking with the mouse on the text invokes
|
||||
one of the mouse actions, depending on which button was pressed. The
|
||||
action can be to execute an external program, to run a python method or
|
||||
to update the text through performing the action associated with the
|
||||
entry. The mouse actions can retreive the text genererated by the timed
|
||||
action.
|
||||
|
||||
Python methods that should be executed as actions should be defined in
|
||||
the class UserMethods. Look in pywmgeneric.py, near the top, for this
|
||||
class and the documentation of how these methods should be defined.
|
||||
Note that the methods allready there only are samples and will probably
|
||||
not work on your system.
|
||||
|
||||
Other options in the configuration file include:
|
||||
scroll = yes|no - en-/disable scrolling of the text when it doesn't fit
|
||||
display = <text> - display a static string instead of the first line of
|
||||
the action-generated output.
|
||||
|
||||
See the sample configuration file for examples and more information.
|
||||
Note that this file is only for reference, it is the one I use. Things
|
||||
will probably not work on your system if you do not change it.
|
||||
|
||||
[Pywmgeneric -- USES]
|
||||
This program is very generic (hence the name ;) ), the uses are many
|
||||
since it is highly configurable.
|
||||
|
||||
I use it for displaying my cpu and system temperatures. I just defined
|
||||
methods for reading two files in the /proc filesystem on my system.
|
||||
|
||||
I also use it for fetching headlines from a newspaper, displaying the
|
||||
first headline fetched. If I click with my left button, all headlines
|
||||
will appear in an xmessage. If I rightclick the headlines along with
|
||||
summaries are displayed, and if I click with my middle button mozilla
|
||||
will fire up showing the newspaper's website.
|
||||
|
||||
I have an external program which displays what's currently on tv,
|
||||
ideal for use with this program I thought! I modified it a bit so
|
||||
it printed a summary line at the top, and voila I have all
|
||||
currently running tv programs scrolling by in an dockapp. And clicking
|
||||
on it shows me the details.
|
||||
|
||||
You could use it as an application launcher, just display the name of
|
||||
the applications and associate mouse actions to lauch them. The
|
||||
xterm-entry in the sample shows this.
|
||||
|
||||
You could probably come up with much more than this!
|
||||
|
||||
[pywmhdmon]
|
||||
pywmhdmon is a WindowMaker dockapp that displays the available space on
|
||||
up to four of your filesystems. It also contains a bar showing the
|
||||
current HD activity. It currently only works on system which has a
|
||||
/proc/stat like file. The application is easy to configure, invoke it
|
||||
with --help or see the sample rc-file for more information.
|
||||
|
||||
[pywmhdmon -- BUGS]
|
||||
The activity bar does not work with the proc filesystem that comes with
|
||||
the 2.6 kernels. It is just a matter of rewriting the app to parse the
|
||||
new format, but I'm low on time personally.
|
||||
|
||||
[Pywmseti]
|
||||
Pywmseti is an WindowMaker dockapp for monitoring your seti@home progress.
|
||||
The application displays how many workunits you have done and the progress
|
||||
on the current one. You start/stop the seti@home process by simply clicking
|
||||
anywhere in the application. It also displays the time spent on the workunit
|
||||
(or since you started the program if you restart it in the middle of a
|
||||
workunit). Invoke the program with --help or see the sample rc-file for
|
||||
more information about customization.
|
||||
|
||||
[pywmsysmon]
|
||||
pywmsysmon is a WindowMaker dockapp that displays your cpu and memory
|
||||
usages. The upper graph shows your cpu usage history and the lower
|
||||
"progress bar" shows your current memory usage excluding cached and
|
||||
buffered data. This program currently only works on systems which got
|
||||
the /proc/stat and /proc/meminfo files available. Invoke the program
|
||||
with --help for information about customization.
|
||||
|
||||
596
pywmgeneric/pywmgeneral.c
Normal file
596
pywmgeneric/pywmgeneral.c
Normal file
@@ -0,0 +1,596 @@
|
||||
/* pywmgeneral.c
|
||||
*
|
||||
* Python bindings to some of the most important functions in the widely used
|
||||
* wmgeneral.c. Also some added functions. The rc file parser is removed since
|
||||
* Python provide better facilities for this.
|
||||
*
|
||||
* Copyright (C) 2003 Kristoffer Erlandsson
|
||||
*
|
||||
* Licensed under the GNU General Public License.
|
||||
*
|
||||
* History:
|
||||
*
|
||||
* 2003-06-24 Kristoffer Erlandsson
|
||||
* Added some additional event handling.
|
||||
*
|
||||
* 2003-06-16 Kristoffer Erlandsson
|
||||
* Added checkForMouseClick to make catching of mouse clicks available from
|
||||
* Python.
|
||||
*
|
||||
* 2003-06-14 Kristoffer Erlandsson
|
||||
* Finished support for "everything" included in wmgeneral by default.
|
||||
*
|
||||
* 2003-06-13 Kristoffer Erlandsson
|
||||
* File created made most of the pure wrapper functions and xpm inclusion.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Thanks to Martijn Pieterse for createing the original wmgeneral.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/xpm.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
|
||||
#include "pywmgeneral.h"
|
||||
|
||||
/*****************/
|
||||
/* X11 Variables */
|
||||
/*****************/
|
||||
|
||||
Window Root;
|
||||
int screen;
|
||||
int x_fd;
|
||||
int d_depth;
|
||||
XSizeHints mysizehints;
|
||||
XWMHints mywmhints;
|
||||
Pixel back_pix, fore_pix;
|
||||
char *Geometry = "";
|
||||
Window iconwin, win;
|
||||
GC NormalGC;
|
||||
XpmIcon wmgen;
|
||||
Pixmap pixmask;
|
||||
Atom deleteAtom; /* Added 2003-06-24 for graceful shutdown. */
|
||||
|
||||
/*****************************************************************************/
|
||||
/* The Python stuff */
|
||||
/*****************************************************************************/
|
||||
static char **pixmap; /* Global pixmap, we only support one of these */
|
||||
static char *maskBits; /* Global maskbits, also only 1 supported */
|
||||
|
||||
char **pyListToStrs(PyObject *l) {
|
||||
/* Convert a python list of strings to a char **. */
|
||||
int size, i;
|
||||
char **target;
|
||||
PyObject *s;
|
||||
if (!PyList_Check(l)) {
|
||||
PyErr_SetString(PyExc_TypeError, "List expected.");
|
||||
return NULL;
|
||||
}
|
||||
size = PyList_Size(l);
|
||||
target = (char **)malloc(size * sizeof(char *));
|
||||
for (i = 0; i < size; i++) {
|
||||
s = PySequence_GetItem(l, i);
|
||||
if (s == NULL)
|
||||
return NULL; /* Shouldn't happen. */
|
||||
if (!PyString_Check(s)) {
|
||||
PyErr_SetString(PyExc_TypeError, "String expected.");
|
||||
return NULL;
|
||||
}
|
||||
target[i] = PyString_AsString(s);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
pywmgeneral_includePixmap(PyObject *self, PyObject *args) {
|
||||
/* Set the global pixmap. */
|
||||
PyObject *arg;
|
||||
if (!PyArg_ParseTuple(args, "O", &arg))
|
||||
return NULL;
|
||||
if(!(pixmap = pyListToStrs(arg)))
|
||||
return NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
pywmgeneral_openXwindow(PyObject *self, PyObject *args) {
|
||||
/* This function now uses the global variable pixmap as xpm and creates the
|
||||
* xbm mask of the given height and width from this one. IOW no other xbm
|
||||
* masks are supported at the moment. This shouldn't be needed except in
|
||||
* special cases (I think...)
|
||||
*/
|
||||
int argc, width, height;
|
||||
PyObject *argvTmp;
|
||||
char **argv;
|
||||
if (!PyArg_ParseTuple(args, "iOii", &argc, &argvTmp, &width, &height))
|
||||
return NULL;
|
||||
if (!(argv = pyListToStrs(argvTmp)))
|
||||
return NULL;
|
||||
maskBits = (char *)malloc(width * height * sizeof(char));
|
||||
createXBMfromXPM(maskBits, pixmap, width, height);
|
||||
openXwindow(argc, argv, pixmap, maskBits, width, height);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pywmgeneral_redrawWindow(PyObject *self, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
RedrawWindow();
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pywmgeneral_redrawWindowXY(PyObject *self, PyObject *args) {
|
||||
int x, y;
|
||||
if (!PyArg_ParseTuple(args, "ii", &x, &y))
|
||||
return NULL;
|
||||
RedrawWindowXY(x, y);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pywmgeneral_addMouseRegion(PyObject *self, PyObject *args) {
|
||||
int index, left, top, right, bottom;
|
||||
if (!PyArg_ParseTuple(args, "iiiii", &index, &left, &top, &right, &bottom))
|
||||
return NULL;
|
||||
AddMouseRegion(index, left, top, right, bottom);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pywmgeneral_checkMouseRegion(PyObject *self, PyObject *args) {
|
||||
int x, y;
|
||||
if (!PyArg_ParseTuple(args, "ii", &x, &y))
|
||||
return NULL;
|
||||
return Py_BuildValue("i", CheckMouseRegion(x, y));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pywmgeneral_copyXPMArea(PyObject *self, PyObject *args) {
|
||||
/* x - source x, y - source y
|
||||
* sx - width, sy - height
|
||||
* dx - destination x, dy - destination y
|
||||
*
|
||||
* Variables named as in the original wmgeneral.c, don't blame me for it :)
|
||||
*/
|
||||
int x, y, sx, sy, dx, dy;
|
||||
if (!PyArg_ParseTuple(args, "iiiiii", &x, &y, &sx, &sy, &dx, &dy))
|
||||
return NULL;
|
||||
copyXPMArea(x, y, sx, sy, dx, dy);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pywmgeneral_checkForEvents(PyObject *self, PyObject *args) {
|
||||
/* If we find an event we handle, return a dicitionary containing some
|
||||
* information about it. Return None if there are no events we handle.
|
||||
* Ignore events we don't handle. Also we provide a handler for when the
|
||||
* window is exposed, redraw it.
|
||||
*/
|
||||
XEvent event;
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
while (XPending(display)) {
|
||||
XNextEvent(display, &event);
|
||||
if (event.type == Expose) {
|
||||
RedrawWindow();
|
||||
}
|
||||
else if (event.type == ClientMessage) {
|
||||
if((Atom)event.xclient.data.l[0] == deleteAtom) {
|
||||
XCloseDisplay(display);
|
||||
return Py_BuildValue("{s:s}", "type", "destroynotify");
|
||||
}
|
||||
}
|
||||
else if (event.type == DestroyNotify) {
|
||||
/* This seems to never happen, why? */
|
||||
XCloseDisplay(display);
|
||||
return Py_BuildValue("{s:s}", "type", "destroynotify");
|
||||
}
|
||||
else if (event.type == ButtonRelease) {
|
||||
return Py_BuildValue("{s:s,s:i,s:i,s:i}", "type", "buttonrelease",
|
||||
"button", event.xbutton.button, "x",
|
||||
event.xbutton.x, "y", event.xbutton.y);
|
||||
}
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyMethodDef PyWmgeneralMethods[] = {
|
||||
{"openXwindow", pywmgeneral_openXwindow, METH_VARARGS,
|
||||
"Open the X window containing everything."},
|
||||
{"includePixmap", pywmgeneral_includePixmap, METH_VARARGS,
|
||||
"Set the global pixmap that will be used as a mask and for everything else."},
|
||||
{"redrawWindow", pywmgeneral_redrawWindow, METH_VARARGS,
|
||||
"Redraw the window."},
|
||||
{"redrawWindowXY", pywmgeneral_redrawWindowXY, METH_VARARGS,
|
||||
"Redraw a give region of the window."},
|
||||
{"addMouseRegion", pywmgeneral_addMouseRegion, METH_VARARGS,
|
||||
"Add a mouse region with a given index."},
|
||||
{"checkMouseRegion", pywmgeneral_checkMouseRegion, METH_VARARGS,
|
||||
"Check if the given coordinates are in any mouse region."},
|
||||
{"copyXPMArea", pywmgeneral_copyXPMArea, METH_VARARGS,
|
||||
"Copy an area of the global XPM."},
|
||||
{"checkForEvents", pywmgeneral_checkForEvents, METH_VARARGS,
|
||||
"Check for some Xevents"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
void initpywmgeneral(void) {
|
||||
Py_InitModule("pywmgeneral", PyWmgeneralMethods);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Original C sources (With some modifications) */
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************/
|
||||
/* Mouse Regions */
|
||||
/*****************/
|
||||
|
||||
typedef struct {
|
||||
int enable;
|
||||
int top;
|
||||
int bottom;
|
||||
int left;
|
||||
int right;
|
||||
} MOUSE_REGION;
|
||||
|
||||
MOUSE_REGION mouse_region[MAX_MOUSE_REGION];
|
||||
|
||||
/***********************/
|
||||
/* Function Prototypes */
|
||||
/***********************/
|
||||
|
||||
static void GetXPM(XpmIcon *, char **);
|
||||
static Pixel GetColor(char *);
|
||||
void RedrawWindow(void);
|
||||
void AddMouseRegion(int, int, int, int, int);
|
||||
int CheckMouseRegion(int, int);
|
||||
|
||||
/*******************************************************************************\
|
||||
|* GetXPM *|
|
||||
\*******************************************************************************/
|
||||
|
||||
static void GetXPM(XpmIcon *wmgen, char *pixmap_bytes[]) {
|
||||
|
||||
XWindowAttributes attributes;
|
||||
int err;
|
||||
|
||||
/* For the colormap */
|
||||
XGetWindowAttributes(display, Root, &attributes);
|
||||
|
||||
wmgen->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
|
||||
|
||||
err = XpmCreatePixmapFromData(display, Root, pixmap_bytes, &(wmgen->pixmap),
|
||||
&(wmgen->mask), &(wmgen->attributes));
|
||||
|
||||
if (err != XpmSuccess) {
|
||||
fprintf(stderr, "Not enough free colorcells.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* GetColor *|
|
||||
\*******************************************************************************/
|
||||
|
||||
static Pixel GetColor(char *name) {
|
||||
|
||||
XColor color;
|
||||
XWindowAttributes attributes;
|
||||
|
||||
XGetWindowAttributes(display, Root, &attributes);
|
||||
|
||||
color.pixel = 0;
|
||||
if (!XParseColor(display, attributes.colormap, name, &color)) {
|
||||
fprintf(stderr, "wm.app: can't parse %s.\n", name);
|
||||
} else if (!XAllocColor(display, attributes.colormap, &color)) {
|
||||
fprintf(stderr, "wm.app: can't allocate %s.\n", name);
|
||||
}
|
||||
return color.pixel;
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* flush_expose *|
|
||||
\*******************************************************************************/
|
||||
|
||||
static int flush_expose(Window w) {
|
||||
|
||||
XEvent dummy;
|
||||
int i=0;
|
||||
|
||||
while (XCheckTypedWindowEvent(display, w, Expose, &dummy))
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* RedrawWindow *|
|
||||
\*******************************************************************************/
|
||||
|
||||
void RedrawWindow(void) {
|
||||
|
||||
flush_expose(iconwin);
|
||||
XCopyArea(display, wmgen.pixmap, iconwin, NormalGC,
|
||||
0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
|
||||
flush_expose(win);
|
||||
XCopyArea(display, wmgen.pixmap, win, NormalGC,
|
||||
0,0, wmgen.attributes.width, wmgen.attributes.height, 0,0);
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* RedrawWindowXY *|
|
||||
\*******************************************************************************/
|
||||
|
||||
void RedrawWindowXY(int x, int y) {
|
||||
|
||||
flush_expose(iconwin);
|
||||
XCopyArea(display, wmgen.pixmap, iconwin, NormalGC,
|
||||
x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
|
||||
flush_expose(win);
|
||||
XCopyArea(display, wmgen.pixmap, win, NormalGC,
|
||||
x,y, wmgen.attributes.width, wmgen.attributes.height, 0,0);
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* AddMouseRegion *|
|
||||
\*******************************************************************************/
|
||||
|
||||
void AddMouseRegion(int index, int left, int top, int right, int bottom) {
|
||||
|
||||
if (index < MAX_MOUSE_REGION) {
|
||||
mouse_region[index].enable = 1;
|
||||
mouse_region[index].top = top;
|
||||
mouse_region[index].left = left;
|
||||
mouse_region[index].bottom = bottom;
|
||||
mouse_region[index].right = right;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* CheckMouseRegion *|
|
||||
\*******************************************************************************/
|
||||
|
||||
int CheckMouseRegion(int x, int y) {
|
||||
|
||||
int i;
|
||||
int found;
|
||||
|
||||
found = 0;
|
||||
|
||||
for (i=0; i<MAX_MOUSE_REGION && !found; i++) {
|
||||
if (mouse_region[i].enable &&
|
||||
x <= mouse_region[i].right &&
|
||||
x >= mouse_region[i].left &&
|
||||
y <= mouse_region[i].bottom &&
|
||||
y >= mouse_region[i].top)
|
||||
found = 1;
|
||||
}
|
||||
if (!found) return -1;
|
||||
return (i-1);
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* createXBMfromXPM *|
|
||||
\*******************************************************************************/
|
||||
void createXBMfromXPM(char *xbm, char **xpm, int sx, int sy) {
|
||||
|
||||
int i,j,k;
|
||||
int width, height, numcol, depth;
|
||||
int zero=0;
|
||||
unsigned char bwrite;
|
||||
int bcount;
|
||||
int curpixel;
|
||||
|
||||
sscanf(*xpm, "%d %d %d %d", &width, &height, &numcol, &depth);
|
||||
|
||||
|
||||
for (k=0; k!=depth; k++)
|
||||
{
|
||||
zero <<=8;
|
||||
zero |= xpm[1][k];
|
||||
}
|
||||
|
||||
for (i=numcol+1; i < numcol+sy+1; i++) {
|
||||
bcount = 0;
|
||||
bwrite = 0;
|
||||
for (j=0; j<sx*depth; j+=depth) {
|
||||
bwrite >>= 1;
|
||||
|
||||
curpixel=0;
|
||||
for (k=0; k!=depth; k++)
|
||||
{
|
||||
curpixel <<=8;
|
||||
curpixel |= xpm[i][j+k];
|
||||
}
|
||||
|
||||
if ( curpixel != zero ) {
|
||||
bwrite += 128;
|
||||
}
|
||||
bcount++;
|
||||
if (bcount == 8) {
|
||||
*xbm = bwrite;
|
||||
xbm++;
|
||||
bcount = 0;
|
||||
bwrite = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* copyXPMArea *|
|
||||
\*******************************************************************************/
|
||||
|
||||
void copyXPMArea(int x, int y, int sx, int sy, int dx, int dy) {
|
||||
|
||||
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* copyXBMArea *|
|
||||
\*******************************************************************************/
|
||||
|
||||
void copyXBMArea(int x, int y, int sx, int sy, int dx, int dy) {
|
||||
|
||||
XCopyArea(display, wmgen.mask, wmgen.pixmap, NormalGC, x, y, sx, sy, dx, dy);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************\
|
||||
|* setMaskXY *|
|
||||
\*******************************************************************************/
|
||||
|
||||
void setMaskXY(int x, int y) {
|
||||
|
||||
XShapeCombineMask(display, win, ShapeBounding, x, y, pixmask, ShapeSet);
|
||||
XShapeCombineMask(display, iconwin, ShapeBounding, x, y, pixmask, ShapeSet);
|
||||
}
|
||||
|
||||
/*******************************************************************************\
|
||||
|* openXwindow *|
|
||||
\*******************************************************************************/
|
||||
void openXwindow(int argc, char *argv[], char *pixmap_bytes[], char *pixmask_bits, int pixmask_width, int pixmask_height) {
|
||||
|
||||
unsigned int borderwidth = 1;
|
||||
XClassHint classHint;
|
||||
char *display_name = NULL;
|
||||
char *wname = argv[0];
|
||||
XTextProperty name;
|
||||
|
||||
XGCValues gcv;
|
||||
unsigned long gcm;
|
||||
|
||||
char *geometry = NULL;
|
||||
|
||||
int dummy=0;
|
||||
int i, wx, wy;
|
||||
|
||||
/* Changed to work better with Python. Changed check in for loop to control
|
||||
* argc instead of argv.
|
||||
*/
|
||||
for (i=1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-display")) {
|
||||
display_name = argv[i+1];
|
||||
i++;
|
||||
}
|
||||
if (!strcmp(argv[i], "-geometry")) {
|
||||
geometry = argv[i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(display = XOpenDisplay(display_name))) {
|
||||
fprintf(stderr, "%s: can't open display %s\n",
|
||||
wname, XDisplayName(display_name));
|
||||
exit(1);
|
||||
}
|
||||
screen = DefaultScreen(display);
|
||||
Root = RootWindow(display, screen);
|
||||
d_depth = DefaultDepth(display, screen);
|
||||
x_fd = XConnectionNumber(display);
|
||||
|
||||
/* Convert XPM to XImage */
|
||||
GetXPM(&wmgen, pixmap_bytes);
|
||||
|
||||
/* Create a window to hold the stuff */
|
||||
mysizehints.flags = USSize | USPosition;
|
||||
mysizehints.x = 0;
|
||||
mysizehints.y = 0;
|
||||
|
||||
back_pix = GetColor("white");
|
||||
fore_pix = GetColor("black");
|
||||
|
||||
XWMGeometry(display, screen, Geometry, NULL, borderwidth, &mysizehints,
|
||||
&mysizehints.x, &mysizehints.y,&mysizehints.width,&mysizehints.height, &dummy);
|
||||
|
||||
mysizehints.width = 64;
|
||||
mysizehints.height = 64;
|
||||
|
||||
win = XCreateSimpleWindow(display, Root, mysizehints.x, mysizehints.y,
|
||||
mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
|
||||
|
||||
iconwin = XCreateSimpleWindow(display, win, mysizehints.x, mysizehints.y,
|
||||
mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix);
|
||||
|
||||
|
||||
/* Added 2003-06-24 for graceful shutdown. */
|
||||
deleteAtom = XInternAtom(display, "WM_DELETE_WINDOW", 0);
|
||||
XSetWMProtocols(display, win, &deleteAtom, 1);
|
||||
|
||||
|
||||
/* Activate hints */
|
||||
XSetWMNormalHints(display, win, &mysizehints);
|
||||
classHint.res_name = wname;
|
||||
classHint.res_class = wname;
|
||||
XSetClassHint(display, win, &classHint);
|
||||
|
||||
XSelectInput(display, win, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
|
||||
XSelectInput(display, iconwin, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
|
||||
|
||||
if (XStringListToTextProperty(&wname, 1, &name) == 0) {
|
||||
fprintf(stderr, "%s: can't allocate window name\n", wname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
XSetWMName(display, win, &name);
|
||||
|
||||
/* Create GC for drawing */
|
||||
|
||||
gcm = GCForeground | GCBackground | GCGraphicsExposures;
|
||||
gcv.foreground = fore_pix;
|
||||
gcv.background = back_pix;
|
||||
gcv.graphics_exposures = 0;
|
||||
NormalGC = XCreateGC(display, Root, gcm, &gcv);
|
||||
|
||||
/* ONLYSHAPE ON */
|
||||
|
||||
pixmask = XCreateBitmapFromData(display, win, pixmask_bits, pixmask_width, pixmask_height);
|
||||
|
||||
XShapeCombineMask(display, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
|
||||
XShapeCombineMask(display, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
|
||||
|
||||
/* ONLYSHAPE OFF */
|
||||
|
||||
mywmhints.initial_state = WithdrawnState;
|
||||
mywmhints.icon_window = iconwin;
|
||||
mywmhints.icon_x = mysizehints.x;
|
||||
mywmhints.icon_y = mysizehints.y;
|
||||
mywmhints.window_group = win;
|
||||
mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
|
||||
|
||||
XSetWMHints(display, win, &mywmhints);
|
||||
|
||||
XSetCommand(display, win, argv, argc);
|
||||
XMapWindow(display, win);
|
||||
|
||||
if (geometry) {
|
||||
if (sscanf(geometry, "+%d+%d", &wx, &wy) != 2) {
|
||||
fprintf(stderr, "Bad geometry string.\n");
|
||||
exit(1);
|
||||
}
|
||||
XMoveWindow(display, win, wx, wy);
|
||||
}
|
||||
}
|
||||
66
pywmgeneric/pywmgeneral.h
Normal file
66
pywmgeneric/pywmgeneral.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Kristoffer Erlandsson
|
||||
*
|
||||
* Licensed under the GNU General Public License.
|
||||
* Copyright (C) 2003 Kristoffer Erlandsson
|
||||
*
|
||||
* Licensed under the GNU General Public License.
|
||||
*/
|
||||
|
||||
#ifndef WMGENERAL_H_INCLUDED
|
||||
#define WMGENERAL_H_INCLUDED
|
||||
|
||||
/***********/
|
||||
/* Defines */
|
||||
/***********/
|
||||
|
||||
#define MAX_MOUSE_REGION (16)
|
||||
|
||||
/************/
|
||||
/* Typedefs */
|
||||
/************/
|
||||
|
||||
typedef struct _rckeys rckeys;
|
||||
|
||||
struct _rckeys {
|
||||
const char *label;
|
||||
char **var;
|
||||
};
|
||||
|
||||
typedef struct _rckeys2 rckeys2;
|
||||
|
||||
struct _rckeys2 {
|
||||
const char *family;
|
||||
const char *label;
|
||||
char **var;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Pixmap pixmap;
|
||||
Pixmap mask;
|
||||
XpmAttributes attributes;
|
||||
} XpmIcon;
|
||||
|
||||
/*******************/
|
||||
/* Global variable */
|
||||
/*******************/
|
||||
|
||||
Display *display;
|
||||
|
||||
/***********************/
|
||||
/* Function Prototypes */
|
||||
/***********************/
|
||||
|
||||
void AddMouseRegion(int index, int left, int top, int right, int bottom);
|
||||
int CheckMouseRegion(int x, int y);
|
||||
|
||||
void openXwindow(int argc, char *argv[], char **, char *, int, int);
|
||||
void RedrawWindow(void);
|
||||
void RedrawWindowXY(int x, int y);
|
||||
|
||||
void createXBMfromXPM(char *, char **, int, int);
|
||||
void copyXPMArea(int, int, int, int, int, int);
|
||||
void copyXBMArea(int, int, int, int, int, int);
|
||||
void setMaskXY(int, int);
|
||||
|
||||
#endif
|
||||
253
pywmgeneric/pywmhelpers.py
Normal file
253
pywmgeneric/pywmhelpers.py
Normal file
@@ -0,0 +1,253 @@
|
||||
"""pywmhelpers.py
|
||||
|
||||
Various helper functions when writing wm dockapps in Python. This module
|
||||
is way better commented than the pywmgeneral one. This is the one
|
||||
intented for use in applications. Many functions are just wrappers
|
||||
around the ones in pywmgeneral but with nicer interfaces and better
|
||||
documentation.
|
||||
|
||||
Copyright (C) 2003 Kristoffer Erlandsson
|
||||
|
||||
Licensed under the GNU General Public License
|
||||
|
||||
|
||||
Changes:
|
||||
2003-06-25 Kristoffer Erlandsson
|
||||
Updated documentation
|
||||
|
||||
2003-06-24 Kristoffer Erlandsson
|
||||
Some changes to handle the additional event handling in pywmgeneral
|
||||
|
||||
2003-06-16 Kristoffer Erlandsson
|
||||
First workingish version
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import ConfigParser
|
||||
|
||||
import pywmgeneral
|
||||
|
||||
def readConfigFile(fileName, errOut):
|
||||
"""Read the config file fileName.
|
||||
|
||||
Return a dictionary with the options and values in the DEFAULT
|
||||
section. Ignore everything else. The configuration file should not
|
||||
get so complicated so that sections are needed. errOut is the
|
||||
file-like object to which error messages will be printed.
|
||||
"""
|
||||
if not os.access(fileName, os.R_OK):
|
||||
if errOut:
|
||||
errOut.write(
|
||||
'Configuration file is not readable. Using defaults.\n')
|
||||
return {}
|
||||
cp = ConfigParser.ConfigParser()
|
||||
try:
|
||||
cp.read(fileName)
|
||||
except ConfigParser.Error, e:
|
||||
if errOut:
|
||||
errOut.write('Error in configuration file:\n')
|
||||
errOut.write(str(e) + '\nUsing defaults.')
|
||||
return {}
|
||||
defaults = cp.defaults()
|
||||
if defaults == {}:
|
||||
if errOut:
|
||||
errOut.write(
|
||||
'Missing or empty DEFAULT section in the config file.\n')
|
||||
errOut.write('Using defaults.\n')
|
||||
return defaults
|
||||
|
||||
def getCenterStartPos(s, letterWidth, areaWidth, offset):
|
||||
"""Get the x starting position if we want to paint s centred."""
|
||||
w = len(s) * letterWidth
|
||||
textArea = areaWidth - offset * 2 - 1
|
||||
return (textArea - w) / 2
|
||||
|
||||
def addChar(ch, x, y, letterWidth, letterHeight, lettersStartX, lettersStartY,
|
||||
letters, digitWidth, digitHeight, digitsStartX, digitsStartY,
|
||||
digits, xOffset, yOffset, width, height):
|
||||
"""Paint the character ch at position x, y in the window.
|
||||
|
||||
Return the (width, height) of the character painted. Raise
|
||||
ValueError if we try to paint a char not in letters or digits
|
||||
or if we get out of bounds during painting. digits is really
|
||||
just another line of chars, it's unlucky called digits everywhere
|
||||
I used it since it contained only digits in the start. However,
|
||||
now it contains various special chars too everywhere I use it. But
|
||||
the name remains in too many places so I haven't gotten to change
|
||||
it.
|
||||
"""
|
||||
chIndex = letters.find(ch.lower())
|
||||
if chIndex != -1:
|
||||
chX = lettersStartX + chIndex * letterWidth
|
||||
chY = lettersStartY
|
||||
w = letterWidth
|
||||
h = letterHeight
|
||||
else:
|
||||
chIndex = digits.find(ch)
|
||||
if chIndex != -1:
|
||||
chX = digitsStartX + chIndex * digitWidth
|
||||
chY = digitsStartY
|
||||
w = digitWidth
|
||||
h = digitHeight
|
||||
else:
|
||||
raise ValueError, "Unsupported char: '%s'" % ch
|
||||
targX = x + xOffset
|
||||
targY = y + yOffset
|
||||
if targX + w > width - xOffset or targY + h > height - yOffset\
|
||||
or targX < 0 or targY < 0:
|
||||
raise ValueError, "Out of bounds."
|
||||
pywmgeneral.copyXPMArea(chX, chY, w, h, targX, targY)
|
||||
return (w, h)
|
||||
|
||||
def addString(s, x, y, letterWidth, letterHeight, lettersStartX, lettersStartY,
|
||||
letters, digitWidth, digitHeight, digitsStartX, digitsStartY,
|
||||
digits, xOffset, yOffset, width, height):
|
||||
"""Add a string at the given x and y positions.
|
||||
|
||||
Call addChar repeatedely, so the same exception rules apply."""
|
||||
lastW = 0
|
||||
for letter in s:
|
||||
w, h = addChar(letter, x + lastW, y, letterWidth, letterHeight,
|
||||
lettersStartX, lettersStartY, letters, digitWidth,
|
||||
digitHeight, digitsStartX, digitsStartY, digits,
|
||||
xOffset, yOffset, width, height)
|
||||
lastW += w
|
||||
|
||||
def getVertSpacing(numLines, margin, height, letterHeight, yOffset):
|
||||
"""Return the optimal spacing between a number of lines.
|
||||
|
||||
margin is the space we want between the first line and the top."""
|
||||
h = height - numLines * letterHeight - yOffset * 2 - margin
|
||||
return h / (numLines - 1)
|
||||
|
||||
|
||||
def readXPM(fileName):
|
||||
"""Read the xpm in filename.
|
||||
|
||||
Return a list of strings containing the xpm. Raise IOError if we run
|
||||
into trouble when trying to read the file. This function surely
|
||||
doesn't handle all XPMs, but it handles the ones I use, so that'll
|
||||
do.
|
||||
"""
|
||||
f = file(fileName, 'r')
|
||||
lines = [l.rstrip('\n') for l in f.readlines()]
|
||||
s = ''.join(lines)
|
||||
res = []
|
||||
while 1:
|
||||
nextStrStart = s.find('"')
|
||||
if nextStrStart != -1:
|
||||
nextStrEnd = s.find('"', nextStrStart + 1)
|
||||
if nextStrEnd != -1:
|
||||
res.append(s[nextStrStart+1:nextStrEnd])
|
||||
s = s[nextStrEnd+1:]
|
||||
continue
|
||||
break
|
||||
return res
|
||||
|
||||
def setColor(xpm, name, newColor):
|
||||
"""Find the color with comment name and set this color to newColor.
|
||||
|
||||
Change the source code of an XPM represented as a list of strings.
|
||||
I'm certain that this will fail on many XPMs too, but it'll do for
|
||||
the ones I use. No check is done that the color is valid, this has
|
||||
to be done elsewhere.
|
||||
"""
|
||||
colorRE = re.compile(
|
||||
r"^(?P<letter>.).*?c (?P<color>#.*?) s (?P<comment>.*)")
|
||||
index = 1
|
||||
for line in xpm[1:]:
|
||||
m = colorRE.match(line)
|
||||
if not m is None:
|
||||
comment = m.group('comment')
|
||||
if comment == name:
|
||||
letter = m.group('letter')
|
||||
color = newColor
|
||||
xpm[index] = '%s\tc %s s %s' % (letter, color, comment)
|
||||
index += 1
|
||||
|
||||
def setDefaultPixmap(xpm):
|
||||
"""Set the pixmap of the program.
|
||||
|
||||
xpm is an XPM represented as a list of strings, possible gotten
|
||||
from readXPM(). This is what we use all the time later. The XBM
|
||||
mask is created out of the XPM. If I understand correctly how it
|
||||
works we use the upper left rectangle as mask. This is the
|
||||
simplest way to do it and is the desired behaviour in most cases.
|
||||
"""
|
||||
pywmgeneral.includePixmap(xpm)
|
||||
|
||||
def openXwindow(argv, w, h):
|
||||
"""Open the X window of given width and height.
|
||||
|
||||
The XBM mask is here created from the upper left rectangle of the
|
||||
XPM using the given width and height."""
|
||||
pywmgeneral.openXwindow(len(argv), argv, w, h)
|
||||
|
||||
def redraw():
|
||||
"""Redraw the window."""
|
||||
pywmgeneral.redrawWindow()
|
||||
|
||||
def redrawXY(x, y):
|
||||
"""Redraw a given region of the window."""
|
||||
pywmgeneral.redrawWindowXY(x, y)
|
||||
|
||||
def copyXPMArea(sourceX, sourceY, width, height, targetX, targetY):
|
||||
"""Copy an area of the global XPM."""
|
||||
if width > 0 or height > 0:
|
||||
pywmgeneral.copyXPMArea(sourceX, sourceY, width, height,
|
||||
targetX, targetY)
|
||||
|
||||
def addMouseRegion(index, left, top, right, bottom):
|
||||
"""Add a mouse region in the window."""
|
||||
pywmgeneral.addMouseRegion(index, left, top, right, bottom)
|
||||
|
||||
def checkMouseRegion(x, y):
|
||||
"""Check if x,y is in any mouse region. Return that region, otherwise -1.
|
||||
"""
|
||||
return pywmgeneral.checkMouseRegion(x, y)
|
||||
|
||||
def getEvent():
|
||||
"""Check for XEvents and return one if found.
|
||||
|
||||
Return None if we find no events. There may be events pending still
|
||||
after this function is called. If an event which we handle is found,
|
||||
return a dictionary with information about it. All dictionaries
|
||||
contain a 'type' field identifying the event. Now existing events
|
||||
with dictionary keys are:
|
||||
'buttonrelease':
|
||||
x, y, button
|
||||
'destroynotify':
|
||||
"""
|
||||
return pywmgeneral.checkForEvents()
|
||||
|
||||
def getColorCode(colorName, rgbFileName):
|
||||
"""Convert a color to rgb code usable in an xpm.
|
||||
|
||||
We use the file rgbFileName for looking up the colors. Return None
|
||||
if we find no match. The rgbFileName should be like the one found in
|
||||
/usr/lib/X11R6/rgb.txt on most sytems.
|
||||
"""
|
||||
f = file(rgbFileName, 'r')
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
for l in lines:
|
||||
if l[0] != '!':
|
||||
words = l.split()
|
||||
if len(words) > 3:
|
||||
name = ' '.join(words[3:])
|
||||
if colorName.lower() == name.lower():
|
||||
# Found the right color, get it's code
|
||||
try:
|
||||
r = int(words[0])
|
||||
g = int(words[1])
|
||||
b = int(words[2])
|
||||
except ValueError:
|
||||
continue
|
||||
rgbstr = '#' + str(hex(r))[2:].zfill(2) + \
|
||||
str(hex(g))[2:].zfill(2) + \
|
||||
str(hex(b))[2:].zfill(2)
|
||||
return rgbstr
|
||||
return None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user