cdesktopenv/cde/programs/dtappbuilder/src/ab/x_util.c

846 lines
20 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* $XConsortium: x_util.c /main/3 1995/11/06 17:57:42 rswiston $
*
* @(#)x_util.c 1.21 21 Nov 1994 cde_app_builder/src/ab
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement between
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel without
* Sun's specific written approval. This document and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*/
/*
***********************************************************************
* x_util.c - X11 & Xt support functions
*
*
***********************************************************************
*/
#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <ab_private/util.h>
#include <ab_private/x_util.h>
#include <ab_private/ab.h>
#include "bitmaps/copy_cursor.xbm"
#include "bitmaps/move_cursor.xbm"
/*************************************************************************
** **
** Private Function Declarations **
** **
**************************************************************************/
static void box_gc_init(
Widget w,
Display *display,
Drawable drawable
);
static void fullscreen_gc_init(
Widget w,
Display *display,
Drawable drawable
);
static Bool expose_count_predicate(
Display *display,
XEvent *event,
XPointer arg
);
/*************************************************************************
** **
** Private Data **
** **
**************************************************************************/
static GC box_gc;
static GC fullscreen_gc;
static GC grid_gc;
/*************************************************************************
** **
** Public Data **
** **
**************************************************************************/
Pixmap AB_cp_cursor_pixmap, AB_mv_cursor_pixmap;
unsigned short AB_cp_cursor_height, AB_cp_cursor_width;
unsigned short AB_mv_cursor_height, AB_mv_cursor_width;
/*************************************************************************
** **
** Function Definitions **
** **
**************************************************************************/
/*
* Load all bitmaps to be used for cursors
*/
int
x_load_cursor_bitmaps(
Widget widget
)
{
if (!XtIsRealized(widget))
{
if (util_get_verbosity() > 0)
fprintf(stderr,"x_load_cursor_bitmaps: widget must be realized\n");
return ERROR;
}
AB_cp_cursor_height = copy_cursor_bm_height;
AB_cp_cursor_width = copy_cursor_bm_width;
AB_cp_cursor_pixmap = XCreatePixmapFromBitmapData(XtDisplay(widget),
XtWindow(widget),
(char*)copy_cursor_bm_bits,
AB_cp_cursor_width,
AB_cp_cursor_height,
BlackPixelOfScreen(XtScreen(widget)),
WhitePixelOfScreen(XtScreen(widget)),
1);
AB_mv_cursor_height = move_cursor_bm_height;
AB_mv_cursor_width = move_cursor_bm_width;
AB_mv_cursor_pixmap = XCreatePixmapFromBitmapData(XtDisplay(widget),
XtWindow(widget),
(char*)move_cursor_bm_bits,
AB_mv_cursor_width,
AB_mv_cursor_height,
BlackPixelOfScreen(XtScreen(widget)),
WhitePixelOfScreen(XtScreen(widget)),
1);
return OK;
}
/*
* return a cursor which is the image of the passed-in pixmap with
* a stencil around it
*/
Cursor
x_create_stencil_cursor(
Widget widget,
Pixmap pixmap,
unsigned short width,
unsigned short height,
unsigned int xhot,
unsigned int yhot
)
{
Display *dpy;
Window win;
Cursor cursor;
Pixmap cursor_pixmap, mask_pixmap;
unsigned short c_width, c_height;
unsigned int c_xhot, c_yhot;
unsigned int max_width, max_height;
static GC c_gc = NULL;
static XColor fg_color, bg_color;
int i, j;
if (!XtIsRealized(widget))
{
if (util_get_verbosity() > 0)
fprintf(stderr,"x_create_stencil_cursor: widget must be realized\n");
return NULL;
}
dpy = XtDisplay(widget);
win = XtWindow(widget);
c_width = width + 2;
c_height = height+ 2;
c_xhot = xhot;
c_yhot = yhot;
XQueryBestCursor(dpy, win, c_width, c_height, &max_width, &max_height);
if ( max_width < c_width)
c_width = max_width - 2;
if ( max_height < c_height)
c_height = max_height - 2;
if ((max_width - 2) < c_xhot)
c_xhot = max_width - 2;
if ((max_height - 2) < c_yhot)
c_yhot = max_height - 2;
cursor_pixmap = XCreatePixmap(dpy, win, c_width, c_height, 1);
mask_pixmap = XCreatePixmap(dpy, win, c_width, c_height, 1);
if (!c_gc)
{
XGCValues values;
XrmValue src, dst;
Pixel fg_pixel, bg_pixel;
/* For the mask, we set foreground to 1 directly */
values.foreground = 1;
values.background = 0;
c_gc = XCreateGC(dpy, cursor_pixmap, GCForeground|GCBackground, &values);
fg_pixel = BlackPixelOfScreen(XtScreen(widget));
bg_pixel = WhitePixelOfScreen(XtScreen(widget));
src.size = sizeof(Pixel);
src.addr = (XPointer)(&fg_pixel);
dst.size = sizeof(XColor);
dst.addr = (XPointer)&fg_color;
XtConvertAndStore(widget, XtRPixel, &src, XtRColor, &dst);
src.addr = (XPointer)&bg_pixel;
dst.addr = (XPointer)&bg_color;
XtConvertAndStore(widget, XtRPixel, &src, XtRColor, &dst);
}
XSetFunction(dpy, c_gc, GXclear);
XFillRectangle(dpy, mask_pixmap, c_gc, 0, 0, c_width, c_height);
XFillRectangle(dpy, cursor_pixmap, c_gc, 0, 0, c_width, c_height);
XSetFunction(dpy, c_gc, GXcopy);
XCopyArea(dpy, pixmap, cursor_pixmap, c_gc, 0, 0, c_width, c_height, 1, 1);
XSetFunction(dpy, c_gc, GXor);
/* Build a cursor mask_pixmap that is a stencil around the image */
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++)
{
x_graphics_op(dpy, mask_pixmap, c_gc, i, j,
c_width, c_height,
cursor_pixmap);
}
}
cursor = XCreatePixmapCursor(dpy, cursor_pixmap, mask_pixmap,
&fg_color, &bg_color, c_xhot, c_yhot);
XFreePixmap(dpy, mask_pixmap);
XFreePixmap(dpy, cursor_pixmap);
return(cursor);
}
void
x_graphics_op(
Display *dpy,
Drawable dest,
GC gc,
int x,
int y,
int width,
int height,
Pixmap src
)
{
XGCValues orig, changes;
unsigned long changes_mask = GCTileStipXOrigin |
GCTileStipYOrigin |
GCFillStyle;
/* Save original GC state */
XGetGCValues(dpy, gc, changes_mask, &orig);
changes.ts_x_origin = x;
changes.ts_y_origin = y;
changes.stipple = src;
changes.fill_style = FillOpaqueStippled;
XChangeGC(dpy, gc, changes_mask | GCStipple, &changes);
XFillRectangle(dpy, dest, gc, x, y, width, height);
/* Restore original GC state (all but stipple) */
XChangeGC(dpy, gc, changes_mask, &orig);
}
void
x_get_widget_rect(
Widget widget,
XRectangle *rect
)
{
XtVaGetValues(widget,
XtNwidth, (XtArgVal)&(rect->width),
XtNheight, (XtArgVal)&(rect->height),
XtNx, (XtArgVal)&(rect->x),
XtNy, (XtArgVal)&(rect->y),
NULL);
}
/*
* Figure out the total area occupied by two rects.
*/
void
x_get_rect_bounding(XRectangle *r1, XRectangle *r2)
{
XRectangle r;
if (rect_isnull(r1))
r = *r2;
else if (rect_isnull(r2))
r = *r1;
else {
r.x = min(r1->x, r2->x);
r.y = min(r1->y, r2->y);
r.width = max(r1->x + (short)r1->width, r2->x + (short)r2->width)
- r.x;
r.height = max(r1->y + (short)r1->height, r2->y + (short)r2->height)
- r.y;
}
*r1 = r;
}
void
x_adjust_rect_margin(
XRectangle *r,
int m
)
{
(r->x)-=m;
(r->y)-=m;
(r->width)+=(m+m);
(r->height)+=(m+m);
}
/*
* x_box
*/
void
x_box(
Widget widget,
Drawable drawable,
int x0,
int y0,
int x1,
int y1
)
{
Display *display;
int tmp;
/* Get display and drawable */
display = (Display *)XtDisplay(widget);
/* Initialize gc before use */
box_gc_init(widget, display, drawable);
/*
* Transpose the coordinates if either the
* width or height of the rectangle is negative.
*/
if (x1 - x0 < 0)
{
tmp = x0;
x0 = x1;
x1 = tmp;
}
if (y1 - y0 < 0)
{
tmp = y0;
y0 = y1;
y1 = tmp;
}
XDrawRectangle(display, drawable, box_gc, x0, y0, x1-x0, y1-y0);
}
/*
* x_box_r
*/
void
x_box_r(
Widget widget,
XRectangle *r
)
{
x_box(widget, XtWindow(widget), r->x, r->y, rect_right(r), rect_bottom(r));
}
/*
* x_dashed_box_r
*/
void
x_dashed_box_r(
Widget widget,
Drawable drawable,
XRectangle *r
)
{
Display *display;
/* Get display and drawable */
display = (Display *)XtDisplay(widget);
/* Initialize gc before use */
box_gc_init(widget, display, drawable);
/* Modify gc to used dashed lines */
XSetLineAttributes(display, box_gc,
0, LineOnOffDash, CapButt, JoinMiter);
XDrawRectangle(display, drawable, box_gc,
r->x, r->y, r->width -1, r->height -1);
/* Restore back to solid lines */
XSetLineAttributes(display, box_gc,
0, LineSolid, CapButt, JoinMiter);
}
void
x_fullscreen_box(
Widget w,
Drawable rootwin,
int x0,
int y0,
int x1,
int y1
)
{
Display *display;
int tmp;
display = XtDisplay(w);
fullscreen_gc_init(w, display, rootwin);
/*
* Transpose the coordinates if either the
* width or height of the rectangle is negative.
*/
if (x1 - x0 < 0)
{
tmp = x0;
x0 = x1;
x1 = tmp;
}
if (y1 - y0 < 0)
{
tmp = y0;
y0 = y1;
y1 = tmp;
}
XDrawRectangle(display, rootwin, fullscreen_gc,
x0, y0, x1 - x0, y1 - y0);
}
void
x_fullscreen_preview_box(
Widget w,
Drawable rootwin,
int x0,
int y0,
int x1,
int y1
)
{
Display *display;
int tmp;
display = XtDisplay(w);
/*
* Transpose the coordinates if either the
* width or height of the rectangle is negative.
*/
if (x1 - x0 < 0)
{
tmp = x0;
x0 = x1;
x1 = tmp;
}
if (y1 - y0 < 0)
{
tmp = y0;
y0 = y1;
y1 = tmp;
}
XDrawRectangle(display, rootwin, fullscreen_gc,
x0 - 1, y0 - 1, x1 - x0 + 2, y1 - y0 + 2);
}
/*
* Return black or white depending on the intensity of the background
* color. Intensity is calculated as I = 0.3*R + 0.59*G + 0.12*B.
*/
unsigned int
x_contrast_color(
Widget widget
)
{
XrmValue src, dst;
float intensity;
unsigned int bg_pixel;
XColor bg_color;
XtVaGetValues(widget, XtNbackground, &bg_pixel, NULL);
src.size = sizeof(Pixel);
src.addr = (XPointer)&bg_pixel;
dst.size = sizeof(XColor);
dst.addr = (XPointer)&bg_color;
XtConvertAndStore(widget, XtRPixel, &src, XtRColor, &dst);
intensity = ((float) bg_color.red * 0.3 + (float) bg_color.green * 0.59 +
(float) bg_color.blue * 0.12) / 255.0;
/*
fprintf(stderr,"x_contrast_color: %s : red(%d) green(%d) blue(%d) = intensity(%f)\n",
XtName(widget),bg_color.red, bg_color.green, bg_color.blue, intensity);
*/
if (intensity >= 90)
return BlackPixelOfScreen(XtScreen(widget));
else
return WhitePixelOfScreen(XtScreen(widget));
}
Boolean
x_widget_translate_xy(
Widget src,
XtPointer dst,
int src_x,
int src_y,
int *p_dst_x,
int *p_dst_y
)
{
Window src_win = XtWindow(src);
Window dst_win = dst? XtWindow((Widget)dst) : RootWindowOfScreen(XtScreen(src));
Window child;
return(XTranslateCoordinates(XtDisplay(src), src_win, dst_win,
src_x, src_y, p_dst_x, p_dst_y, &child));
}
Boolean
x_rootxy_inside_widget(
Widget w,
int rootx,
int rooty
)
{
Window root_win = RootWindowOfScreen(XtScreen(w));
XRectangle w_rect;
int w_x, w_y;
Window win_below;
if (XtIsRealized(w))
{
x_get_widget_rect(w, &w_rect);
XTranslateCoordinates(XtDisplay(w), XtWindow(w),
root_win, 0, 0, &w_x, &w_y, &win_below);
w_rect.x = (short)w_x;
w_rect.y = (short)w_y;
if (rect_includespoint(&w_rect, rootx, rooty))
return TRUE;
}
return FALSE;
}
/*
* box_gc_init
*/
static void
box_gc_init(
Widget widget,
Display *display,
Drawable drawable
)
{
XGCValues gc_val;
unsigned long cc_pixel = x_contrast_color(widget);
unsigned long bg_pixel;
XtVaGetValues(widget, XtNbackground, &bg_pixel, NULL);
/* If gc doesn't exist yet, create it */
if (!box_gc)
{
gc_val.foreground = bg_pixel ^ cc_pixel;
gc_val.function = GXxor;
box_gc = XCreateGC(display, drawable,
(GCFunction | GCForeground), &gc_val);
}
else
{
XSetForeground(display, box_gc, bg_pixel ^ cc_pixel);
}
}
/*
* fullscreen_gc_init
*/
static void
fullscreen_gc_init(
Widget widget,
Display *display,
Drawable drawable
)
{
XGCValues gc_val;
unsigned long cc_pixel = x_contrast_color(widget);
unsigned long bg_pixel;
XtVaGetValues(widget, XtNbackground, &bg_pixel, NULL);
/* If gc doesn't exist yet, create it */
if (!fullscreen_gc)
{
gc_val.foreground = bg_pixel ^ cc_pixel;
gc_val.function = GXxor;
gc_val.subwindow_mode = IncludeInferiors;
fullscreen_gc = XCreateGC(display, drawable,
(GCFunction|GCForeground|GCSubwindowMode), &gc_val);
}
else
{
XSetForeground(display, fullscreen_gc, bg_pixel ^ cc_pixel);
}
}
/*
* Return the X Window which is directly under the x,y position
* on the RootWindow
*/
Window
x_xwin_at_rootxy(
Widget widget,
int x,
int y,
int *dstx,
int *dsty
)
{
Display *dpy;
Window child;
Window rootwin, srcwin, dstwin;
dpy = XtDisplay(widget);
rootwin = RootWindowOfScreen(XtScreen(widget));
if (XTranslateCoordinates(dpy, rootwin, rootwin, x, y,
dstx, dsty, &child) == 0)
return ((Window) 0);
/*
* child is the XID of a child window of rootwin at
* root cordinates (x,y)
* If child is NULL, we dropped on the root window
*/
if (!child)
return ((Window) rootwin);
srcwin = rootwin;
x = *dstx;
y = *dsty;
dstwin = child;
for (;;)
{
if (XTranslateCoordinates(dpy, srcwin, dstwin, x, y,
dstx, dsty, &child) == 0)
return ((Window) 0);
if (!child)
break;
else
{
srcwin = dstwin;
dstwin = child;
x = *dstx;
y = *dsty;
}
}
return (dstwin);
}
void
x_conn_fullscreen_init(
Widget w,
Drawable root_win
)
{
Display *display;
display = XtDisplay(w);
fullscreen_gc_init(w, display, root_win);
/* Modify gc to used thick lines */
XSetLineAttributes(display, fullscreen_gc,
2, LineSolid, CapButt, JoinMiter);
}
/*
* Draw a line on the root window using fullscreen_gc
*/
void
x_conn_fullscreen_chord(
Widget w,
Drawable rootwin,
int x0,
int y0,
int x1,
int y1
)
{
Display *display;
int tmp;
display = XtDisplay(w);
XDrawLine(display, rootwin, fullscreen_gc, x0, y0, x1, y1);
}
void
x_conn_fullscreen_cleanup(
Widget w
)
{
/* Restore back to solid lines */
XSetLineAttributes(XtDisplay(w), fullscreen_gc,
0, LineSolid, CapButt, JoinMiter);
}
Cursor
x_create_cursor(
Widget widget,
Window root_win,
unsigned char bits[],
unsigned short width,
unsigned short height,
unsigned int xhot,
unsigned int yhot
)
{
Pixmap curs_pix;
Cursor cursor;
XColor fg_color;
XColor bg_color;
curs_pix = XCreateBitmapFromData(XtDisplay(widget), root_win, (char*)bits,
width, height);
if (curs_pix == None)
return(None);
{
XrmValue src, dst;
Pixel fg_pixel, bg_pixel;
fg_pixel = BlackPixelOfScreen(XtScreen(widget));
bg_pixel = WhitePixelOfScreen(XtScreen(widget));
src.size = sizeof(Pixel);
dst.size = sizeof(XColor);
src.addr = (XPointer)&fg_pixel;
dst.addr = (XPointer)&fg_color;
XtConvertAndStore(widget, XtRPixel, &src, XtRColor, &dst);
src.addr = (XPointer)&bg_pixel;
dst.addr = (XPointer)&bg_color;
XtConvertAndStore(widget, XtRPixel, &src, XtRColor, &dst);
}
cursor = XCreatePixmapCursor(XtDisplay(widget), curs_pix, curs_pix,
&fg_color, &bg_color, xhot, yhot);
XFreePixmap(XtDisplay(widget), curs_pix);
return(cursor);
}
/*
* Counts the number of expose events or events that could cause
* exposures currently waiting in the queue.
*
* note: THIS DOES NOT FLUSH THE OUTPUT QUEUE, SO OTHER EVENTS MAY
* BE PENDING ON THE CLIENT SIDE (USE XFlush() TO AVOID THIS)
*/
int
x_get_num_pending_expose_events(Display *display)
{
int num_expose_events = 0;
XEvent event;
XCheckIfEvent(display, &event,
expose_count_predicate, (XPointer)&num_expose_events);
return num_expose_events;
}
/*
* If we return True from this predicate function, the event will
* be removed from the queue. We don't want this to happen, so we
* will *always* return False, but increment the counter (the arg ptr)
* for each expose event.
*/
static Bool
expose_count_predicate(Display *display, XEvent *event, XPointer arg)
{
#define expose_count (*expose_count_out)
int *expose_count_out = (int *)arg;
switch (event->type)
{
case CreateNotify:
case DestroyNotify:
case Expose:
case GraphicsExpose:
case MapNotify:
case MapRequest:
case NoExpose:
case UnmapNotify:
case VisibilityNotify:
++expose_count;
break;
}
return False;
#undef expose_count
}