A Place Where No Dreams Come True...

Current Project: A very simple X11 progress/meter bar graph implementation with no external dependencies. It additionally supports a centered title commonly used to add time information to the display (progress).

What Does This Code Do...

Implements X11 Progress/Meter (bar-graph) class window. Additionally there is support for a, centered, text-field (title) which I commonly use for displaying progress time. This window class responds only to change-requests from a parent (owner) window.

What Doesn't This Code Do...

Although dynamically resettable, the initial theme is hardcoded. Eventually I hope to create a set of Window-Manager Property definitions to handle themeing. Finally some of the constants in the drawing routines need to be made runtime-selectable and probably some additional features should be added.

//-----------------------------------------------------------------------------
// progress.c
//
//  X11 progress-bar implementation.
//
// Copyright (c) 2013 - No Fun Farms A.K.A. www.smegware.com
//
//  All Smegware software is free; 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 software 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.
//
//-----------------------------------------------------------------------------
//
// History...
//
//   $Source$
//   $Author$
// $Revision$
//
// $Log$
//
//-----------------------------------------------------------------------------

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdlib.h>
#include <string.h>

#include "progress.h"
#include "report.h"
#include "xwinatom.h"
#include "xwinhlpr.h"

#define defprgSizeBorder 1
#define defprgBorder 0x00000000
#define defprgFace 0xFFB0B080
#define defprgProgress 0xFFC0C000
#define defprgHilite 0xFFC0C0C0
#define defprgShadow 0xFF606060
#define defprgText 0x00000000
#define defprgBackground 0x00000000

struct _progress {
  Display      *display;
  Window        parent;
  Window        window;
  int           screen;
  GC            gc;
  Pixmap        bgnd;
  Font          font;
  XRectangle    map;
  unsigned      clrBorder;
  unsigned      clrFace;
  unsigned      clrProgress;
  unsigned      clrHilite;
  unsigned      clrShadow;
  unsigned      clrText;
  unsigned      clrBackground;
  int           bprogress;
  int           max;
  int           min;
  int           cur;
  int           spos;
  int           strheight;
  int           strwidth;
  char          string[80];
};

//-----------------------------------------------------------------------------

Window progress_get_window(pProgress progress)
{
  Window rtn = 0;
  if(progress)
  {
    rtn = progress->window;
  }
  return rtn;
}

//-----------------------------------------------------------------------------

int progress_get_width(pProgress progress)
{
  int rtn = 0;
  if(progress)
  {
    rtn = progress->map.width;
  }
  return rtn;
}

//-----------------------------------------------------------------------------

void progress_set_width(pProgress progress, int width)
{
  if(progress)
  {
    progress->map.width = width;
  }
}

//-----------------------------------------------------------------------------

int progress_get_height(pProgress progress)
{
  int rtn = 0;
  if(progress)
  {
    rtn = progress->map.height;
  }
  return rtn;
}

//-----------------------------------------------------------------------------

void progress_set_height(pProgress progress, int height)
{
  if(progress)
  {
    progress->map.height = height;
  }
}

//-----------------------------------------------------------------------------

int progress_get_position_x(pProgress progress)
{
  int rtn = 0;
  if(progress)
  {
    rtn = progress->map.x;
  }
  return rtn;
}

//-----------------------------------------------------------------------------

void progress_set_position_x(pProgress progress, int x)
{
  if(progress)
  {
    progress->map.x = x;
  }
}

//-----------------------------------------------------------------------------

int progress_get_position_y(pProgress progress)
{
  int rtn = 0;
  if(progress)
  {
    rtn = progress->map.y;
  }
  return rtn;
}

//-----------------------------------------------------------------------------

void progress_set_position_y(pProgress progress, int y)
{
  if(progress)
  {
    progress->map.y = y;
  }
}

//-----------------------------------------------------------------------------

void progress_draw(pProgress progress, int cur, int max, char *msg)
{
  if(progress)
  {
    int width = progress->map.width < PROGRESSMAXWIDTH ? progress->map.width : PROGRESSMAXWIDTH;

    XSetForeground(progress->display, progress->gc, progress->clrFace);
    XFillRectangle(progress->display, progress->bgnd, progress->gc,
		   0,
		   0,
		   width, //progress->map.width - progress->map.x,
		   progress->map.height);
    if((progress->map.width > 32) && (cur > 0) && (max > 0))
    {
      int current = (int)(((float)((/*progress->map.*/width/* - progress->map.x*/) - 2) / max) * cur);
      XSetForeground(progress->display, progress->gc, progress->clrProgress);
      XFillRectangle(progress->display, progress->bgnd, progress->gc,
		     0,
		     0,
		     current,
		     progress->map.height);

      if(msg)
      {
	XSetForeground(progress->display, progress->gc, progress->clrText);
	XDrawString(progress->display, progress->bgnd, progress->gc,
		    ((/*progress->map.*/width  / 2) - 2) - ((progress->strwidth * 4)  / 2),
		    ((progress->map.height / 2) - 2) + (progress->strheight / 2) + 0,
		    msg, strlen(msg));
      }
    }
    XCopyArea(progress->display, progress->bgnd, progress->window, progress->gc,
    	      0, 0, /*progress->map.*/width, progress->map.height, 0, 0);
  }
}

//-----------------------------------------------------------------------------
// Increase reference count.

