482 lines
12 KiB
C
482 lines
12 KiB
C
/*
|
|
wmget - A background download manager as a Window Maker dock app
|
|
Copyright (c) 2001-2003 Aaron Trickey <aaron@amtrickey.net>
|
|
|
|
Permission is hereby granted, free of charge, to any person
|
|
obtaining a copy of this software and associated documentation files
|
|
(the "Software"), to deal in the Software without restriction,
|
|
including without limitation the rights to use, copy, modify, merge,
|
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
|
and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
********************************************************************
|
|
dockapp/da_x.c - General X11 code
|
|
|
|
This file encapsulates all the X11 interface code, such as drawing,
|
|
initialization, and selection handling.
|
|
*/
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/xpm.h>
|
|
#include <X11/extensions/shape.h>
|
|
#include <X11/Xatom.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
#include "dockapp.h"
|
|
|
|
#define DOCKAPP_EXPOSE_INTERNALS
|
|
#include "da_mouse.h"
|
|
|
|
#define SELECTION_MAX 1024
|
|
|
|
static Display *display;
|
|
|
|
/* We need to update both the ``icon'' and ``main'' windows
|
|
* simultaneously... icon for WindowMaker and main for AfterStep...
|
|
*/
|
|
static Window icon_win;
|
|
static Window main_win;
|
|
|
|
static Pixmap icon_pixmap;
|
|
|
|
static GC copy_gc;
|
|
static GC xor_gc;
|
|
|
|
|
|
/* request the X selection; when the server responds, we will get it in
|
|
* da_xfd_callback.
|
|
*/
|
|
static void da_request_selection ()
|
|
{
|
|
Atom prop;
|
|
|
|
prop = XInternAtom (display, "XSEL_DATA", False);
|
|
XConvertSelection (
|
|
display,
|
|
XA_PRIMARY, /* only use the PRIMARY selection */
|
|
XA_STRING, /* we only accept strings (the 90% case) */
|
|
prop,
|
|
icon_win,
|
|
CurrentTime);
|
|
}
|
|
|
|
static dockapp_rv_t (*da_selection_cb) (void *, const char *);
|
|
static void *da_selection_cbdata;
|
|
|
|
static dockapp_rv_t da_receive_selection (XEvent *event)
|
|
{
|
|
Atom actual_type;
|
|
int actual_format;
|
|
unsigned long actual_length;
|
|
unsigned long remaining;
|
|
unsigned char *data;
|
|
dockapp_rv_t rv;
|
|
|
|
if (event->xselection.selection != XA_PRIMARY)
|
|
return dockapp_ok;
|
|
|
|
if (event->xselection.property == None) {
|
|
fprintf (stderr, "! selection can't become string !\n");
|
|
return dockapp_ok;
|
|
}
|
|
|
|
XGetWindowProperty (
|
|
event->xselection.display,
|
|
event->xselection.requestor,
|
|
event->xselection.property,
|
|
0, /* from byte zero... */
|
|
SELECTION_MAX, /* to this many bytes */
|
|
False, /* do not delete after retrieval */
|
|
AnyPropertyType,
|
|
&actual_type, /* actual type returned */
|
|
&actual_format, /* actual format returned */
|
|
&actual_length, /* in 8, 16, or 32 bit units */
|
|
&remaining, /* unread content (always in 8 bit units!) */
|
|
&data); /* property content */
|
|
|
|
/* We do not support non-string data or incremental transfer. */
|
|
if (actual_type != XA_STRING || actual_format != 8) {
|
|
fprintf (stderr, "! selection unavailable or not of known type !\n");
|
|
|
|
if (actual_length) {
|
|
XFree (data);
|
|
}
|
|
|
|
return dockapp_ok;
|
|
}
|
|
|
|
|
|
rv = da_selection_cb (da_selection_cbdata, (const char *)data);
|
|
|
|
XFree (data);
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
dockapp_rv_t dockapp_request_selection_string (
|
|
dockapp_rv_t (*cb) (void *, const char *),
|
|
void *cbdata)
|
|
{
|
|
da_selection_cb = cb;
|
|
da_selection_cbdata = cbdata;
|
|
da_request_selection ();
|
|
|
|
return dockapp_ok;
|
|
}
|
|
|
|
|
|
static void da_redraw_icon (void)
|
|
{
|
|
XEvent event;
|
|
|
|
/* slurp up any queued Expose events */
|
|
while (XCheckTypedWindowEvent (
|
|
display,
|
|
event.xany.window,
|
|
Expose,
|
|
&event))
|
|
;
|
|
|
|
XCopyArea (
|
|
display,
|
|
icon_pixmap,
|
|
icon_win,
|
|
copy_gc,
|
|
0, 0, 64, 64, /* source coords */
|
|
0, 0); /* dest coords */
|
|
|
|
XCopyArea (
|
|
display,
|
|
icon_pixmap,
|
|
main_win,
|
|
copy_gc,
|
|
0, 0, 64, 64, /* source coords */
|
|
0, 0); /* dest coords */
|
|
}
|
|
|
|
|
|
/* this is the callback bound to the X server socket descriptor
|
|
*/
|
|
static dockapp_rv_t da_xfd_callback (
|
|
void *unused_cbdata,
|
|
short unused_revents)
|
|
{
|
|
(void)unused_cbdata;
|
|
(void)unused_revents;
|
|
|
|
XSync (display, False);
|
|
|
|
while (XPending (display)) {
|
|
|
|
XEvent event;
|
|
|
|
XNextEvent (display, &event);
|
|
|
|
switch (event.type) {
|
|
case ButtonPress:
|
|
da_mouse_button_down (
|
|
event.xbutton.x,
|
|
event.xbutton.y,
|
|
event.xbutton.state);
|
|
break;
|
|
|
|
case ButtonRelease:
|
|
/* da_mouse_button_up() returns the callback rv of the
|
|
* callback which is invoked, if any
|
|
*/
|
|
return da_mouse_button_up (
|
|
event.xbutton.x,
|
|
event.xbutton.y,
|
|
event.xbutton.state);
|
|
break;
|
|
|
|
case Expose:
|
|
da_redraw_icon ();
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
XCloseDisplay (display);
|
|
return dockapp_exit;
|
|
|
|
case SelectionNotify:
|
|
return da_receive_selection (&event);
|
|
}
|
|
}
|
|
|
|
return dockapp_ok;
|
|
}
|
|
|
|
|
|
int da_x_error_handler (Display *display, XErrorEvent *xerr)
|
|
{
|
|
char msgbuf[1024];
|
|
|
|
XGetErrorText (display, xerr->error_code, msgbuf, sizeof msgbuf);
|
|
|
|
fprintf (stderr, "X11 error: %s\n", msgbuf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* the following code is stolen largely from wmgeneral.c...
|
|
*/
|
|
static Pixmap da_create_shaping_bitmap (char **xpm)
|
|
{
|
|
int i,j,k;
|
|
int width, height, numcol, depth;
|
|
unsigned long zero=0;
|
|
unsigned char bwrite;
|
|
int bcount;
|
|
unsigned long curpixel;
|
|
|
|
char xbm_data[64*64];
|
|
char *xbm = xbm_data;
|
|
|
|
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+64+1; i++) {
|
|
bcount = 0;
|
|
bwrite = 0;
|
|
for (j=0; j<64*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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return XCreateBitmapFromData (
|
|
display,
|
|
icon_win,
|
|
xbm_data,
|
|
64, 64);
|
|
}
|
|
|
|
|
|
dockapp_rv_t dockapp_init_gui (
|
|
char *appname,
|
|
char *argv[],
|
|
char **xpmdata)
|
|
{
|
|
int screen;
|
|
Window root;
|
|
XpmAttributes xpm_att;
|
|
Pixmap xpm_mask;
|
|
unsigned long black, white;
|
|
|
|
(void)argv; /* not currently parsed */
|
|
|
|
/* initialize x error handler */
|
|
XSetErrorHandler (da_x_error_handler);
|
|
|
|
/* get some stuff out */
|
|
display = XOpenDisplay (0);
|
|
|
|
screen = DefaultScreen (display);
|
|
|
|
root = RootWindow (display, screen);
|
|
|
|
black = BlackPixel (display, screen);
|
|
white = WhitePixel (display, screen);
|
|
|
|
/* construct the pixmap */
|
|
xpm_att.valuemask = XpmReturnPixels | XpmReturnExtensions;
|
|
|
|
XpmCreatePixmapFromData (
|
|
display,
|
|
root,
|
|
xpmdata,
|
|
&icon_pixmap,
|
|
&xpm_mask,
|
|
&xpm_att);
|
|
|
|
/* construct the windows */
|
|
main_win = XCreateSimpleWindow (
|
|
display,
|
|
root, /* parent */
|
|
0, 0, 64, 64, /* pos & size */
|
|
1, /* border width */
|
|
black, /* foreground */
|
|
white); /* background */
|
|
|
|
icon_win = XCreateSimpleWindow (
|
|
display,
|
|
main_win, /* parent */
|
|
0, 0, 64, 64, /* pos & size */
|
|
1, /* border width */
|
|
black, /* foreground */
|
|
white); /* background */
|
|
|
|
/* request all interesting X events */
|
|
XSelectInput (display, main_win,
|
|
ButtonPressMask | ExposureMask | ButtonReleaseMask |
|
|
PointerMotionMask | StructureNotifyMask);
|
|
|
|
XSelectInput (display, icon_win,
|
|
ButtonPressMask | ExposureMask | ButtonReleaseMask |
|
|
PointerMotionMask | StructureNotifyMask);
|
|
|
|
/* apply the shaping bitmap */
|
|
XShapeCombineMask (
|
|
display,
|
|
icon_win,
|
|
ShapeBounding,
|
|
0, 0,
|
|
da_create_shaping_bitmap (xpmdata),
|
|
ShapeSet);
|
|
|
|
XShapeCombineMask (
|
|
display,
|
|
main_win,
|
|
ShapeBounding,
|
|
0, 0,
|
|
da_create_shaping_bitmap (xpmdata),
|
|
ShapeSet);
|
|
|
|
|
|
/* set wm hints and title */
|
|
{
|
|
XClassHint classhint;
|
|
XWMHints wmhints;
|
|
|
|
classhint.res_name = appname;
|
|
classhint.res_class = appname;
|
|
XSetClassHint (display, main_win, &classhint);
|
|
|
|
wmhints.initial_state = WithdrawnState;
|
|
wmhints.icon_window = icon_win;
|
|
wmhints.window_group = main_win;
|
|
wmhints.flags = StateHint | IconWindowHint | WindowGroupHint;
|
|
XSetWMHints (display, main_win, &wmhints);
|
|
|
|
XStoreName (display, main_win, appname);
|
|
}
|
|
|
|
/* now we need two gc's to do drawing & copying... one which paints
|
|
* by overwriting pixels, and one which paints by xor'ing pixels
|
|
*/
|
|
{
|
|
XGCValues gcv;
|
|
|
|
gcv.graphics_exposures = 0;
|
|
gcv.function = GXcopy;
|
|
|
|
copy_gc = XCreateGC (
|
|
display,
|
|
root,
|
|
GCGraphicsExposures | GCFunction,
|
|
&gcv);
|
|
|
|
gcv.function = GXxor;
|
|
|
|
xor_gc = XCreateGC (
|
|
display,
|
|
root,
|
|
GCGraphicsExposures | GCFunction,
|
|
&gcv);
|
|
}
|
|
|
|
/* finally, show the window */
|
|
XMapWindow (display, main_win);
|
|
|
|
/* invoke da_xfd_callback once manually to process all events which
|
|
* were generated by the above work... after this, it will be called
|
|
* by the framework whenever there is activity on the server socket
|
|
*/
|
|
da_xfd_callback (0, 0);
|
|
|
|
/* now that we're up, add the X file descriptor to the main poll
|
|
* loop and bind it to our event handler
|
|
*/
|
|
return dockapp_add_pollfd (
|
|
XConnectionNumber (display),
|
|
POLLIN | POLLPRI,
|
|
da_xfd_callback,
|
|
0);
|
|
}
|
|
|
|
|
|
void dockapp_copy_pixmap (
|
|
int source_x, int source_y,
|
|
int target_x, int target_y,
|
|
int w, int h)
|
|
{
|
|
XCopyArea (
|
|
display,
|
|
icon_pixmap,
|
|
icon_pixmap,
|
|
copy_gc,
|
|
source_x, source_y,
|
|
w, h,
|
|
target_x, target_y);
|
|
|
|
da_redraw_icon ();
|
|
}
|
|
|
|
|
|
void dockapp_overlay_pixmap (
|
|
int source_x, int source_y,
|
|
int target_x, int target_y,
|
|
int w, int h)
|
|
{
|
|
XCopyArea (
|
|
display,
|
|
icon_pixmap,
|
|
icon_pixmap,
|
|
xor_gc,
|
|
source_x, source_y,
|
|
w, h,
|
|
target_x, target_y);
|
|
|
|
da_redraw_icon ();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|