e16/src/draw.c

343 lines
8.6 KiB
C

/*
* Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
* Copyright (C) 2007-2020 Kim Woelders
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of the Software, its documentation and marketing & publicity
* materials, and acknowledgment shall be given in the documentation, materials
* and software packages that this Software was used.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <X11/Xlib.h>
#include "E.h"
#include "desktops.h"
#include "eobj.h"
#include "ewins.h"
#include "shapewin.h"
#include "xwin.h"
#define MR_MODES_MOVE 0x47 /* MR_OPAQUE through MR_BOX and MR_TECH_OPAQUE */
#define MR_MODES_RESIZE 0x47 /* MR_OPAQUE through MR_BOX and MR_TECH_OPAQUE */
static Font font = NoXID; /* Used in mode 1 (technical) */
static void
draw_h_arrow(EX_Drawable dr, GC gc, int x1, int x2, int y1)
{
char str[32];
if (x2 - x1 >= 12)
{
XDrawLine(disp, dr, gc, x1, y1, x1 + 6, y1 - 3);
XDrawLine(disp, dr, gc, x1, y1, x1 + 6, y1 + 3);
XDrawLine(disp, dr, gc, x2, y1, x2 - 6, y1 - 3);
XDrawLine(disp, dr, gc, x2, y1, x2 - 6, y1 + 3);
}
if (x2 >= x1)
{
XDrawLine(disp, dr, gc, x1, y1, x2, y1);
Esnprintf(str, sizeof(str), "%i", x2 - x1 + 1);
XDrawString(disp, dr, gc, (x1 + x2) / 2, y1 - 10, str, strlen(str));
}
}
static void
draw_v_arrow(EX_Drawable dr, GC gc, int y1, int y2, int x1)
{
char str[32];
if (y2 - y1 >= 12)
{
XDrawLine(disp, dr, gc, x1, y1, x1 + 3, y1 + 6);
XDrawLine(disp, dr, gc, x1, y1, x1 - 3, y1 + 6);
XDrawLine(disp, dr, gc, x1, y2, x1 + 3, y2 - 6);
XDrawLine(disp, dr, gc, x1, y2, x1 - 3, y2 - 6);
}
if (y2 >= y1)
{
XDrawLine(disp, dr, gc, x1, y1, x1, y2);
Esnprintf(str, sizeof(str), "%i", y2 - y1 + 1);
XDrawString(disp, dr, gc, x1 + 10, (y1 + y2) / 2, str, strlen(str));
}
}
void
do_draw_technical(EX_Drawable dr, GC gc,
int a, int b, int c, int d, int bl, int br, int bt, int bb)
{
if (!font)
font = XLoadFont(disp, "-*-helvetica-medium-r-*-*-10-*-*-*-*-*-*-*");
XSetFont(disp, gc, font);
if (c < 3)
c = 3;
if (d < 3)
d = 3;
draw_h_arrow(dr, gc, a + bl, a + bl + c - 1, b + bt + d - 16);
draw_h_arrow(dr, gc, 0, a - 1, b + bt + (d / 2));
draw_h_arrow(dr, gc, a + c + bl + br, WinGetW(VROOT) - 1, b + bt + (d / 2));
draw_v_arrow(dr, gc, b + bt, b + bt + d - 1, a + bl + 16);
draw_v_arrow(dr, gc, 0, b - 1, a + bl + (c / 2));
draw_v_arrow(dr, gc, b + d + bt + bb, WinGetH(VROOT) - 1, a + bl + (c / 2));
XDrawLine(disp, dr, gc, a, 0, a, WinGetH(VROOT));
XDrawLine(disp, dr, gc, a + c + bl + br - 1, 0,
a + c + bl + br - 1, WinGetH(VROOT));
XDrawLine(disp, dr, gc, 0, b, WinGetW(VROOT), b);
XDrawLine(disp, dr, gc, 0, b + d + bt + bb - 1,
WinGetW(VROOT), b + d + bt + bb - 1);
XDrawRectangle(disp, dr, gc, a + bl + 1, b + bt + 1, c - 3, d - 3);
}
static void
do_draw_boxy(EX_Drawable dr, GC gc,
int a, int b, int c, int d, int bl, int br, int bt, int bb)
{
if (c < 3)
c = 3;
if (d < 3)
d = 3;
XDrawRectangle(disp, dr, gc, a, b, c + bl + br - 1, d + bt + bb - 1);
XDrawRectangle(disp, dr, gc, a + bl + 1, b + bt + 1, c - 3, d - 3);
}
typedef struct {
EX_Window root;
GC gc;
int xo, yo, wo, ho;
int bl, br, bt, bb;
ShapeWin *shwin;
} ShapeData;
static void
_ShapeDrawNograb_tech_box(EWin * ewin, int md, int firstlast,
int xn, int yn, int wn, int hn)
{
ShapeData *psd = (ShapeData *) ewin->shape_data;
if (firstlast == 0 && !psd->shwin)
psd->shwin = ShapewinCreate(md);
if (!psd->shwin)
return;
ShapewinShapeSet(psd->shwin, md, xn, yn, wn, hn,
psd->bl, psd->br, psd->bt, psd->bb);
EoMap(psd->shwin, 0);
CoordsShow(ewin);
if (firstlast == 2)
{
ShapewinDestroy(psd->shwin);
psd->shwin = NULL;
}
}
typedef void (DrawFunc) (EX_Drawable dr, GC gc,
int a, int b, int c, int d,
int bl, int br, int bt, int bb);
static DrawFunc *const draw_functions[] = {
do_draw_technical, do_draw_boxy,
NULL, NULL,
NULL, do_draw_technical,
};
static void
_ShapeDrawNontranslucent(EWin * ewin, int md, int firstlast,
int xn, int yn, int wn, int hn)
{
ShapeData *psd = (ShapeData *) ewin->shape_data;
DrawFunc *drf;
if (firstlast == 0)
{
XGCValues gcv;
gcv.function = GXxor;
gcv.foreground = Dpy.pixel_white;
if (gcv.foreground == 0)
gcv.foreground = Dpy.pixel_black;
gcv.subwindow_mode = IncludeInferiors;
psd->gc = EXCreateGC(psd->root,
GCFunction | GCForeground | GCSubwindowMode, &gcv);
}
drf = draw_functions[md - 1];
if (firstlast > 0)
drf(psd->root, psd->gc, psd->xo, psd->yo, psd->wo, psd->ho,
psd->bl, psd->br, psd->bt, psd->bb);
CoordsShow(ewin);
if (firstlast < 2)
drf(psd->root, psd->gc, xn, yn, wn, hn,
psd->bl, psd->br, psd->bt, psd->bb);
if (firstlast == 2)
{
EXFreeGC(psd->gc);
psd->gc = NULL;
}
}
void
DrawEwinShape(EWin * ewin, int md, int x, int y, int w, int h, int firstlast)
{
ShapeData *psd;
int dx, dy;
/* Quit if no change */
if (firstlast == 1 &&
(x == ewin->shape_x && y == ewin->shape_y &&
(ewin->state.shaded || (w == ewin->shape_w && h == ewin->shape_h))))
return;
if ((md == MR_OPAQUE) || (md == MR_TECH_OPAQUE))
{
EwinOpMoveResize(ewin, OPSRC_USER, x, y, w, h);
EwinShapeSet(ewin);
CoordsShow(ewin);
if (md == MR_OPAQUE)
goto done;
}
if (firstlast == 0)
{
EwinShapeSet(ewin);
psd = (ShapeData *) ewin->shape_data;
if (!psd)
{
psd = ECALLOC(ShapeData, 1);
if (!psd)
goto done;
ewin->shape_data = psd;
psd->root = WinGetXwin(VROOT);
EwinBorderGetSize(ewin, &psd->bl, &psd->br, &psd->bt, &psd->bb);
}
}
psd = (ShapeData *) ewin->shape_data;
if (!psd)
goto done;
dx = EoGetX(EoGetDesk(ewin));
dy = EoGetY(EoGetDesk(ewin));
ewin->shape_x = x;
ewin->shape_y = y;
x += dx;
y += dy;
if (!ewin->state.shaded)
{
ewin->shape_w = w;
ewin->shape_h = h;
}
else
{
w = ewin->shape_w;
h = ewin->shape_h;
}
if (((md <= MR_BOX) || (md == MR_TECH_OPAQUE)) &&
Conf.movres.avoid_server_grab)
{
_ShapeDrawNograb_tech_box(ewin, md, firstlast, x, y, w, h);
goto done;
}
switch (md)
{
case MR_TECHNICAL:
case MR_TECH_OPAQUE:
case MR_BOX:
_ShapeDrawNontranslucent(ewin, md, firstlast, x, y, w, h);
break;
default:
/* Fall back to opaque mode */
Conf.movres.mode_move = MR_OPAQUE;
break;
}
psd->xo = x;
psd->yo = y;
psd->wo = w;
psd->ho = h;
done:
if (firstlast == 0 || firstlast == 2 || firstlast == 4)
{
ewin->req_x = ewin->shape_x;
ewin->req_y = ewin->shape_y;
if (firstlast == 2)
{
CoordsHide();
EFREE_NULL(ewin->shape_data);
}
}
}
void
DrawEwinShapeEnd(EWin * ewin)
{
ShapeData *psd = (ShapeData *) ewin->shape_data;
if (!psd)
return;
if (psd->shwin)
ShapewinDestroy(psd->shwin);
Efree(psd);
ewin->shape_data = NULL;
}
int
DrawEwinShapeNeedsGrab(int mode)
{
if (mode == MR_OPAQUE)
return 0;
if ((mode <= MR_BOX) || (mode == MR_TECH_OPAQUE))
return !Conf.movres.avoid_server_grab;
return 1;
}
static int
_MoveResizeModeValidate(unsigned int valid, int md)
{
if (md & ~0x1f)
return MR_OPAQUE;
if (valid & (1U << md))
return md;
return MR_OPAQUE;
}
int
MoveResizeModeValidateMove(int md)
{
return _MoveResizeModeValidate(MR_MODES_MOVE, md);
}
int
MoveResizeModeValidateResize(int md)
{
return _MoveResizeModeValidate(MR_MODES_RESIZE, md);
}