update
[midnight-commander.git] / xv / xvicon.c
blobd0b0221b09491fb55616bc84f2022cd922e62c05
1 /* XView Onroot Icon from Pixmap creation.
2 Copyright (C) 1995 Jakub Jelinek.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 #include <config.h>
20 #ifdef HAVE_XPM_SHAPE
22 #include <stdio.h>
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/extensions/shape.h>
26 #include <xview/xview.h>
27 #include <xview/frame.h>
28 #include <xview/dragdrop.h>
29 #include <xview/font.h>
30 #include <xview/defaults.h>
31 #include "util.h"
32 #include "mad.h"
33 #include "ext.h" /* regex_command */
35 #include "xvmain.h"
36 #include "xvicon.h"
37 #include "xvscreen.h"
39 /* XPM */
40 static char *file_xpm[] = {
41 /* width height ncolors chars_per_pixel */
42 "32 32 5 1",
43 /* colors */
44 "` c black",
45 "a c gray",
46 "c c black",
47 "d s none c none",
48 "e c white",
49 /* pixels */
50 "dddd``````````````````dddddddddd",
51 "dddd`eeeeeeeeeeeeeeee``ddddddddd",
52 "dddd`eeeeeeeeeeeeeeee`a`dddddddd",
53 "dddd`eeeeeeeeeeeeeeee`aa`ddddddd",
54 "dddd`eeeeeeeeeeeeeeee`aaa`dddddd",
55 "dddd`eeeeeeeeeeeeeeee`aaaa`ddddd",
56 "dddd`eeeeeeeeeeeeeeee```````dddd",
57 "dddd`eeeeeeeeeeeeeeeeeaaaaa`cddd",
58 "dddd`eeeeeeeeeeeeeeeeeeaaaa`cddd",
59 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
60 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
61 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
62 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
63 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
64 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
65 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
66 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
67 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
68 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
69 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
70 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
71 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
72 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
73 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
74 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
75 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
76 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
77 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
78 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
79 "dddd`eeeeeeeeeeeeeeeeeeeeee`cddd",
80 "dddd````````````````````````cddd",
81 "dddddccccccccccccccccccccccccddd"
84 extern Display *dpy;
85 static Screen *screen;
86 #define root XRootWindowOfScreen(screen)
87 static Colormap colormap;
88 extern Frame mcframe;
89 extern Dlg_head *midnight_dlg;
91 static struct {
92 Frame frame;
93 int btn_down_x, btn_down_y;
94 struct timeval prev_time;
95 } click_info = { XV_NULL, 0, 0, {0, 0}};
96 static int xv_icon_grab = 0, xv_icon_drag = 0;
97 static int wait_for_btnup = 0;
98 static GC xor_gc;
99 static int last_x, last_y, offset_x, offset_y;
100 static xv_icondep_frame = XV_NULL;
101 static char *xv_icondep_free = NULL;
103 static void draw_borderrect (Window win, Xv_window xv_win, int x, int y)
105 int width, height;
107 width = xv_get (xv_win, XV_WIDTH);
108 height = xv_get (xv_win, XV_HEIGHT);
110 XDrawRectangle (dpy, win, xor_gc, x, y, width, height);
113 struct xviconruncommand {
114 char *filename;
115 char *action;
116 char *drops;
119 void xvIconRunCommand (struct xviconruncommand *xirc)
121 char *droplist [2];
122 droplist [0] = xirc->drops;
123 droplist [1] = NULL;
125 regex_command (x_basename (xirc->filename), xirc->action, droplist, NULL);
126 free (xirc->filename);
127 free (xirc->action);
128 if (xirc->drops != NULL)
129 free (xirc->drops);
130 free (xirc);
133 void XvIconRunCommand (Frame frame, char *action, char *drops)
135 XpmIcon *icon = (XpmIcon *) xv_get (frame, WIN_CLIENT_DATA);
136 struct xviconruncommand *xirc = (struct xviconruncommand *)
137 xmalloc (sizeof (struct xviconruncommand), "XvIconRunCommand");
139 xirc->filename = strdup (icon->filename);
140 xirc->action = strdup (action);
141 if (drops != NULL)
142 xirc->drops = strdup (drops);
143 else
144 xirc->drops = NULL;
146 xv_post_proc (midnight_dlg, (void (*)(void *))xvIconRunCommand,
147 (void *) xirc);
150 void XvIconDepMenu (Menu menu, Menu_item item)
152 char *p = (char *) xv_get (item, MENU_STRING);
154 if (!strcmp (p, "Close")) {
155 DeleteXpmIcon ((XpmIcon *) xv_get (xv_icondep_frame, WIN_CLIENT_DATA));
156 xv_destroy_safe (xv_icondep_frame);
157 XFlush (dpy);
158 } else {
159 XvIconRunCommand (xv_icondep_frame, p, NULL);
161 if (xv_icondep_free)
162 free (xv_icondep_free);
165 void XpmIconEvent (Xv_window frame, Event *event)
167 if (xv_icon_drag) {
168 if (event_action (event) == LOC_DRAG) {
169 draw_borderrect (root, frame, last_x, last_y);
170 last_x = event_x (event) - offset_x;
171 last_y = event_y (event) - offset_y;
172 draw_borderrect (root, frame, last_x, last_y);
173 return;
174 } else if (event_is_button (event)) {
175 if (event_is_down (event))
176 return;
177 } else if (!event_is_iso (event))
178 return;
179 draw_borderrect (root, frame, last_x, last_y);
180 last_x = event_x (event) - offset_x;
181 last_y = event_y (event) - offset_y;
182 xv_set (frame,
183 XV_X, last_x,
184 XV_Y, last_y,
185 NULL);
186 xv_icon_drag = 0;
187 xv_icon_grab = 0;
188 XFreeGC (dpy, xor_gc);
189 return;
190 } else if (xv_icon_grab) {
191 if (wait_for_btnup) {
192 if (event_action (event) == LOC_DRAG) {
193 static int threshold;
194 static int dist_x, dist_y;
196 if (threshold == 0)
197 threshold = defaults_get_integer (
198 "mxc.clickmovethreshold",
199 "Mxc.ClickMoveThreshold", 10);
201 dist_x = event_x (event) - click_info.btn_down_x;
202 if (dist_x < 0)
203 dist_x = - dist_x;
204 dist_y = event_y (event) - click_info.btn_down_y;
205 if (dist_y < 0)
206 dist_y = - dist_y;
207 if (!xv_icon_drag && (dist_x > threshold || dist_y > threshold ||
208 event_ctrl_is_down (event) || event_shift_is_down (event))) {
209 xor_gc = XCreateGC (dpy, xv_get (frame, XV_XID), 0, 0);
210 XSetForeground (dpy, xor_gc, xv_get (frame, WIN_FOREGROUND_COLOR));
211 XSetFunction (dpy, xor_gc, GXxor);
212 XSetLineAttributes (dpy, xor_gc, 2, LineSolid, CapNotLast, JoinRound);
213 last_x = xv_get (frame, XV_X);
214 last_y = xv_get (frame, XV_Y);
215 offset_x = event_x (event) - last_x;
216 offset_y = event_y (event) - last_y;
217 draw_borderrect (root, frame, last_x, last_y);
218 xv_icon_drag = 1;
220 return;
222 if (event_is_button (event) && event_is_down (event)) {
223 return;
225 if (event_action (event) == ACTION_SELECT) {
226 if (is_dbl_click (&click_info.prev_time, &event_time (event))) {
227 click_info.prev_time.tv_sec = 0;
228 click_info.prev_time.tv_usec = 0;
229 XvIconRunCommand (frame, "Open", NULL);
230 } else {
231 click_info.prev_time = event_time (event);
233 xv_icon_grab = 0;
234 return;
236 if (event_action (event) == ACTION_ADJUST) {
237 xv_icon_grab = 0;
238 return;
240 if (!event_is_button (event) && !event_is_iso (event))
241 return;
242 xv_icon_grab = 0;
243 return;
246 switch (event_action (event)) {
247 case ACTION_DRAG_PREVIEW:
248 return;
249 case ACTION_DRAG_COPY:
250 case ACTION_DRAG_MOVE:
251 case ACTION_DRAG_LOAD:
253 Xv_drop_site ds;
254 Selection_requestor sel = (Selection_requestor)
255 xv_get (frame, XV_KEY_DATA, KEY_DATA_SELREQ);
257 if ((ds = dnd_decode_drop (sel, event)) != XV_ERROR) {
258 int length, format;
259 char *p, *q;
261 xv_set (sel, SEL_TYPE, XA_STRING, NULL);
262 q = (char *) xv_get (sel, SEL_DATA, &length, &format);
263 if (length != SEL_ERROR) {
264 XvIconRunCommand (frame, "Drop", q);
265 free (q);
267 xv_set (sel, SEL_TYPE_NAME, "_SUN_SELECTION_END", 0);
268 xv_get (sel, SEL_DATA, &length, &format);
269 dnd_done (sel);
272 return;
273 case ACTION_HELP:
274 if (event_is_down (event)) {
276 return;
277 case ACTION_MENU:
278 if (event_is_down (event)) {
279 static Menu menu = XV_NULL;
280 char *p, *q, c;
281 char *filename;
283 if (menu != XV_NULL)
284 xv_destroy (menu);
286 filename = ((XpmIcon *) xv_get (frame, WIN_CLIENT_DATA))->filename;
287 menu = (Menu) xv_create (XV_NULL, MENU,
288 MENU_NOTIFY_PROC, XvIconDepMenu,
289 MENU_TITLE_ITEM, x_basename (filename),
290 MENU_STRINGS, "Close", "Open", "View", "Edit", NULL,
291 NULL);
292 p = regex_command (x_basename (filename), NULL, NULL, NULL);
293 if (p != NULL) {
294 for (;;) {
295 while (*p == ' ' || *p == '\t')
296 p++;
297 if (!*p)
298 break;
299 q = p;
300 while (*q && *q != ' ' && *q != '\t')
301 q++;
302 c = *q;
303 *q = 0;
304 xv_set (menu,
305 MENU_ITEM,
306 MENU_STRING, p,
307 NULL,
308 NULL);
309 if (!c)
310 break;
311 p = q + 1;
314 xv_icondep_frame = frame;
315 xv_icondep_free = p;
316 menu_show (menu, frame, event, NULL);
318 return;
319 case ACTION_SELECT:
320 case ACTION_ADJUST:
321 if (event_is_down (event)) {
322 if (click_info.frame != frame) {
323 click_info.frame = frame;
324 click_info.prev_time.tv_sec = 0;
325 click_info.prev_time.tv_usec = 0;
327 click_info.btn_down_x = event_x (event);
328 click_info.btn_down_y = event_y (event);
329 wait_for_btnup = 1;
330 xv_icon_grab = 1;
335 XpmIcon *CreateXpmIcon (char *iconname, int x, int y, char *title)
337 int ErrorStatus;
338 Window win;
339 Frame frame;
340 XpmIcon *view = xmalloc (sizeof (*view), "CreateXpmIcon");
341 Rect rect;
342 Font font;
343 Font_string_dims fontdims;
344 XFontStruct *xfs;
345 XImage *ximage, *shapeimage;
346 GC gc;
347 static char *fontname = NULL;
348 int width, height;
349 int titlelen = strlen (title);
351 screen = ScreenOfDisplay (dpy,
352 (int) xv_get ((Xv_Screen) xv_get (mcframe, XV_SCREEN), SCREEN_NUMBER));
354 colormap = XDefaultColormapOfScreen(screen);
355 memset (view, 0, sizeof (*view));
357 frame = xv_create (mcframe, FRAME,
358 WIN_MAP, FALSE,
359 XV_X, x,
360 XV_Y, y,
361 XV_WIDTH, 32,
362 XV_HEIGHT, 32,
363 WIN_CONSUME_EVENTS, WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, LOC_DRAG, NULL,
364 WIN_EVENT_PROC, XpmIconEvent,
365 WIN_CLIENT_DATA, view,
366 NULL);
368 win = (Window) xv_get (frame, XV_XID);
370 view->attributes.valuemask |= XpmReturnInfos;
371 view->attributes.valuemask |= XpmReturnPixels | XpmCloseness;
372 view->attributes.closeness = 40000;
374 ErrorStatus = XpmReadFileToImage(dpy, iconname,
375 &ximage, &shapeimage,
376 &view->attributes);
377 if (ErrorStatus != XpmSuccess)
378 ErrorStatus = XpmCreateImageFromData(dpy, file_xpm,
379 &ximage, &shapeimage,
380 &view->attributes);
382 if (ErrorStatus != XpmSuccess) {
383 free (view);
384 xv_destroy_safe (frame);
385 XFlush (dpy);
386 return NULL;
389 fontname = defaults_get_string ("mxc.iconfont", "Mxc.IconFont", "");
390 font = XV_NULL;
391 if (*fontname)
392 font = xv_find (mcframe, FONT,
393 FONT_NAME, fontname,
394 NULL);
395 if (font == XV_NULL)
396 font = xv_get (mcframe, XV_FONT);
397 xv_get (font, FONT_STRING_DIMS, title, &fontdims);
398 xfs = (XFontStruct *) xv_get (font, FONT_INFO);
399 width = view->attributes.width;
400 if (view->attributes.width < fontdims.width)
401 view->attributes.width = fontdims.width;
402 height = view->attributes.height;
403 view->attributes.height += fontdims.height;
405 view->pixmap = XCreatePixmap (dpy, win, view->attributes.width,
406 view->attributes.height, ximage->depth);
407 gc = XCreateGC (dpy, view->pixmap, 0, NULL);
408 XSetForeground (dpy, gc, BlackPixelOfScreen (screen));
409 XFillRectangle (dpy, view->pixmap, gc, 0, 0, view->attributes.width,
410 view->attributes.height);
411 XPutImage (dpy, view->pixmap, gc, ximage, 0, 0,
412 (view->attributes.width - width) / 2, 0, width, height);
413 XFreeGC (dpy, gc);
414 view->mask = XCreatePixmap (dpy, win, view->attributes.width,
415 view->attributes.height, 1);
416 gc = XCreateGC (dpy, view->mask, 0, NULL);
417 XSetFont (dpy, gc, xv_get (font, XV_XID));
418 XSetForeground (dpy, gc, 0);
419 XFillRectangle (dpy, view->mask, gc, 0, 0, view->attributes.width,
420 view->attributes.height);
421 XSetForeground (dpy, gc, 1);
422 if (shapeimage != NULL)
423 XPutImage (dpy, view->mask, gc, shapeimage, 0, 0,
424 (view->attributes.width - width) / 2, 0, width, height);
425 else
426 XFillRectangle (dpy, view->mask, gc,
427 (view->attributes.width - width) / 2, 0, width, height);
428 XDrawString (dpy, view->mask, gc,
429 (view->attributes.width - fontdims.width) / 2, height + xfs->ascent,
430 title, titlelen);
431 XFreeGC (dpy, gc);
432 XDestroyImage (ximage);
433 if (shapeimage != NULL)
434 XDestroyImage (shapeimage);
436 xv_set (frame,
437 XV_X, x - view->attributes.width / 2,
438 XV_Y, y - view->attributes.height / 2,
439 XV_WIDTH, view->attributes.width,
440 XV_HEIGHT, view->attributes.height,
441 NULL);
443 XSetWindowBackgroundPixmap(dpy, win, view->pixmap);
445 if (view->mask)
446 XShapeCombineMask(dpy, win, ShapeBounding, 0, 0,
447 view->mask, ShapeSet);
449 XClearWindow(dpy, win);
451 rect.r_left = 0;
452 rect.r_top = 0;
453 rect.r_width = view->attributes.width;
454 rect.r_height = view->attributes.height;
456 xv_create (frame, DROP_SITE_ITEM,
457 DROP_SITE_EVENT_MASK, DND_ENTERLEAVE,
458 DROP_SITE_REGION, &rect,
459 NULL);
460 xv_set (frame,
461 XV_KEY_DATA, KEY_DATA_SELREQ,
462 xv_create (frame, SELECTION_REQUESTOR, NULL),
463 NULL);
465 xv_set (frame,
466 WIN_MAP, TRUE,
467 NULL);
469 view->frame = frame;
471 return view;
474 void DeleteXpmIcon (XpmIcon *view)
476 if (view->pixmap) {
477 XFreePixmap(dpy, view->pixmap);
478 if (view->mask)
479 XFreePixmap(dpy, view->mask);
481 XFreeColors(dpy, colormap,
482 view->attributes.pixels, view->attributes.npixels, 0);
484 XpmFreeAttributes(&view->attributes);
486 if (view->filename)
487 free (view->filename);
488 free (view);
491 #endif