X Toolkit: heap is growing when recreating widgets - c

I'm trying to understand why the following program is leaking memory. When I look at the heap size by using the command more /proc/<pid>/smaps, I can see that the heap is only growing. It seems that the XtDestroyWidget is not really freeing up the memory. I would be very grateful if somebody can tell me why this is happening and show me the right way of recreating widgets.
Thanks in advance!
/* Compile on Solaris: cc widgets_mem.c -lXm -lXt -lX11 */
/* Compile on Linux: gcc -m32 widgets_mem.c -lXm -lXt -lX11 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysymdef.h>
#include <Xm/MainW.h>
#include <Xm/PushB.h>
#include <Xm/Form.h>
Widget toplevel;
Widget w_main;
Widget w_bb;
Widget w_button = NULL;
Window root_win;
XtAppContext app;
int screen_number;
Display *display = NULL;
void recreateWidgets ()
{
printf ("recreating widgets\n");
XtDestroyWidget (w_button);
w_button = XtVaCreateManagedWidget (
"button",
xmPushButtonWidgetClass, w_bb,
XmNfillOnArm, False,
XmNhighlightThickness, 0,
XmNborderWidth, 1,
XmNmarginTop, 1,
XmNmarginWidth, 2,
XmNmarginHeight, 0,
XmNwidth, 20,
XmNheight, 10,
XmNrecomputeSize, False,
XmNalignment, XmALIGNMENT_CENTER,
NULL);
}
void main (int argc, char **argv)
{
XEvent event;
toplevel = XtVaAppInitialize (&app, "Mem leak test",
NULL, 0, &argc, argv, NULL, NULL);
display = XtDisplay (toplevel);
screen_number = DefaultScreen (display);
root_win = RootWindow (display, screen_number);
w_main = XtVaCreatePopupShell (
"main",
topLevelShellWidgetClass, toplevel,
XmNgeometry, "-0+0",
XmNborderWidth, 0,
XmNshadowThickness, 0,
XmNminWidth, 1,
XmNmwmDecorations, 0,
XmNmwmFunctions, 0,
XmNwidth, 600,
XmNheight, 200,
NULL);
w_bb = XtVaCreateManagedWidget (
"",
xmBulletinBoardWidgetClass, w_main,
XmNborderWidth, 4,
XmNshadowThickness, 0,
XmNmarginWidth, 0,
XmNmarginHeight, 0,
XmNx, 0,
XmNy, 0,
XmNwidth, 500,
XmNheight, 100,
NULL);
w_button = XtVaCreateManagedWidget (
"button",
xmPushButtonWidgetClass, w_bb,
XmNfillOnArm, False,
XmNhighlightThickness, 0,
XmNborderWidth, 1,
XmNmarginTop, 1,
XmNmarginWidth, 2,
XmNmarginHeight, 0,
XmNwidth, 20,
XmNheight, 10,
XmNrecomputeSize, False,
XmNalignment, XmALIGNMENT_CENTER,
NULL);
XtPopup (w_main, XtGrabNone);
while (1)
{
XtAppNextEvent (app, &event);
if (event.type == ButtonPress)
{
printf ("Button pressed, recreating widgets\n");
recreateWidgets();
}
}
}

I found the bug in my code: I had to add a XtDispatchEvent(&event), which handles the deallocating of the widgets which are on the destory list, an internal list in Xt.

Related

C SDL2 write text to canvas segmentation fault

I'm trying to use C to create a webassembly program to write text to an HTML5 canvas. I'm getting a segfault.
I've been looking at this tutorial: https://lyceum-allotments.github.io/2016/06/emscripten-and-sdl2-tutorial-part-6-write-owl/
This is my main.c file:
#include <stdio.h>
#include <SDL2/SDL.h>
#include <emscripten.h>
#include <stdlib.h>
#include <math.h>
#include <SDL2/SDL_ttf.h>
/**
* A Context structure that can be used to pass variables into the loop
*/
//
struct Context {
SDL_Renderer *renderer;
int iteration;
// Rectangle that texture will be rendered into
TTF_Font *font;
SDL_Texture *text_texture;
} Context;
/**
* size of the canvas in pixels
*/
const int WINDOW_WIDTH = 1600;
const int WINDOW_HEIGHT = 420;
void set_font_text(struct Context *ctx, const char *text) {
SDL_Color fg = {0,0,0,255};
SDL_Surface *text_surface = TTF_RenderText_Blended(ctx->font, text, fg);
ctx->text_texture = SDL_CreateTextureFromSurface(ctx->renderer, text_surface);
SDL_FreeSurface(text_surface);
SDL_DestroyTexture(ctx->text_texture);
}
int get_font_texture(struct Context *ctx) {
ctx->font = TTF_OpenFont("assets/fonts/Alef-Regular.ttf", 30);
set_font_text(ctx, "NEIL DU TOIT");
TTF_CloseFont(ctx->font);
TTF_Quit();
return 1;
}
/**
* The loop handler, will be called repeatedly
*/
void mainLoop(void *arg) {
struct Context *ctx = arg;
// Set background color and clear canvas
SDL_SetRenderDrawColor(ctx->renderer, 100, 143, 154, 255);
SDL_RenderClear(ctx->renderer);
SDL_Rect text_dest = {.x = 50, .y = 175, .w = 0, .h = 0};
SDL_QueryTexture(ctx->text_texture, NULL, NULL, &text_dest.w, &text_dest.h);
SDL_RenderCopy(ctx->renderer, ctx->text_texture, NULL, &text_dest);
SDL_RenderPresent(ctx->renderer);
}
int main() {
SDL_Window *window;
struct Context ctx;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &ctx.renderer);
SDL_SetRenderDrawColor(ctx.renderer, 255, 143, 154, 255);
get_font_texture(&ctx);
ctx.iteration = 0;
int infinite_loop = 1;
int fps = -1;
emscripten_set_main_loop_arg(mainLoop, &ctx, fps, infinite_loop);
SDL_DestroyRenderer(ctx.renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
Comiled using:
emcc main.c -s USE_SDL=2 -s WASM=1 -s USE_SDL_TTF=2 -O3 -o main.js
and served with:
python3 -m http.server 8000
When opened I immediately see:
If I remove the call to set_font_text the error goes away (but I don't see any text of course)
What's going wrong?

Mouse move and click in C / linux X11

I need to move pointer and perform a click. It is moving ok but the click are not working, can anyone see what I'm missing? Code is below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
int main(int argc, char *argv[]){
Display *dpy;
Window root_window;
dpy = XOpenDisplay(0);
root_window = XRootWindow(dpy, 0);
XSelectInput(dpy, root_window, KeyReleaseMask);
XWarpPointer(dpy, None, root_window, 0, 0, 0, 0, 180, 500);
XGrabPointer(dpy, root_window, True, ButtonPressMask, GrabModeAsync,GrabModeAsync, None, None, CurrentTime);
XFlush(dpy);
return 0;
}

Basic C SDL2 program won't work with TCC while it does work with GCC (Linux)

I have the following C code (for clarity, I know it's not complete code and it should handle events and stuff like that):
#!/usr/bin/tcc -run -L/usr/lib/x86_64-linux-gnu -D_REENTRANT -DSDL_MAIN_HANDLED -I/usr/include/SDL2 -lSDL2 -lGL -lGLEW
#include <GL/glew.h>
#include <SDL.h>
int main(int argc, char **argv)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_Window *win = SDL_CreateWindow("Hello World!", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
SDL_GLContext glContext = SDL_GL_CreateContext(win);
while (1)
{
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(win);
}
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(win);
return 0;
}
If I compile this with GCC (without the shebang line), and start the executable, it works fine, but I like the simplicity of the compile and run functionality of TCC and its speed.
However, the compiled executable gives me the following console output and then hangs forever and can't even be killed with CTRL-C:
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
I added the SDL_MAIN_HANDLED as suggested here but that didn't change anything.
Anyone?
How about proper handling of the possible errors of the SDL calls and also initializing glew?
#include <stdlib.h>
#include <SDL.h>
#include <GL/glew.h>
void exit_sdl_error(const char *message) {
SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "%s failed with SDL error %s", message, SDL_GetError());
exit(EXIT_FAILURE);
}
int main() {
const Uint32 init_flags = SDL_INIT_VIDEO;
const int gl_major = 4, gl_minor = 0;
if (!SDL_WasInit(init_flags)) {
if (SDL_Init(init_flags) != 0)
exit_sdl_error("Unable to initialize SDL");
if (SDL_InitSubSystem(init_flags) != 0)
exit_sdl_error("Unable to initialize sub system of SDL");
}
if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, gl_major))
exit_sdl_error("Unable to set gl major version");
if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, gl_minor))
exit_sdl_error("Unable to set gl minor version");
if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE))
exit_sdl_error("Unable to set gl profile");
SDL_Window *window = SDL_CreateWindow("Hello World!", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (!window) {
SDL_QuitSubSystem(init_flags);
exit_sdl_error("Unable to create window");
}
SDL_GLContext glContext = SDL_GL_CreateContext(window);
if (!glContext) {
SDL_DestroyWindow(window);
SDL_QuitSubSystem(init_flags);
exit_sdl_error("Unable to create context");
}
glewInit();
while (1)
{
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(window);
}
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(window);
SDL_QuitSubSystem(init_flags);
}

