/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/****************************************************************************
* This module is all original code
* by Rob Nation
* Copyright 1993, Robert Nation
* You may use this code for any purpose, as long as the original
* copyright remains in the source code and all documentation
****************************************************************************/
/****************************************************************************
*
* Assorted odds and ends
*
**************************************************************************/
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
/* To add timing info to debug output, #define this: */
#ifdef FVWM_DEBUG_TIME
#include <sys/times.h>
#endif
#include "libs/fvwmlib.h"
#include "fvwm.h"
#include "externs.h"
#include "cursor.h"
#include "functions.h"
#include "bindings.h"
#include "misc.h"
#include "screen.h"
#include "module_interface.h"
#include "events.h"
#include "focus.h"
static unsigned int grab_count[GRAB_MAXVAL] = { 1, 1, 0, 0, 0, 0, 0 };
#define GRAB_EVMASK (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask)
int GetTwoArguments(char *action, int *val1, int *val2, int *val1_unit,
int *val2_unit)
{
*val1_unit = Scr.MyDisplayWidth;
*val2_unit = Scr.MyDisplayHeight;
return GetTwoPercentArguments(action, val1, val2, val1_unit, val2_unit);
}
/*****************************************************************************
* Change the appearance of the grabbed cursor.
****************************************************************************/
static void change_grab_cursor(int cursor)
{
if (cursor != None)
XChangeActivePointerGrab(
dpy, GRAB_EVMASK, Scr.FvwmCursors[cursor], CurrentTime);
return;
}
/*****************************************************************************
* Grab the pointer.
* grab_context: GRAB_NORMAL, GRAB_BUSY, GRAB_MENU, GRAB_BUSYMENU,
* GRAB_PASSIVE.
* GRAB_STARTUP and GRAB_NONE are used at startup but are not made
* to be grab_context.
* GRAB_PASSIVE does not actually grab, but only delays the following ungrab
* until the GRAB_PASSIVE is released too.
****************************************************************************/
#define DEBUG_GRAB 0
#if DEBUG_GRAB
void print_grab_stats(char *text)
{
int i;
fprintf(stderr,"grab_stats (%s):", text);
for (i = 0; i < GRAB_MAXVAL; i++)
fprintf(stderr," %d", grab_count[i]);
fprintf(stderr," \n");
return;
}
#endif
Bool GrabEm(int cursor, int grab_context)
{
int i = 0;
int val = 0;
int rep;
Window grab_win;
if (grab_context <= GRAB_STARTUP || grab_context >= GRAB_MAXVAL)
{
fvwm_msg(
ERR, "GrabEm", "Bug: Called with illegal context %d", grab_context);
return False;
}
if (grab_context == GRAB_PASSIVE)
{
grab_count[grab_context]++;
grab_count[GRAB_ALL]++;
return True;
}
if (grab_count[GRAB_ALL] > grab_count[GRAB_PASSIVE])
{
/* already grabbed, just change the grab cursor */
grab_count[grab_context]++;
grab_count[GRAB_ALL]++;
if (grab_context != GRAB_BUSY || grab_count[GRAB_STARTUP] == 0)
{
change_grab_cursor(cursor);
}
return True;
}
/* move the keyboard focus prior to grabbing the pointer to
* eliminate the enterNotify and exitNotify events that go
* to the windows. But GRAB_BUSY. */
switch (grab_context)
{
case GRAB_BUSY:
if ( Scr.Hilite != NULL )
grab_win = Scr.Hilite->w;
else
grab_win = Scr.Root;
/* retry to grab the busy cursor only once */
rep = 2;
break;
case GRAB_PASSIVE:
/* cannot happen */
return False;
default:
grab_win = Scr.Root;
rep = NUMBER_OF_GRAB_ATTEMPTS;
break;
}
XSync(dpy,0);
while((i < rep)&&
(val = XGrabPointer(
dpy, grab_win, True, GRAB_EVMASK, GrabModeAsync, GrabModeAsync,
None, Scr.FvwmCursors[cursor], CurrentTime) != GrabSuccess))
{
switch (val)
{
case GrabInvalidTime:
case GrabNotViewable:
/* give up */
i += rep;
break;
case GrabSuccess:
break;
case AlreadyGrabbed:
case GrabFrozen:
default:
/* If you go too fast, other windows may not get a change to release
* any grab that they have. */
usleep(1000 * TIME_BETWEEN_GRAB_ATTEMPTS);
i++;
break;
}
}
XSync(dpy,0);
/* If we fall out of the loop without grabbing the pointer, its
* time to give up */
if (val != GrabSuccess)
{
return False;
}
grab_count[grab_context]++;
grab_count[GRAB_ALL]++;
#if DEBUG_GRAB
print_grab_stats("grabbed");
#endif
return True;
}
/*****************************************************************************
*
* UnGrab the pointer
*
****************************************************************************/
Bool UngrabEm(int ungrab_context)
{
if (ungrab_context <= GRAB_ALL || ungrab_context >= GRAB_MAXVAL)
{
fvwm_msg(
ERR, "UngrabEm", "Bug: Called with illegal context %d", ungrab_context);
return False;
}
if (grab_count[ungrab_context] == 0 || grab_count[GRAB_ALL] == 0)
{
/* context is not grabbed */
return False;
}
XSync(dpy,0);
grab_count[ungrab_context]--;
grab_count[GRAB_ALL]--;
if (grab_count[GRAB_ALL] > 0)
{
int new_cursor = None;
/* there are still grabs left - switch grab cursor */
switch (ungrab_context)
{
case GRAB_NORMAL:
case GRAB_BUSY:
case GRAB_MENU:
if (grab_count[GRAB_BUSYMENU] > 0)
new_cursor = CRS_WAIT;
else if (grab_count[GRAB_BUSY] > 0)
new_cursor = CRS_WAIT;
else if (grab_count[GRAB_MENU] > 0)
new_cursor = CRS_MENU;
else
new_cursor = None;
break;
case GRAB_BUSYMENU:
/* switch back from busymenu cursor to normal menu cursor */
new_cursor = CRS_MENU;
break;
default:
new_cursor = None;
break;
}
if (grab_count[GRAB_ALL] > grab_count[GRAB_PASSIVE])
{
#if DEBUG_GRAB
print_grab_stats("-restore");
#endif
change_grab_cursor(new_cursor);
}
}
else
{
#if DEBUG_GRAB
print_grab_stats("-ungrab");
#endif
XUngrabPointer(dpy, CurrentTime);
}
XSync(dpy,0);
return True;
}
#ifndef fvwm_msg /* Some ports (i.e. VMS) define their own version */
/*
** fvwm_msg: used to send output from fvwm to files and or stderr/stdout
**
** type -> DBG == Debug, ERR == Error, INFO == Information, WARN == Warning
** id -> name of function, or other identifier
*/
static char *fvwm_msg_strings[] =
{ "<<DEBUG>>", "", "", "<<WARNING>>", "<<ERROR>>" };
void fvwm_msg(fvwm_msg_type type, char *id, char *msg, ...)
{
va_list args;
#ifdef FVWM_DEBUG_TIME
clock_t time_val, time_taken;
static clock_t start_time = 0;
static clock_t prev_time = 0;
struct tms not_used_tms;
char buffer[200]; /* oversized */
time_t mytime;
struct tm *t_ptr;
static int counter = 0;
#endif
#ifdef FVWM_DEBUG_TIME
time(&mytime);
t_ptr = localtime(&mytime);
if (start_time == 0) {
prev_time = start_time =
(unsigned int)times(¬_used_tms); /* get clock ticks */
}
time_val = (unsigned int)times(¬_used_tms); /* get clock ticks */
time_taken = time_val - prev_time;
prev_time = time_val;
sprintf(buffer, "%.2d:%.2d:%.2d %6ld",
t_ptr->tm_hour, t_ptr->tm_min, t_ptr->tm_sec, time_taken);
#endif
if (Scr.NumberOfScreens > 1)
{
fprintf(stderr,"[FVWM.%d][%s]: "
#ifdef FVWM_DEBUG_TIME
"%s "
#endif
"%s ",(int)Scr.screen,id,
#ifdef FVWM_DEBUG_TIME
buffer,
#endif
fvwm_msg_strings[(int)type]);
}
else
{
fprintf(stderr,"[FVWM][%s]: "
#ifdef FVWM_DEBUG_TIME
"%s "
#endif
"%s ",id,
#ifdef FVWM_DEBUG_TIME
buffer,
#endif
fvwm_msg_strings[(int)type]);
}
if (type == ECHO)
{
/* user echos must be printed as a literal string */
fprintf(stderr, "%s", msg);
}
else
{
va_start(args,msg);
vfprintf(stderr, msg, args);
va_end(args);
}
fprintf(stderr,"\n");
if (type == ERR)
{
/* I hate to use a fixed length but this will do for now */
char tmp[2 * MAX_TOKEN_LENGTH];
sprintf(tmp,"[FVWM][%s]: %s ",id, fvwm_msg_strings[(int)type]);
va_start(args,msg);
vsprintf(tmp+strlen(tmp), msg, args);
va_end(args);
tmp[strlen(tmp)+1]='\0';
tmp[strlen(tmp)]='\n';
if (strlen(tmp) >= MAX_MODULE_INPUT_TEXT_LEN)
sprintf(tmp + MAX_MODULE_INPUT_TEXT_LEN - 5, "...\n");
BroadcastName(M_ERROR,0,0,0,tmp);
}
} /* fvwm_msg */
#endif
/* Store the last item that was added with '+' */
void set_last_added_item(last_added_item_type type, void *item)
{
Scr.last_added_item.type = type;
Scr.last_added_item.item = item;
}
/* some fancy font handling stuff */
void NewFontAndColor(Font newfont, Pixel color, Pixel backcolor)
{
Globalgcv.font = newfont;
Globalgcv.foreground = color;
Globalgcv.background = backcolor;
Globalgcm = GCFont | GCForeground | GCBackground;
XChangeGC(dpy,Scr.TitleGC,Globalgcm,&Globalgcv);
}
/****************************************************************************
*
* For menus, move, and resize operations, we can effect keyboard
* shortcuts by warping the pointer.
*
****************************************************************************/
void Keyboard_shortcuts(
XEvent *Event, FvwmWindow *fw, int *x_defect, int *y_defect, int ReturnEvent)
{
int x_move_size = 0;
int y_move_size = 0;
if (fw)
{
x_move_size = fw->hints.width_inc;
y_move_size = fw->hints.height_inc;
}
fvwmlib_keyboard_shortcuts(
dpy, Scr.screen, Event, x_move_size, y_move_size, x_defect, y_defect,
ReturnEvent);
return;
}
/****************************************************************************
*
* Check if the given FvwmWindow structure still points to a valid window.
*
****************************************************************************/
Bool check_if_fvwm_window_exists(FvwmWindow *fw)
{
FvwmWindow *t;
for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
{
if (t == fw)
return True;
}
return False;
}
/* rounds x down to the next multiple of m */
int truncate_to_multiple (int x, int m)
{
return (x < 0) ? (m * (((x + 1) / m) - 1)) : (m * (x / m));
}
Bool IntersectsInterval(int x1, int width1, int x2, int width2)
{
return !(x1 + width1 <= x2 || x2 + width2 <= x1);
}
Bool IsRectangleOnThisPage(rectangle *rec, int desk)
{
return (desk == Scr.CurrentDesk &&
rec->x + rec->width > 0 &&
rec->x < Scr.MyDisplayWidth &&
rec->y + rec->height > 0 &&
rec->y < Scr.MyDisplayHeight) ?
True : False;
}
Bool move_into_rectangle(rectangle *move_rec, rectangle *target_rec)
{
Bool has_changed = False;
if (!IntersectsInterval(move_rec->x, move_rec->width,
target_rec->x, target_rec->width))
{
move_rec->x = move_rec->x % target_rec->width;
if (move_rec->x < 0)
{
move_rec->x += target_rec->width;
}
move_rec->x += target_rec->x;
has_changed = True;
}
if (!IntersectsInterval(move_rec->y, move_rec->height,
target_rec->y, target_rec->height))
{
move_rec->y = move_rec->y % target_rec->height;
if (move_rec->y < 0)
{
move_rec->y += target_rec->height;
}
move_rec->y += target_rec->y;
has_changed = True;
}
return has_changed;
}
Bool intersect_xrectangles(XRectangle *r1, XRectangle *r2)
{
int x1 = max(r1->x, r2->x);
int y1 = max(r1->y, r2->y);
int x2 = min(r1->x + r1->width, r2->x + r2->width);
int y2 = min(r1->y + r1->height, r2->y + r2->height);
r1->x = x1;
r1->y = y1;
r1->width = x2 - x1;
r1->height = y2 - y1;
if (x2 > x1 && y2 > y1)
return True;
else
return False;
}
syntax highlighted by Code2HTML, v. 0.9.1