Add NEWS bug entry for previous FvwmForm commit.
[fvwm.git] / fvwm / cursor.c
blob731bff217d4a3449e068f69cbb386d59ae2f1360
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 /* ---------------------------- included header files ---------------------- */
19 #include "config.h"
21 #include <stdio.h>
23 #include "libs/fvwmlib.h"
24 #include "libs/ColorUtils.h"
25 #include "libs/Cursor.h"
26 #include "libs/Parse.h"
27 #include "libs/Strings.h"
28 #include "fvwm.h"
29 #include "libs/PictureImageLoader.h"
30 #include "externs.h"
31 #include "cursor.h"
32 #include "functions.h"
33 #include "bindings.h"
34 #include "misc.h"
35 #include "screen.h"
36 #include "cursor.h"
37 #include "menus.h"
39 /* ---------------------------- local definitions -------------------------- */
41 /* ---------------------------- local macros ------------------------------- */
43 /* ---------------------------- imports ------------------------------------ */
45 /* ---------------------------- included code files ------------------------ */
47 /* ---------------------------- local types -------------------------------- */
49 /* ---------------------------- forward declarations ----------------------- */
51 /* ---------------------------- local variables ---------------------------- */
53 static Cursor cursors[CRS_MAX];
54 static const unsigned int default_cursors[CRS_MAX] =
56 None,
57 XC_top_left_corner, /* CRS_POSITION */
58 XC_top_left_arrow, /* CRS_TITLE */
59 XC_top_left_arrow, /* CRS_DEFAULT */
60 XC_hand2, /* CRS_SYS */
61 XC_fleur, /* CRS_MOVE */
62 XC_sizing, /* CRS_RESIZE */
63 XC_watch, /* CRS_WAIT */
64 XC_top_left_arrow, /* CRS_MENU */
65 XC_crosshair, /* CRS_SELECT */
66 XC_pirate, /* CRS_DESTROY */
67 XC_top_side, /* CRS_TOP */
68 XC_right_side, /* CRS_RIGHT */
69 XC_bottom_side, /* CRS_BOTTOM */
70 XC_left_side, /* CRS_LEFT */
71 XC_top_left_corner, /* CRS_TOP_LEFT */
72 XC_top_right_corner, /* CRS_TOP_RIGHT */
73 XC_bottom_left_corner, /* CRS_BOTTOM_LEFT */
74 XC_bottom_right_corner, /* CRS_BOTTOM_RIGHT */
75 XC_top_side, /* CRS_TOP_EDGE */
76 XC_right_side, /* CRS_RIGHT_EDGE */
77 XC_bottom_side, /* CRS_BOTTOM_EDGE */
78 XC_left_side, /* CRS_LEFT_EDGE */
79 XC_left_ptr, /* CRS_ROOT */
80 XC_plus /* CRS_STROKE */
83 /* ---------------------------- exported variables (globals) --------------- */
85 /* ---------------------------- local functions ---------------------------- */
87 static void SafeDefineCursor(Window w, Cursor cursor)
89 if (w)
91 XDefineCursor(dpy,w,cursor);
94 return;
97 /* ---------------------------- interface functions ------------------------ */
99 /* CreateCursors - Loads fvwm cursors */
100 Cursor *CreateCursors(Display *dpy)
102 int i;
103 /* define cursors */
104 cursors[0] = None;
105 for (i = 1; i < CRS_MAX; i++)
107 cursors[i] = XCreateFontCursor(dpy, default_cursors[i]);
110 return cursors;
113 /* ---------------------------- builtin commands --------------------------- */
115 void CMD_CursorStyle(F_CMD_ARGS)
117 char *cname=NULL;
118 char *newcursor=NULL;
119 char *errpos = NULL;
120 char *fore = NULL;
121 char *back = NULL;
122 XColor colors[2];
123 int index;
124 int nc;
125 int i;
126 int my_nc;
127 FvwmWindow *fw2;
128 Cursor cursor;
130 cursor = 0;
131 cname = PeekToken(action, &action);
132 if (!cname)
134 fvwm_msg(ERR, "CursorStyle", "Bad cursor style");
136 return;
138 if (StrEquals("POSITION", cname))
140 index = CRS_POSITION;
142 else if (StrEquals("DEFAULT", cname))
144 index = CRS_DEFAULT;
146 else if (StrEquals("SYS", cname))
148 index = CRS_SYS;
150 else if (StrEquals("TITLE", cname))
152 index = CRS_TITLE;
154 else if (StrEquals("MOVE", cname))
156 index = CRS_MOVE;
158 else if (StrEquals("RESIZE", cname))
160 index = CRS_RESIZE;
162 else if (StrEquals("MENU", cname))
164 index = CRS_MENU;
166 else if (StrEquals("WAIT", cname))
168 index = CRS_WAIT;
170 else if (StrEquals("SELECT", cname))
172 index = CRS_SELECT;
174 else if (StrEquals("DESTROY", cname))
176 index = CRS_DESTROY;
178 else if (StrEquals("LEFT", cname))
180 index = CRS_LEFT;
182 else if (StrEquals("RIGHT", cname))
184 index = CRS_RIGHT;
186 else if (StrEquals("TOP", cname))
188 index = CRS_TOP;
190 else if (StrEquals("BOTTOM", cname))
192 index = CRS_BOTTOM;
194 else if (StrEquals("TOP_LEFT", cname))
196 index = CRS_TOP_LEFT;
198 else if (StrEquals("TOP_RIGHT", cname))
200 index = CRS_TOP_RIGHT;
202 else if (StrEquals("BOTTOM_LEFT", cname))
204 index = CRS_BOTTOM_LEFT;
206 else if (StrEquals("BOTTOM_RIGHT", cname))
208 index = CRS_BOTTOM_RIGHT;
210 else if (StrEquals("LEFT_EDGE", cname))
212 index = CRS_LEFT_EDGE;
214 else if (StrEquals("RIGHT_EDGE", cname))
216 index = CRS_RIGHT_EDGE;
218 else if (StrEquals("TOP_EDGE", cname))
220 index = CRS_TOP_EDGE;
222 else if (StrEquals("BOTTOM_EDGE", cname))
224 index = CRS_BOTTOM_EDGE;
226 else if (StrEquals("ROOT", cname))
228 index = CRS_ROOT;
230 else if (StrEquals("STROKE", cname))
232 index = CRS_STROKE;
234 else
236 fvwm_msg(ERR, "CursorStyle", "Unknown cursor name %s", cname);
238 return;
240 cname = 0;
242 /* check if the cursor is given by X11 name */
243 action = GetNextToken(action, &newcursor);
244 if (newcursor)
246 my_nc = fvwmCursorNameToIndex(newcursor);
248 else
250 my_nc = default_cursors[index];
253 if (my_nc == -1)
255 nc = strtol(newcursor, &errpos, 10);
256 if (errpos && *errpos == '\0')
258 my_nc = 0;
261 else
263 nc = my_nc;
266 if (my_nc > -1)
268 /* newcursor was a number or the name of a X11 cursor */
269 if ((nc < 0) || (nc >= XC_num_glyphs) || ((nc % 2) != 0))
271 fvwm_msg(
272 ERR, "CursorStyle", "Bad cursor number %s",
273 newcursor);
274 free(newcursor);
276 return;
278 cursor = XCreateFontCursor(dpy, nc);
280 else
282 /* newcursor was not a number neither a X11 cursor name */
283 if (
284 StrEquals("none", newcursor) ||
285 StrEquals("tiny", newcursor))
287 XColor nccol;
289 XSetForeground(
290 dpy, Scr.MonoGC,
291 (tolower(*newcursor) == 'n') ? 0 : 1);
292 XFillRectangle(
293 dpy, Scr.ScratchMonoPixmap, Scr.MonoGC,
294 0, 0, 1, 1);
295 cursor = XCreatePixmapCursor(
296 dpy, Scr.ScratchMonoPixmap,
297 Scr.ScratchMonoPixmap, &nccol, &nccol, 0, 0);
299 else
301 char *path;
302 char *tmp;
303 int hotspot[2];
305 hotspot[0] = -1;
306 hotspot[1] = -1;
307 path = PictureFindImageFile(newcursor, NULL, R_OK);
308 if (!path)
310 fvwm_msg(
311 ERR, "CursorStyle",
312 "Cursor %s not found", newcursor);
313 free(newcursor);
315 return;
317 if (GetIntegerArguments(action, &tmp, hotspot, 2) == 2)
319 action = tmp;
321 cursor = PImageLoadCursorFromFile(
322 dpy, Scr.Root, path, hotspot[0], hotspot[1]);
323 free(path);
326 if (!cursor)
328 fvwm_msg(
329 ERR, "CursorStyle", "Cannot load cursor: %s",
330 newcursor);
331 free(newcursor);
333 return;
335 free(newcursor);
336 newcursor = 0;
338 /* replace the cursor defn */
339 if (Scr.FvwmCursors[index])
341 XFreeCursor(dpy, Scr.FvwmCursors[index]);
343 Scr.FvwmCursors[index] = cursor;
345 /* look for optional color arguments */
346 action = GetNextToken(action, &fore);
347 action = GetNextToken(action, &back);
348 if (fore && back)
350 colors[0].pixel = GetColor(fore);
351 colors[1].pixel = GetColor(back);
352 XQueryColors (dpy, Pcmap, colors, 2);
353 XRecolorCursor(
354 dpy, Scr.FvwmCursors[index], &(colors[0]),
355 &(colors[1]));
357 if (fore)
359 free(fore);
361 if (back)
363 free(back);
366 /* redefine all the windows using cursors */
367 for (fw2 = Scr.FvwmRoot.next; fw2; fw2 = fw2->next)
369 if (!HAS_HANDLES(fw2))
371 /* Ignore windows without handles */
372 continue;
374 for (i = 0; i < 4; i++)
376 SafeDefineCursor(
377 FW_W_CORNER(fw2, i),
378 Scr.FvwmCursors[CRS_TOP_LEFT + i]);
379 SafeDefineCursor(
380 FW_W_SIDE(fw2, i),
381 Scr.FvwmCursors[CRS_TOP + i]);
383 for (i = 0; i / 2 < Scr.nr_left_buttons; i += 2)
385 SafeDefineCursor(
386 FW_W_BUTTON(fw2, i), Scr.FvwmCursors[CRS_SYS]);
388 for (i = 1; i / 2 < Scr.nr_right_buttons; i += 2)
390 SafeDefineCursor(
391 FW_W_BUTTON(fw2, i), Scr.FvwmCursors[CRS_SYS]);
393 SafeDefineCursor(FW_W_TITLE(fw2), Scr.FvwmCursors[CRS_TITLE]);
394 if (index == CRS_DEFAULT)
396 SafeDefineCursor(
397 FW_W_FRAME(fw2), Scr.FvwmCursors[CRS_DEFAULT]);
398 SafeDefineCursor(
399 FW_W_PARENT(fw2), Scr.FvwmCursors[CRS_DEFAULT]);
400 if (IS_ICONIFIED(fw2))
402 if (!HAS_NO_ICON_TITLE(fw2))
404 SafeDefineCursor(
405 FW_W_ICON_TITLE(fw2),
406 Scr.FvwmCursors[CRS_DEFAULT]);
408 if (FW_W_ICON_PIXMAP(fw2) != None)
410 SafeDefineCursor(
411 FW_W_ICON_PIXMAP(fw2),
412 Scr.FvwmCursors[CRS_DEFAULT]);
418 /* Do the menus for good measure */
419 SetMenuCursor(Scr.FvwmCursors[CRS_MENU]);
421 SafeDefineCursor(Scr.PanFrameTop.win, Scr.FvwmCursors[CRS_TOP_EDGE]);
422 SafeDefineCursor(
423 Scr.PanFrameBottom.win, Scr.FvwmCursors[CRS_BOTTOM_EDGE]);
424 SafeDefineCursor(Scr.PanFrameLeft.win, Scr.FvwmCursors[CRS_LEFT_EDGE]);
425 SafeDefineCursor(
426 Scr.PanFrameRight.win, Scr.FvwmCursors[CRS_RIGHT_EDGE]);
427 /* migo (04/Nov/1999): don't annoy users which use xsetroot */
428 if (index == CRS_ROOT)
430 SafeDefineCursor(Scr.Root, Scr.FvwmCursors[CRS_ROOT]);
433 return;
436 /* Defines in which cases fvwm "grab" the cursor during execution of certain
437 * functions. */
438 void CMD_BusyCursor(F_CMD_ARGS)
440 char *option = NULL;
441 char *optstring = NULL;
442 char *args = NULL;
443 int flag = -1;
444 char *optlist[] = {
445 "read", "wait", "modulesynchronous", "dynamicmenu", "*", NULL
448 while (action && *action != '\0')
450 action = GetQuotedString(
451 action, &optstring, ",", NULL, NULL, NULL);
452 if (!optstring)
454 break;
457 args = GetNextToken(optstring, &option);
458 if (!option)
460 free(optstring);
461 break;
464 flag = ParseToggleArgument(args, NULL, -1, True);
465 free(optstring);
466 if (flag == -1)
468 fvwm_msg(ERR, "BusyCursor",
469 "error in boolean specification");
470 free(option);
471 break;
474 switch (GetTokenIndex(option, optlist, 0, NULL))
476 case 0: /* read */
477 if (flag)
479 Scr.BusyCursor |= BUSY_READ;
481 else
483 Scr.BusyCursor &= ~BUSY_READ;
485 break;
487 case 1: /* wait */
488 if (flag)
490 Scr.BusyCursor |= BUSY_WAIT;
492 else
494 Scr.BusyCursor &= ~BUSY_WAIT;
496 break;
498 case 2: /* modulesynchronous */
499 if (flag)
501 Scr.BusyCursor |= BUSY_MODULESYNCHRONOUS;
503 else
505 Scr.BusyCursor &= ~BUSY_MODULESYNCHRONOUS;
507 break;
509 case 3: /* dynamicmenu */
510 if (flag)
512 Scr.BusyCursor |= BUSY_DYNAMICMENU;
514 else
516 Scr.BusyCursor &= ~BUSY_DYNAMICMENU;
518 break;
520 case 4: /* "*" */
521 if (flag)
523 Scr.BusyCursor |= BUSY_ALL;
525 else
527 Scr.BusyCursor &= ~(BUSY_ALL);
529 break;
531 default:
532 fvwm_msg(ERR, "BusyCursor", "unknown context '%s'",
533 option);
534 break;
536 free(option);
539 return;