/*-
* Copyright (c) 2001 Jordan DeLong
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "plugutil.h"
/* temporary */
#define ICONSIZE 64
/* per screen structure */
static struct iconscr {
Pixmap pixmap; /* pixmap used as window bg for icons */
} *iconscr;
/* structure describing an icon */
typedef struct icon {
Window icon; /* the icon window we created */
client_t *client; /* the client it represents */
TAILQ_ENTRY(icon) i_list;
} icon_t;
/* linked list of icons */
static TAILQ_HEAD(iconlist, icon) icon_list;
/* context for icon windows */
static XContext icon_context;
/* information for dragging of icons */
static icon_t *dragged_icon = NULL;
static int drag_x, drag_y;
/* add an icon */
static icon_t *icon_add(client_t *client) {
XSetWindowAttributes attr;
icon_t *icon;
Window dumwin;
int x, y, width, height;
int dumint;
icon = calloc(1, sizeof(icon_t));
if (!icon)
return NULL;
icon->client = client;
if (client->wmhints && client->wmhints->flags & IconPositionHint) {
x = client->wmhints->icon_x;
y = client->wmhints->icon_y;
} else {
x = client->x + ((client->width + client->dgroup->left_space
+ client->dgroup->right_space) / 2) - ICONSIZE / 2;
y = client->y + ((client->height + client->dgroup->top_space
+ client->dgroup->bottom_space) / 2) - ICONSIZE / 2;
}
/* create the window */
attr.override_redirect = 1;
attr.background_pixmap = iconscr[client->screen->num].pixmap;
icon->icon = XCreateWindow(display, RootWindow(display, client->screen->num), x, y,
ICONSIZE, ICONSIZE, 0, CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect | CWBackPixmap, &attr);
plugin_setcontext(plugin_this, icon->icon);
XSaveContext(display, icon->icon, icon_context, (XPointer) icon);
XSaveContext(display, icon->client->frame, icon_context, (XPointer) icon);
/* use it's icon window if it has one */
if (client->wmhints && client->wmhints->flags & IconWindowHint) {
XGetGeometry(display, client->wmhints->icon_window, &dumwin,
&dumint, &dumint, &width, &height, &dumint, &dumint);
XSetWindowBorder(display, client->wmhints->icon_window, 0);
XReparentWindow(display, client->wmhints->icon_window, icon->icon,
ICONSIZE / 2 - width / 2, ICONSIZE / 2 - height / 2);
XMapWindow(display, client->wmhints->icon_window);
}
TAILQ_INSERT_HEAD(&icon_list, icon, i_list);
XSelectInput(display, icon->icon, ButtonPressMask | ButtonReleaseMask | Button1MotionMask);
XMapRaised(display, icon->icon);
return icon;
}
/* get rid of an icon */
static void icon_rm(icon_t *icon) {
plugin_rmcontext(icon->icon);
XDeleteContext(display, icon->icon, icon_context);
XDeleteContext(display, icon->client->frame, icon_context);
XDestroyWindow(display, icon->icon);
TAILQ_REMOVE(&icon_list, icon, i_list);
free(icon);
}
/* client window gets unmmapped, and client_t subsequently becomes invalid */
static int window_death(int pcall, client_t *client) {
icon_t *icon;
if (XFindContext(display, client->frame, icon_context, (XPointer *) &icon))
return PLUGIN_OK;
icon_rm(icon);
return PLUGIN_OK;
}
/* client iconification */
static int iconify_notify(int pcall, client_t *client) {
icon_t *icon;
if (XFindContext(display, client->frame, icon_context, (XPointer *) &icon)) {
if (!icon_add(client))
return PLUGIN_UNLOAD;
} else
XMapRaised(display, icon->icon);
return PLUGIN_OK;
}
/* client deiconification */
static int restore_notify(int pcall, client_t *client) {
icon_t *icon;
if (XFindContext(display, client->frame, icon_context, (XPointer *) &icon))
return PLUGIN_OK;
XUnmapWindow(display, icon->icon);
return PLUGIN_OK;
}
/* x event handler for button presses */
static void button_press(XButtonEvent *e) {
icon_t *icon;
if (XFindContext(display, e->window, icon_context, (XPointer *) &icon))
return;
drag_x = e->x;
drag_y = e->y;
XRaiseWindow(display, icon->icon);
}
/* x event handler for presses on the icons */
static void button_release(XButtonEvent *e) {
icon_t *icon;
if (XFindContext(display, e->window, icon_context, (XPointer *) &icon))
return;
/* they were dragging, not clicking */
if (dragged_icon) {
dragged_icon = NULL;
return;
}
/* restore it if it's still over the icon */
if (e->x < ICONSIZE && e->y < ICONSIZE && e->x > 0 && e->y > 0)
action_restore(icon->client);
}
/* x event handler to allow the icons to be dragged */
static void pointer_motion(XMotionEvent *e) {
if (!dragged_icon) {
if (XFindContext(display, e->window, icon_context, (XPointer *) &dragged_icon))
return;
} else {
/* this shouldn't happen */
if (e->window != dragged_icon->icon) {
dragged_icon = NULL;
return;
}
}
XMoveWindow(display, dragged_icon->icon, e->x_root - drag_x,
e->y_root - drag_y);
}
/* x event processor */
int xevent_handler(XEvent *e) {
switch (e->type) {
case ButtonPress:
button_press(&e->xbutton);
break;
case ButtonRelease:
button_release(&e->xbutton);
break;
case MotionNotify:
pointer_motion(&e->xmotion);
break;
}
return PLUGIN_OK;
}
/* read parameters */
int init() {
char *pmfn;
int i, cnt;
TAILQ_INIT(&icon_list);
REQUIRED_PARAM(&plugin_this->params, "pixmap", string, pmfn);
cnt = ScreenCount(display);
iconscr = calloc(cnt, sizeof(struct iconscr));
if (!iconscr)
goto free;
for (i = 0; i < cnt; i++)
XpmReadFileToPixmap(display, RootWindow(display, i), pmfn, &iconscr[i].pixmap,
NULL, NULL);
free(pmfn);
return PLUGIN_OK;
free:
free(pmfn);
return PLUGIN_UNLOAD;
}
/* setup for the plugin */
int start() {
icon_context = XUniqueContext();
/* register plugin callbacks */
plugin_callback_add(plugin_this, PCALL_WINDOW_DEATH, window_death);
plugin_callback_add(plugin_this, PCALL_ICONIFY_NOTIFY, iconify_notify);
plugin_callback_add(plugin_this, PCALL_RESTORE_NOTIFY, restore_notify);
return PLUGIN_OK;
}
/* plugin shutdown */
void shutdown() {
icon_t *icon;
int i;
while (!TAILQ_EMPTY(&icon_list)) {
icon = TAILQ_FIRST(&icon_list);
icon_rm(icon);
}
if (iconscr) {
for (i = 0; i < screen_count; i++)
XFreePixmap(display, iconscr[i].pixmap);
free(iconscr);
}
}
syntax highlighted by Code2HTML, v. 0.9.1