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
18 * This module is all original code
20 * Copyright 1993, Robert Nation
21 * You may use this code for any purpose, as long as the original
22 * copyright remains in the source code and all documentation
25 /* ---------------------------- included header files ---------------------- */
31 #include <X11/Xatom.h>
33 #include "libs/ftime.h"
34 #ifdef FVWM_DEBUG_TIME
35 #include <sys/times.h>
37 #include "libs/Parse.h"
38 #include "libs/Target.h"
41 #include "execcontext.h"
45 #include "module_interface.h"
47 #include "eventmask.h"
49 /* ---------------------------- local definitions -------------------------- */
51 /* ---------------------------- local macros ------------------------------- */
53 #define GRAB_EVMASK (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | \
54 PointerMotionMask | EnterWindowMask | LeaveWindowMask)
56 /* ---------------------------- imports ------------------------------------ */
58 /* ---------------------------- included code files ------------------------ */
60 /* ---------------------------- local types -------------------------------- */
62 /* ---------------------------- forward declarations ----------------------- */
64 /* ---------------------------- local variables ---------------------------- */
66 static int grab_count
[GRAB_MAXVAL
] = { 1, 1, 0, 0, 0, 0, 0 };
68 /* ---------------------------- exported variables (globals) --------------- */
70 /* ---------------------------- local functions ---------------------------- */
73 * Change the appearance of the grabbed cursor.
75 static void change_grab_cursor(int cursor
)
79 XChangeActivePointerGrab(
80 dpy
, GRAB_EVMASK
, Scr
.FvwmCursors
[cursor
], CurrentTime
);
86 /* ---------------------------- interface functions ------------------------ */
89 char *action
, int *val1
, int *val2
, int *val1_unit
, int *val2_unit
)
91 *val1_unit
= Scr
.MyDisplayWidth
;
92 *val2_unit
= Scr
.MyDisplayHeight
;
94 return GetTwoPercentArguments(action
, val1
, val2
, val1_unit
, val2_unit
);
99 * grab_context: GRAB_NORMAL, GRAB_BUSY, GRAB_MENU, GRAB_BUSYMENU,
101 * GRAB_STARTUP and GRAB_NONE are used at startup but are not made
102 * to be grab_context.
103 * GRAB_PASSIVE does not actually grab, but only delays the following ungrab
104 * until the GRAB_PASSIVE is released too.
108 void print_grab_stats(char *text
)
112 fprintf(stderr
,"grab_stats (%s):", text
);
113 for (i
= 0; i
< GRAB_MAXVAL
; i
++)
115 fprintf(stderr
," %d", grab_count
[i
]);
117 fprintf(stderr
," \n");
123 Bool
GrabEm(int cursor
, int grab_context
)
129 extern Window PressedW
;
131 if (grab_context
<= GRAB_STARTUP
|| grab_context
>= GRAB_MAXVAL
)
134 ERR
, "GrabEm", "Bug: Called with illegal context %d",
139 if (grab_context
== GRAB_PASSIVE
)
141 grab_count
[grab_context
]++;
142 grab_count
[GRAB_ALL
]++;
146 if (grab_count
[GRAB_ALL
] > grab_count
[GRAB_PASSIVE
])
148 /* already grabbed, just change the grab cursor */
149 if (grab_context
== GRAB_FREEZE_CURSOR
)
152 dpy
, (PressedW
!= None
) ?
153 PressedW
: Scr
.NoFocusWin
, True
,
154 GRAB_EVMASK
, GrabModeAsync
, GrabModeAsync
,
155 None
, Scr
.FvwmCursors
[CRS_DEFAULT
],
156 CurrentTime
) != GrabSuccess
)
162 grab_count
[grab_context
]++;
163 grab_count
[GRAB_ALL
]++;
164 if (grab_context
!= GRAB_BUSY
|| grab_count
[GRAB_STARTUP
] == 0)
166 change_grab_cursor(cursor
);
171 /* move the keyboard focus prior to grabbing the pointer to
172 * eliminate the enterNotify and exitNotify events that go
173 * to the windows. But GRAB_BUSY. */
174 switch (grab_context
)
177 if ( Scr
.Hilite
!= NULL
)
179 grab_win
= FW_W(Scr
.Hilite
);
185 /* retry to grab the busy cursor only once */
191 case GRAB_FREEZE_CURSOR
:
192 grab_win
= (PressedW
!= None
) ? PressedW
: Scr
.NoFocusWin
;
197 rep
= NUMBER_OF_GRAB_ATTEMPTS
;
204 dpy
, grab_win
, True
, GRAB_EVMASK
, GrabModeAsync
,
206 (grab_context
== GRAB_FREEZE_CURSOR
) ?
207 None
: Scr
.FvwmCursors
[cursor
], CurrentTime
) !=
212 case GrabInvalidTime
:
213 case GrabNotViewable
:
222 /* If you go too fast, other windows may not get a
223 * chance to release any grab that they have. */
225 if (grab_context
== GRAB_FREEZE_CURSOR
)
231 usleep(1000 * TIME_BETWEEN_GRAB_ATTEMPTS
);
238 /* If we fall out of the loop without grabbing the pointer, its
240 if (val
!= GrabSuccess
)
244 grab_count
[grab_context
]++;
245 grab_count
[GRAB_ALL
]++;
247 print_grab_stats("grabbed");
258 Bool
UngrabEm(int ungrab_context
)
260 if (ungrab_context
<= GRAB_ALL
|| ungrab_context
>= GRAB_MAXVAL
)
263 ERR
, "UngrabEm", "Bug: Called with illegal context %d",
268 if (grab_count
[ungrab_context
] == 0 || grab_count
[GRAB_ALL
] == 0)
270 /* context is not grabbed */
275 grab_count
[ungrab_context
]--;
276 grab_count
[GRAB_ALL
]--;
277 if (grab_count
[GRAB_ALL
] > 0)
279 int new_cursor
= None
;
281 /* there are still grabs left - switch grab cursor */
282 switch (ungrab_context
)
287 if (grab_count
[GRAB_BUSYMENU
] > 0)
289 new_cursor
= CRS_WAIT
;
291 else if (grab_count
[GRAB_BUSY
] > 0)
293 new_cursor
= CRS_WAIT
;
295 else if (grab_count
[GRAB_MENU
] > 0)
297 new_cursor
= CRS_MENU
;
305 /* switch back from busymenu cursor to normal menu
307 new_cursor
= CRS_MENU
;
313 if (grab_count
[GRAB_ALL
] > grab_count
[GRAB_PASSIVE
])
316 print_grab_stats("-restore");
318 change_grab_cursor(new_cursor
);
324 print_grab_stats("-ungrab");
326 XUngrabPointer(dpy
, CurrentTime
);
333 #ifndef fvwm_msg /* Some ports (i.e. VMS) define their own version */
335 ** fvwm_msg: used to send output from fvwm to files and or stderr/stdout
337 ** type -> DBG == Debug, ERR == Error, INFO == Information, WARN == Warning,
338 ** OLD == Command or option deprecated
339 ** id -> name of function, or other identifier
341 static char *fvwm_msg_strings
[] =
343 "<<DEBUG>> ", "", "", "<<WARNING>> ", "<<DEPRECATED>> ", "<<ERROR>> "
346 void fvwm_msg(fvwm_msg_t type
, char *id
, char *msg
, ...)
350 char time_str
[40] = "\0";
351 #ifdef FVWM_DEBUG_TIME
352 clock_t time_val
, time_taken
;
353 static clock_t start_time
= 0;
354 static clock_t prev_time
= 0;
355 struct tms not_used_tms
;
360 #ifdef FVWM_DEBUG_TIME
362 t_ptr
= localtime(&mytime
);
365 /* get clock ticks */
366 prev_time
= start_time
= (unsigned int)times(¬_used_tms
);
368 time_val
= (unsigned int)times(¬_used_tms
); /* get clock ticks */
369 time_taken
= time_val
- prev_time
;
370 prev_time
= time_val
;
371 sprintf(time_str
, "%.2d:%.2d:%.2d%7ld ",
372 t_ptr
->tm_hour
, t_ptr
->tm_min
, t_ptr
->tm_sec
, time_taken
);
375 strcpy(fvwm_id
, "fvwm");
376 if (Scr
.NumberOfScreens
> 1)
378 sprintf(&fvwm_id
[strlen(fvwm_id
)], ".%d", (int)Scr
.screen
);
381 fprintf(stderr
, "%s[%s][%s]: %s",
382 time_str
, fvwm_id
, id
, fvwm_msg_strings
[(int)type
]);
386 /* user echos must be printed as a literal string */
387 fprintf(stderr
, "%s", msg
);
392 vfprintf(stderr
, msg
, args
);
395 fprintf(stderr
, "\n");
399 /* I hate to use a fixed length but this will do for now */
400 char tmp
[2 * MAX_TOKEN_LENGTH
];
401 sprintf(tmp
, "[%s][%s]: %s",
402 fvwm_id
, id
, fvwm_msg_strings
[(int)type
]);
404 vsprintf(tmp
+ strlen(tmp
), msg
, args
);
406 tmp
[strlen(tmp
) + 1] = '\0';
407 tmp
[strlen(tmp
)] = '\n';
408 if (strlen(tmp
) >= MAX_MODULE_INPUT_TEXT_LEN
)
410 sprintf(tmp
+ MAX_MODULE_INPUT_TEXT_LEN
- 5, "...\n");
412 BroadcastName(M_ERROR
, 0, 0, 0, tmp
);
418 void fvwm_msg_report_app(void)
422 " If you are having a problem with the application, send a"
424 " with this message included to the application owner.\n"
425 " There is no need to notify fvwm-workers@fvwm.org.\n");
430 void fvwm_msg_report_app_and_workers(void)
434 " If you are having a problem with the application, send"
435 " a bug report with\n"
436 " this message included to the application owner and"
438 " fvwm-workers@fvwm.org.\n");
443 /* Store the last item that was added with '+' */
444 void set_last_added_item(last_added_item_t type
, void *item
)
446 Scr
.last_added_item
.type
= type
;
447 Scr
.last_added_item
.item
= item
;
452 /* some fancy font handling stuff */
453 void NewFontAndColor(FlocaleFont
*flf
, Pixel color
, Pixel backcolor
)
455 Globalgcm
= GCForeground
| GCBackground
;
459 Globalgcv
.font
= flf
->font
->fid
;
461 Globalgcv
.foreground
= color
;
462 Globalgcv
.background
= backcolor
;
463 XChangeGC(dpy
,Scr
.TitleGC
,Globalgcm
,&Globalgcv
);
471 * For menus, move, and resize operations, we can effect keyboard
472 * shortcuts by warping the pointer.
475 void Keyboard_shortcuts(
476 XEvent
*ev
, FvwmWindow
*fw
, int *x_defect
, int *y_defect
,
484 x_move_size
= fw
->hints
.width_inc
;
485 y_move_size
= fw
->hints
.height_inc
;
487 fvwmlib_keyboard_shortcuts(
488 dpy
, Scr
.screen
, ev
, x_move_size
, y_move_size
, x_defect
,
489 y_defect
, ReturnEvent
);
497 * Check if the given FvwmWindow structure still points to a valid window.
501 Bool
check_if_fvwm_window_exists(FvwmWindow
*fw
)
505 for (t
= Scr
.FvwmRoot
.next
; t
!= NULL
; t
= t
->next
)
513 /* rounds x down to the next multiple of m */
514 int truncate_to_multiple (int x
, int m
)
516 return (x
< 0) ? (m
* (((x
+ 1) / m
) - 1)) : (m
* (x
/ m
));
519 Bool
IsRectangleOnThisPage(const rectangle
*rec
, int desk
)
521 return (desk
== Scr
.CurrentDesk
&&
522 rec
->x
+ (signed int)rec
->width
> 0 &&
523 (rec
->x
< 0 || rec
->x
< Scr
.MyDisplayWidth
) &&
524 rec
->y
+ (signed int)rec
->height
> 0 &&
525 (rec
->y
< 0 || rec
->y
< Scr
.MyDisplayHeight
)) ?
529 /* returns the FvwmWindow that contains the pointer or NULL if none */
530 FvwmWindow
*get_pointer_fvwm_window(void)
538 dpy
, Scr
.Root
, &JunkRoot
, &win
, &JunkX
, &JunkY
,
539 &x
, &y
, &JunkMask
) == False
)
541 /* pointer is on a different screen */
544 for (t
= NULL
; win
!= Scr
.Root
&& win
!= None
; win
= ancestor
)
548 unsigned int nchildren
;
550 if (XFindContext(dpy
, win
, FvwmContext
, (caddr_t
*) &t
) !=
553 /* found a matching window context */
556 /* get next higher ancestor window */
559 dpy
, win
, &root
, &ancestor
, &children
, &nchildren
))
573 /* Returns the current X server time */
574 Time
get_server_time(void)
577 XSetWindowAttributes attr
;
579 /* add PropChange to NoFocusWin events */
580 attr
.event_mask
= PropertyChangeMask
;
581 XChangeWindowAttributes (dpy
, Scr
.NoFocusWin
, CWEventMask
, &attr
);
582 /* provoke an event */
584 dpy
, Scr
.NoFocusWin
, XA_WM_CLASS
, XA_STRING
, 8, PropModeAppend
,
586 FWindowEvent(dpy
, Scr
.NoFocusWin
, PropertyChangeMask
, &xev
);
587 attr
.event_mask
= XEVMASK_NOFOCUSW
;
588 XChangeWindowAttributes(dpy
, Scr
.NoFocusWin
, CWEventMask
, &attr
);
590 return xev
.xproperty
.time
;
593 void print_g(char *text
, rectangle
*g
)
595 fprintf(stderr
,"%s: ", (text
!= NULL
) ? text
: "");
598 fprintf(stderr
, "(null)\n");
602 fprintf(stderr
,"%4d %4d %4dx%4d (%4d - %4d, %4d - %4d)\n",
603 g
->x
, g
->y
, g
->width
, g
->height
,
604 g
->x
, g
->x
+ g
->width
, g
->y
, g
->y
+ g
->height
);