How to correctly refresh SDL2 window after resizing

I wrote a little SDL2 app that reacts on resizing by rearranging its contents. It works quite nice on Windows 10, but not on my Linux machine.
Here's the MCVE that (hopefully) reproduces the problem:
#include <SDL2/SDL.h>
int main(int argc, char **argv)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *w = SDL_CreateWindow("MCVE",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 250, 250,
SDL_WINDOW_ALLOW_HIGHDPI|SDL_WINDOW_RESIZABLE);
SDL_Renderer *r = SDL_CreateRenderer(w, -1, SDL_RENDERER_ACCELERATED);
SDL_Surface *shape = SDL_CreateRGBSurface(0, 500, 500, 32, 0, 0, 0, 0);
SDL_Rect rect = { .x = 100, .y = 100, .h = 300, .w = 300 };
SDL_FillRect(shape, &rect, SDL_MapRGB(shape->format, 0xff, 0, 0));
SDL_Texture *t = SDL_CreateTextureFromSurface(r, shape);
SDL_RenderClear(r);
SDL_RenderCopy(r, t, 0, 0);
SDL_RenderPresent(r);
SDL_Event ev;
while (SDL_WaitEvent(&ev))
{
switch (ev.type)
{
case SDL_QUIT:
SDL_Quit();
return 0;
case SDL_WINDOWEVENT:
if (ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
SDL_RenderClear(r);
SDL_RenderCopy(r, t, 0, 0);
SDL_RenderPresent(r);
}
}
}
return 1;
}
compile command:
gcc -std=c11 -Wall -Wextra -Wno-unused-parameter -pedantic -osdlresize sdlresize.c -lSDL2main -lSDL2
Note any error checking and cleanup is skipped just for brevity, the real code is here for reference.
What I get on my Linux machine when resizing the window often looks like this:
In case you can't see the image: the content isn't properly refreshed, it shows some area to the right and the bottom with contents of whatever is below my window on the desktop.
Is there anything wrong in my handling of the SDL_WINDOWEVENT_SIZE_CHANGED? The same thing happens if I handle SDL_WINDOWEVENT_RESIZED instead...

