1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 12:28:22 +01:00
Files
wmaker/WINGs/wframe.c
David Maciejak 2a14004fc3 SwitchPanel: make sure WMRetainColor and WMReleaseColor calls are even
The number of calls to WMRetainColor for a color in use should the same as the number of calls to WMReleaseColor
to free that color. In case of discrepancy, random crashes can happen and memory is not freed properly.
To debug that issue I checked the retained colors when the switchpanel is opened and then checked if those colors are properly released once the panel is closed.

This patch fixes the issue mentioned at https://github.com/window-maker/wmaker/issues/22
2023-02-10 11:24:55 +00:00

264 lines
5.1 KiB
C

#include "WINGsP.h"
typedef struct W_Frame {
W_Class widgetClass;
W_View *view;
char *caption;
WMColor *textColor;
struct {
WMReliefType relief:4;
WMTitlePosition titlePosition:4;
} flags;
} Frame;
#define DEFAULT_RELIEF WRGroove
#define DEFAULT_TITLE_POSITION WTPAtTop
#define DEFAULT_WIDTH 40
#define DEFAULT_HEIGHT 40
static void destroyFrame(Frame * fPtr);
static void paintFrame(Frame * fPtr);
static void repaintFrame(Frame * fPtr);
void WMSetFrameTitlePosition(WMFrame * fPtr, WMTitlePosition position)
{
fPtr->flags.titlePosition = position;
if (fPtr->view->flags.realized) {
repaintFrame(fPtr);
}
}
void WMSetFrameRelief(WMFrame * fPtr, WMReliefType relief)
{
fPtr->flags.relief = relief;
if (fPtr->view->flags.realized) {
repaintFrame(fPtr);
}
}
void WMSetFrameTitle(WMFrame * fPtr, const char *title)
{
if (fPtr->caption)
wfree(fPtr->caption);
if (title)
fPtr->caption = wstrdup(title);
else
fPtr->caption = NULL;
if (fPtr->view->flags.realized) {
repaintFrame(fPtr);
}
}
static void repaintFrame(Frame * fPtr)
{
W_View *view = fPtr->view;
W_Screen *scrPtr = view->screen;
XClearWindow(scrPtr->display, view->window);
paintFrame(fPtr);
}
static void paintFrame(Frame * fPtr)
{
W_View *view = fPtr->view;
W_Screen *scrPtr = view->screen;
WMFont *font = scrPtr->normalFont;
Display *display = scrPtr->display;
int tx, ty, tw, th, tlen;
int fy, fh;
Bool drawTitle;
if (fPtr->caption != NULL) {
th = WMFontHeight(font);
tlen = strlen(fPtr->caption);
} else {
th = 0;
tlen = 0;
}
switch (fPtr->flags.titlePosition) {
case WTPAboveTop:
ty = 0;
fy = th + 4;
fh = view->size.height - fy;
break;
case WTPAtTop:
ty = 0;
fy = th / 2;
fh = view->size.height - fy;
break;
case WTPBelowTop:
ty = 4;
fy = 0;
fh = view->size.height;
break;
case WTPAboveBottom:
ty = view->size.height - th - 4;
fy = 0;
fh = view->size.height;
break;
case WTPAtBottom:
ty = view->size.height - th;
fy = 0;
fh = view->size.height - th / 2;
break;
case WTPBelowBottom:
ty = view->size.height - th;
fy = 0;
fh = view->size.height - th - 4;
break;
default:
ty = 0;
fy = 0;
fh = view->size.height;
}
if (tlen > 0 && fPtr->flags.titlePosition != WTPNoTitle) {
tw = WMWidthOfString(font, fPtr->caption, tlen);
tx = (view->size.width - tw) / 2;
drawTitle = True;
} else {
tw = tx = 0;
drawTitle = False;
}
{
XRectangle rect;
Region region, tmp;
GC gc[4];
int i;
region = XCreateRegion();
rect.x = 0;
rect.y = 0;
rect.width = view->size.width;
rect.height = view->size.height;
XUnionRectWithRegion(&rect, region, region);
if (drawTitle) {
tmp = XCreateRegion();
rect.x = tx;
rect.y = ty;
rect.width = tw;
rect.height = th;
XUnionRectWithRegion(&rect, tmp, tmp);
XSubtractRegion(region, tmp, region);
XDestroyRegion(tmp);
}
gc[0] = WMColorGC(scrPtr->black);
gc[1] = WMColorGC(scrPtr->darkGray);
gc[2] = WMColorGC(scrPtr->gray);
gc[3] = WMColorGC(scrPtr->white);
for (i = 0; i < 4; i++) {
XSetRegion(display, gc[i], region);
}
XDestroyRegion(region);
W_DrawReliefWithGC(scrPtr, view->window, 0, fy, view->size.width, fh,
fPtr->flags.relief, gc[0], gc[1], gc[2], gc[3]);
for (i = 0; i < 4; i++) {
XSetClipMask(display, gc[i], None);
}
}
if (drawTitle) {
/* can't draw AA text over and over again because it gets messed */
/* // TODO create the dbl buffer pixmap when create/set frame title */
if (scrPtr->antialiasedText) {
Drawable d;
d = XCreatePixmap(display, view->window, tw, th, scrPtr->depth);
XFillRectangle(display, d, WMColorGC(view->backColor), 0, 0, tw, th);
WMDrawString(scrPtr, d, fPtr->textColor ? fPtr->textColor : scrPtr->black, font, 0, 0, fPtr->caption, tlen);
XCopyArea(display, d, view->window, scrPtr->copyGC, 0, 0, tw, th, tx, ty);
XFreePixmap(display, d);
} else {
WMDrawString(scrPtr, view->window, scrPtr->black, font, tx, ty, fPtr->caption, tlen);
}
}
}
static void handleEvents(XEvent * event, void *data)
{
Frame *fPtr = (Frame *) data;
CHECK_CLASS(data, WC_Frame);
switch (event->type) {
case Expose:
if (event->xexpose.count == 0)
paintFrame(fPtr);
break;
case DestroyNotify:
destroyFrame(fPtr);
break;
}
}
void WMSetFrameTitleColor(WMFrame *fPtr, WMColor *color)
{
if (fPtr->textColor)
WMReleaseColor(fPtr->textColor);
fPtr->textColor = WMRetainColor(color);
if (fPtr->view->flags.realized) {
repaintFrame(fPtr);
}
}
WMFrame *WMCreateFrame(WMWidget * parent)
{
Frame *fPtr;
fPtr = wmalloc(sizeof(Frame));
fPtr->widgetClass = WC_Frame;
fPtr->view = W_CreateView(W_VIEW(parent));
if (!fPtr->view) {
wfree(fPtr);
return NULL;
}
fPtr->view->self = fPtr;
fPtr->textColor = WMRetainColor(fPtr->view->screen->black);
WMCreateEventHandler(fPtr->view, ExposureMask | StructureNotifyMask, handleEvents, fPtr);
fPtr->flags.relief = DEFAULT_RELIEF;
fPtr->flags.titlePosition = DEFAULT_TITLE_POSITION;
WMResizeWidget(fPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT);
return fPtr;
}
static void destroyFrame(Frame * fPtr)
{
if (fPtr->textColor)
WMReleaseColor(fPtr->textColor);
if (fPtr->caption)
wfree(fPtr->caption);
wfree(fPtr);
}