int progress_enable_progress(pProgress progress)
{
  int ref = -1;
  if(progress)
  {
    ref = progress->bprogress;
    progress->bprogress += 1;
    report(dbglevl_debug, "progress_enable_progress(%i).\n", progress->bprogress);
    // Show and redraw.
    //progress_draw(progress);
  }
  return ref;
}

//-----------------------------------------------------------------------------
// Decrease reference count.

int progress_disable_progress(pProgress progress)
{
  int ref = -1;
  if(progress)
  {
    ref = progress->bprogress;
    // FIXME: should catch -1 but not yet.
    progress->bprogress -= 1;
    report(dbglevl_debug, "progress_disable_progress(%i).\n", progress->bprogress);
  }
  return ref;
}

//-----------------------------------------------------------------------------

pProgress progress_create(Display *display, Window parent, GC gc, int width, int height)
{
  pProgress progress = malloc(sizeof(Progress));
  if(progress)
  {
    memset(progress, 0, sizeof(Progress));
    progress->display        = display;
    progress->parent         = parent;
    progress->screen         = DefaultScreen(display);
    progress->gc             = gc;
    progress->map.x          = 0;
    progress->map.y          = 0;
    progress->map.width      = width;
    progress->map.height     = height;
    progress->clrBorder      = defprgBorder;
    progress->clrFace        = defprgFace;
    progress->clrProgress    = defprgProgress;
    progress->clrHilite      = defprgHilite;
    progress->clrShadow      = defprgShadow;
    progress->clrText        = defprgText;
    progress->clrBackground  = defprgBackground;
    progress->window  = XCreateSimpleWindow(display,
					    parent,
					    progress->map.x,
					    progress->map.y,
					    progress->map.width,
					    progress->map.height,
					    0,
					    WhitePixel(display, 0),
					    progress->clrBackground);
    XSelectInput(progress->display, progress->window, ExposureMask | ButtonPressMask | ButtonReleaseMask);

    progress->gc = XCreateGC(progress->display, progress->window, 0, NULL);
    progress->font = XLoadFont(progress->display, "7x14bold");
    XSetFont(progress->display, progress->gc, progress->font);

    int direction;
    int ascent;
    int descent;
    XCharStruct xchar;
    XQueryTextExtents(display, XGContextFromGC(progress->gc),
		      "0", 1,
		      &direction, &ascent, &descent,
		      &xchar);
    progress->strheight = ascent + descent;
    progress->strwidth  = xchar.width;

    progress->bgnd = XCreatePixmap(progress->display, progress->window, PROGRESSMAXWIDTH, height, 24);
    XSetWindowBackgroundPixmap(progress->display, progress->window, progress->bgnd);
    xwin_set_window_property_atoms(progress->display, progress->window, _NET_WM_WINDOW_TYPE,
				   (unsigned char*)&_NET_WM_WINDOW_TYPE_PROGRESS, 1);

    report(dbglevl_debug, " Created progress-bar : %08X window=%08X.\n", progress, progress->window);
  }
  return progress;
}

//-----------------------------------------------------------------------------

void progress_destroy(pProgress *progress)
{
  if(progress)
  {
    pProgress prg = *progress;
    if(prg)
    {
      report(dbglevl_debug, " Destroying progress-bar : %08X window=%08X.\n", prg, prg->window);
      XFreeGC(prg->display, prg->gc);
      free(prg);
    }
    *progress = NULL;
  }
}

//-----------------------------------------------------------------------------
// end: progress.c
//

  

And The Companion Header...

//-----------------------------------------------------------------------------
// progress.h
//
//  X11 progress-bar definition.
//
// Copyright (c) 2013 - No Fun Farms A.K.A. www.smegware.com
//
//  All Smegware software is free; 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 software 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.
//
//-----------------------------------------------------------------------------
//
// History...
//
//   $Source$
//   $Author$
// $Revision$
//
// $Log$
//
//-----------------------------------------------------------------------------

#define PROGRESSMAXWIDTH 1624

//-----------------------------------------------------------------------------

typedef struct _progress Progress, *pProgress;

//-----------------------------------------------------------------------------

extern Window progress_get_window(pProgress);
extern int progress_get_width(pProgress);
extern void progress_set_width(pProgress, int);
extern int progress_get_height(pProgress);
extern void progress_set_height(pProgress, int);
extern int progress_get_position_x(pProgress);
extern void progress_set_position_x(pProgress, int);
extern int progress_get_position_y(pProgress);
extern void progress_set_position_y(pProgress, int);
extern pProgress progress_create(Display*, Window, GC, int, int);
extern void progress_destroy(pProgress*);
extern void progress_draw(pProgress, int, int, char*);
extern int progress_enable_progress(pProgress);
extern int progress_disable_progress(pProgress);

//-----------------------------------------------------------------------------
// end: progress.h
//

  

The Code Demonstrates The Following Programming Techniques...

Conclusion...

It is known that this code has many 'Freshman' mistakes in it. It is not claimed to be good code. Hopefully though; it demonstrates some of the less obvious interface mechanisms when communicating with both a Window-Manager and a Client program. A definition of how to use the code is also missing. Not purposely, an interface spec just can't be fit into my schedule. For now. Besides... This code is not really meant to be used. Although I use this code it is presented here purely for educational purposes.

6994