mc/xv/xvicon.c
1998-02-27 04:54:42 +00:00

488 lines
15 KiB
C

/* XView Onroot Icon from Pixmap creation.
Copyright (C) 1995 Jakub Jelinek.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
#ifdef HAVE_XPM_SHAPE
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include <xview/xview.h>
#include <xview/frame.h>
#include <xview/dragdrop.h>
#include <xview/font.h>
#include <xview/defaults.h>
#include "util.h"
#include "mad.h"
#include "ext.h" /* regex_command */
#include "xvmain.h"
#include "xvicon.h"
#include "xvscreen.h"
/* XPM */
static char *file_xpm[] = {
/* width height ncolors chars_per_pixel */
"32 32 5 1",
/* colors */
"` c black",
"a c gray",
"c c black",
"d s none c none",
"e c white",
/* pixels */
"dddd``````````````````dddddddddd",
"dddd`eeeeeeeeeeeeeeee``ddddddddd",
"dddd`eeeeeeeeeeeeeeee`a`dddddddd",
"dddd`eeeeeeeeeeeeeeee`aa`ddddddd",
"dddd`eeeeeeeeeeeeeeee`aaa`dddddd",
"dddd`eeeeeeeeeeeeeeee`aaaa`ddddd",
"dddd`eeeeeeeeeeeeeeee```````dddd",
"dddd`eeeeeeeeeeeeeeeeeaaaaa`cddd",
"dddd`eeeeeeeeeeeeeeeeeeaaaa`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
"dddd````````````````````````cddd",
"dddddccccccccccccccccccccccccddd"
};
extern Display *dpy;
static Screen *screen;
#define root XRootWindowOfScreen(screen)
static Colormap colormap;
extern Frame mcframe;
extern Dlg_head *midnight_dlg;
static struct {
Frame frame;
int btn_down_x, btn_down_y;
struct timeval prev_time;
} click_info = { XV_NULL, 0, 0, {0, 0}};
static int xv_icon_grab = 0, xv_icon_drag = 0;
static int wait_for_btnup = 0;
static GC xor_gc;
static int last_x, last_y, offset_x, offset_y;
static xv_icondep_frame = XV_NULL;
static char *xv_icondep_free = NULL;
static void draw_borderrect (Window win, Xv_window xv_win, int x, int y)
{
int width, height;
width = xv_get (xv_win, XV_WIDTH);
height = xv_get (xv_win, XV_HEIGHT);
XDrawRectangle (dpy, win, xor_gc, x, y, width, height);
}
struct xviconruncommand {
char *filename;
char *action;
char *drops;
};
void xvIconRunCommand (struct xviconruncommand *xirc)
{
regex_command (x_basename (xirc->filename), xirc->action, xirc->drops, NULL);
free (xirc->filename);
free (xirc->action);
if (xirc->drops != NULL)
free (xirc->drops);
free (xirc);
}
void XvIconRunCommand (Frame frame, char *action, char *drops)
{
XpmIcon *icon = (XpmIcon *) xv_get (frame, WIN_CLIENT_DATA);
struct xviconruncommand *xirc = (struct xviconruncommand *)
xmalloc (sizeof (struct xviconruncommand), "XvIconRunCommand");
xirc->filename = strdup (icon->filename);
xirc->action = strdup (action);
if (drops != NULL)
xirc->drops = strdup (drops);
else
xirc->drops = NULL;
xv_post_proc (midnight_dlg, (void (*)(void *))xvIconRunCommand,
(void *) xirc);
}
void XvIconDepMenu (Menu menu, Menu_item item)
{
char *p = (char *) xv_get (item, MENU_STRING);
if (!strcmp (p, "Close")) {
DeleteXpmIcon ((XpmIcon *) xv_get (xv_icondep_frame, WIN_CLIENT_DATA));
xv_destroy_safe (xv_icondep_frame);
XFlush (dpy);
} else {
XvIconRunCommand (xv_icondep_frame, p, NULL);
}
if (xv_icondep_free)
free (xv_icondep_free);
}
void XpmIconEvent (Xv_window frame, Event *event)
{
if (xv_icon_drag) {
if (event_action (event) == LOC_DRAG) {
draw_borderrect (root, frame, last_x, last_y);
last_x = event_x (event) - offset_x;
last_y = event_y (event) - offset_y;
draw_borderrect (root, frame, last_x, last_y);
return;
} else if (event_is_button (event)) {
if (event_is_down (event))
return;
} else if (!event_is_iso (event))
return;
draw_borderrect (root, frame, last_x, last_y);
last_x = event_x (event) - offset_x;
last_y = event_y (event) - offset_y;
xv_set (frame,
XV_X, last_x,
XV_Y, last_y,
NULL);
xv_icon_drag = 0;
xv_icon_grab = 0;
XFreeGC (dpy, xor_gc);
return;
} else if (xv_icon_grab) {
if (wait_for_btnup) {
if (event_action (event) == LOC_DRAG) {
static int threshold;
static int dist_x, dist_y;
if (threshold == 0)
threshold = defaults_get_integer (
"mxc.clickmovethreshold",
"Mxc.ClickMoveThreshold", 10);
dist_x = event_x (event) - click_info.btn_down_x;
if (dist_x < 0)
dist_x = - dist_x;
dist_y = event_y (event) - click_info.btn_down_y;
if (dist_y < 0)
dist_y = - dist_y;
if (!xv_icon_drag && (dist_x > threshold || dist_y > threshold ||
event_ctrl_is_down (event) || event_shift_is_down (event))) {
xor_gc = XCreateGC (dpy, xv_get (frame, XV_XID), 0, 0);
XSetForeground (dpy, xor_gc, xv_get (frame, WIN_FOREGROUND_COLOR));
XSetFunction (dpy, xor_gc, GXxor);
XSetLineAttributes (dpy, xor_gc, 2, LineSolid, CapNotLast, JoinRound);
last_x = xv_get (frame, XV_X);
last_y = xv_get (frame, XV_Y);
offset_x = event_x (event) - last_x;
offset_y = event_y (event) - last_y;
draw_borderrect (root, frame, last_x, last_y);
xv_icon_drag = 1;
}
return;
}
if (event_is_button (event) && event_is_down (event)) {
return;
}
if (event_action (event) == ACTION_SELECT) {
if (is_dbl_click (&click_info.prev_time, &event_time (event))) {
click_info.prev_time.tv_sec = 0;
click_info.prev_time.tv_usec = 0;
XvIconRunCommand (frame, "Open", NULL);
} else {
click_info.prev_time = event_time (event);
}
xv_icon_grab = 0;
return;
}
if (event_action (event) == ACTION_ADJUST) {
xv_icon_grab = 0;
return;
}
if (!event_is_button (event) && !event_is_iso (event))
return;
xv_icon_grab = 0;
return;
}
}
switch (event_action (event)) {
case ACTION_DRAG_PREVIEW:
return;
case ACTION_DRAG_COPY:
case ACTION_DRAG_MOVE:
case ACTION_DRAG_LOAD:
{
Xv_drop_site ds;
Selection_requestor sel = (Selection_requestor)
xv_get (frame, XV_KEY_DATA, KEY_DATA_SELREQ);
if ((ds = dnd_decode_drop (sel, event)) != XV_ERROR) {
int length, format;
char *p, *q;
xv_set (sel, SEL_TYPE, XA_STRING, NULL);
q = (char *) xv_get (sel, SEL_DATA, &length, &format);
if (length != SEL_ERROR) {
XvIconRunCommand (frame, "Drop", q);
free (q);
}
xv_set (sel, SEL_TYPE_NAME, "_SUN_SELECTION_END", 0);
xv_get (sel, SEL_DATA, &length, &format);
dnd_done (sel);
}
}
return;
case ACTION_HELP:
if (event_is_down (event)) {
}
return;
case ACTION_MENU:
if (event_is_down (event)) {
static Menu menu = XV_NULL;
char *p, *q, c;
char *filename;
if (menu != XV_NULL)
xv_destroy (menu);
filename = ((XpmIcon *) xv_get (frame, WIN_CLIENT_DATA))->filename;
menu = (Menu) xv_create (XV_NULL, MENU,
MENU_NOTIFY_PROC, XvIconDepMenu,
MENU_TITLE_ITEM, x_basename (filename),
MENU_STRINGS, "Close", "Open", "View", "Edit", NULL,
NULL);
p = regex_command (x_basename (filename), NULL, NULL, NULL);
if (p != NULL) {
for (;;) {
while (*p == ' ' || *p == '\t')
p++;
if (!*p)
break;
q = p;
while (*q && *q != ' ' && *q != '\t')
q++;
c = *q;
*q = 0;
xv_set (menu,
MENU_ITEM,
MENU_STRING, p,
NULL,
NULL);
if (!c)
break;
p = q + 1;
}
}
xv_icondep_frame = frame;
xv_icondep_free = p;
menu_show (menu, frame, event, NULL);
}
return;
case ACTION_SELECT:
case ACTION_ADJUST:
if (event_is_down (event)) {
if (click_info.frame != frame) {
click_info.frame = frame;
click_info.prev_time.tv_sec = 0;
click_info.prev_time.tv_usec = 0;
}
click_info.btn_down_x = event_x (event);
click_info.btn_down_y = event_y (event);
wait_for_btnup = 1;
xv_icon_grab = 1;
}
}
}
XpmIcon *CreateXpmIcon (char *iconname, int x, int y, char *title)
{
int ErrorStatus;
Window win;
Frame frame;
XpmIcon *view = xmalloc (sizeof (*view), "CreateXpmIcon");
Rect rect;
Font font;
Font_string_dims fontdims;
XFontStruct *xfs;
XImage *ximage, *shapeimage;
GC gc;
static char *fontname = NULL;
int width, height;
int titlelen = strlen (title);
screen = ScreenOfDisplay (dpy,
(int) xv_get ((Xv_Screen) xv_get (mcframe, XV_SCREEN), SCREEN_NUMBER));
colormap = XDefaultColormapOfScreen(screen);
memset (view, 0, sizeof (*view));
frame = xv_create (mcframe, FRAME,
WIN_MAP, FALSE,
XV_X, x,
XV_Y, y,
XV_WIDTH, 32,
XV_HEIGHT, 32,
WIN_CONSUME_EVENTS, WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, LOC_DRAG, NULL,
WIN_EVENT_PROC, XpmIconEvent,
WIN_CLIENT_DATA, view,
NULL);
win = (Window) xv_get (frame, XV_XID);
view->attributes.valuemask |= XpmReturnInfos;
view->attributes.valuemask |= XpmReturnPixels | XpmCloseness;
view->attributes.closeness = 40000;
ErrorStatus = XpmReadFileToImage(dpy, iconname,
&ximage, &shapeimage,
&view->attributes);
if (ErrorStatus != XpmSuccess)
ErrorStatus = XpmCreateImageFromData(dpy, file_xpm,
&ximage, &shapeimage,
&view->attributes);
if (ErrorStatus != XpmSuccess) {
free (view);
xv_destroy_safe (frame);
XFlush (dpy);
return NULL;
}
fontname = defaults_get_string ("mxc.iconfont", "Mxc.IconFont", "");
font = XV_NULL;
if (*fontname)
font = xv_find (mcframe, FONT,
FONT_NAME, fontname,
NULL);
if (font == XV_NULL)
font = xv_get (mcframe, XV_FONT);
xv_get (font, FONT_STRING_DIMS, title, &fontdims);
xfs = (XFontStruct *) xv_get (font, FONT_INFO);
width = view->attributes.width;
if (view->attributes.width < fontdims.width)
view->attributes.width = fontdims.width;
height = view->attributes.height;
view->attributes.height += fontdims.height;
view->pixmap = XCreatePixmap (dpy, win, view->attributes.width,
view->attributes.height, ximage->depth);
gc = XCreateGC (dpy, view->pixmap, 0, NULL);
XSetForeground (dpy, gc, BlackPixelOfScreen (screen));
XFillRectangle (dpy, view->pixmap, gc, 0, 0, view->attributes.width,
view->attributes.height);
XPutImage (dpy, view->pixmap, gc, ximage, 0, 0,
(view->attributes.width - width) / 2, 0, width, height);
XFreeGC (dpy, gc);
view->mask = XCreatePixmap (dpy, win, view->attributes.width,
view->attributes.height, 1);
gc = XCreateGC (dpy, view->mask, 0, NULL);
XSetFont (dpy, gc, xv_get (font, XV_XID));
XSetForeground (dpy, gc, 0);
XFillRectangle (dpy, view->mask, gc, 0, 0, view->attributes.width,
view->attributes.height);
XSetForeground (dpy, gc, 1);
if (shapeimage != NULL)
XPutImage (dpy, view->mask, gc, shapeimage, 0, 0,
(view->attributes.width - width) / 2, 0, width, height);
else
XFillRectangle (dpy, view->mask, gc,
(view->attributes.width - width) / 2, 0, width, height);
XDrawString (dpy, view->mask, gc,
(view->attributes.width - fontdims.width) / 2, height + xfs->ascent,
title, titlelen);
XFreeGC (dpy, gc);
XDestroyImage (ximage);
if (shapeimage != NULL)
XDestroyImage (shapeimage);
xv_set (frame,
XV_X, x - view->attributes.width / 2,
XV_Y, y - view->attributes.height / 2,
XV_WIDTH, view->attributes.width,
XV_HEIGHT, view->attributes.height,
NULL);
XSetWindowBackgroundPixmap(dpy, win, view->pixmap);
if (view->mask)
XShapeCombineMask(dpy, win, ShapeBounding, 0, 0,
view->mask, ShapeSet);
XClearWindow(dpy, win);
rect.r_left = 0;
rect.r_top = 0;
rect.r_width = view->attributes.width;
rect.r_height = view->attributes.height;
xv_create (frame, DROP_SITE_ITEM,
DROP_SITE_EVENT_MASK, DND_ENTERLEAVE,
DROP_SITE_REGION, &rect,
NULL);
xv_set (frame,
XV_KEY_DATA, KEY_DATA_SELREQ,
xv_create (frame, SELECTION_REQUESTOR, NULL),
NULL);
xv_set (frame,
WIN_MAP, TRUE,
NULL);
view->frame = frame;
return view;
}
void DeleteXpmIcon (XpmIcon *view)
{
if (view->pixmap) {
XFreePixmap(dpy, view->pixmap);
if (view->mask)
XFreePixmap(dpy, view->mask);
XFreeColors(dpy, colormap,
view->attributes.pixels, view->attributes.npixels, 0);
XpmFreeAttributes(&view->attributes);
}
if (view->filename)
free (view->filename);
free (view);
}
#endif