SDL2 - How to render with one buffer instead of two?

In SDL2 I want to be able to draw changes to one buffer rather than redraw the whole image to two different buffers as my setup seems to be doing. Below is a really quick test which shows the unwanted behavior:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <SDL.h>
// Compile: gcc test.c -I/usr/local/include/SDL2 -L/usr/local/lib -lSDL2
void putPixel(SDL_Renderer *renderer, int x, int y)
{
SDL_SetRenderDrawColor(renderer, 255,255,255,255);
SDL_RenderDrawPoint(renderer, x, y);
}
int main(int argc, char* argv[]) {
int width = 640;
int height = 480;
SDL_Window *window = SDL_CreateWindow("Test", 0,0,width,height, 0);
if (window == NULL)
{
return -1;
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL)
{
return -2;
}
SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
for(int x=0;x<8;x++)
{
for(int y=0;y<10;y++)
{
putPixel(renderer,40+x*10,50+y);
}
SDL_RenderPresent(renderer);
sleep(1);
}
SDL_Quit();
return 0;
}
The output from this is two alternating screens. It is obviously using a double buffer which means I have to clear and redraw to get the output I want. After each cycle of the for...loop I wanted to add a line to the buffer - there should have been 8 lines at the end of the program running. In this case I got 4 on one buffer and 4 on another. I don't want to redraw the previous lines again either, hence the need for one buffer:
This uses a texture as a buffer and copies this to the screen when done.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <SDL.h>
// Compile: gcc test.c -I/usr/local/include/SDL2 -L/usr/local/lib -lSDL2
void putPixel(SDL_Renderer *renderer, int x, int y)
{
SDL_SetRenderDrawColor(renderer, 255,255,255,255);
SDL_RenderDrawPoint(renderer, x, y);
}
int main(int argc, char* argv[]) {
int width = 640;
int height = 480;
SDL_Window *window = SDL_CreateWindow("Test", 0,0,width,height, 0);
if (window == NULL)
{
return -1;
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
if (renderer == NULL)
{
return -2;
}
SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_BLEND);
/* Create texture for display */
SDL_Texture *display = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
SDL_SetRenderTarget(renderer, display);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
for(int x=0;x<8;x++)
{
SDL_SetRenderTarget(renderer, display);
for(int y=0;y<10;y++)
{
putPixel(renderer,40+x*10,50+y);
}
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, display, NULL, NULL);
SDL_RenderPresent(renderer);
sleep(1);
}
SDL_Quit();
return 0;
}
The output from this is below:

Resources