A Place Where No Dreams Come True...

Current Project: A very simple X11 static window implementation with no external dependencies. It it completely owner controlled and provides no feedback whatsoever to the owner window.

What Does This Code Do...

Implements X11 static class window. That is... A child window intended not to change, although not disallowed, during it's lifetime. There is no communication from this window to it's parent window. Currently it only supports text display.

What Doesn't This Code Do...

It does not yet support graphic backgrounds or borders in implementation. 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.

//-----------------------------------------------------------------------------
// text.c
//
//  X11 static text window 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 <X11/xpm.h>
#include <stdlib.h>
#include <string.h>

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

#define deftxtSizeBorder 2
#define deftxtItemBorder 1
#define deftxtBorder 0x00000000
#define deftxtFace 0xFFB0B080
#define deftxtAlert 0xFFC0C000
#define deftxtHilite 0xFFE0E0E0
#define deftxtShadow 0xFF505050
#define deftxtText 0x00000000
#define deftxtTextHilite 0xFF909090
#define deftxtTextShadow 0xFF505050
#define deftxtBackground 0x00000000
#define deftxtIconSize 16

struct _text {
  Display      *display;
  Window        parent;
  Window        window;
  int           screen;
  GC            gc;
  Pixmap        bgnd;
  XImage       *image;
  Font          font;
  XRectangle    map;
  Atom          message;
  XCharStruct   xchar;
  unsigned      clrBorder;
  unsigned      clrFace;
  unsigned      clrAlert;
  unsigned      clrHilite;
  unsigned      clrShadow;
  unsigned      clrText;
  unsigned      clrTextHilite;
  unsigned      clrTextShadow;
  unsigned      clrBackground;
  int           btext;
  int           itemid;
  int           selected;
  int           txtborder;
  int           iconsize;
  int           itmborder;
  int           bdeleteGC;
  char          *text;
};

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

Window text_get_window(pText text)
{
  Window rtn = 0;
  if(text)
  {
    rtn = text->window;
  }
  return rtn;
}

//-----------------------------------------------------------------------------
/*
static void text_set_gc_mask(pMenu menu, Pixmap mask, int x , int y)
{
  XGCValues vals;
  vals.clip_x_origin = x;
  vals.clip_y_origin = y;
  vals.clip_mask = mask;
  XChangeGC(menu->display, menu->gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &vals);
}
*/
//-----------------------------------------------------------------------------

void text_draw(pText text)
{
  if(text)
  {
    if(text->image)
    {
      XPutImage(text->display, text->window, text->gc, text->image,
		0, 0, 0, 0, text->image->width, text->image->height);
    }
    else
    {
      // Start with blank canvas.
      XSetForeground(text->display, text->gc, text->clrFace);
      XFillRectangle(text->display, text->window, text->gc,
		     0, 0, text->map.width, text->map.height);
      XSetForeground(text->display, text->gc, text->clrText);
      if(text->font)
      {
	XSetFont(text->display, text->gc, text->font);
      }
      XDrawString(text->display, text->window, text->gc,
		  text->itmborder, (text->map.height - text->itmborder) - text->xchar.descent,
		  text->text, strlen(text->text));
    }
    /*
    // Border.
    XSetForeground(menu->display, menu->gc, menu->clrHilite);
    XDrawLine(menu->display, menu->bgnd, menu->gc, 0, menu->map.height - 2, 0, 0);
    XDrawLine(menu->display, menu->bgnd, menu->gc, 0, 0, menu->map.width - 2, 0);
    XSetForeground(menu->display, menu->gc, menu->clrShadow);
    XDrawLine(menu->display, menu->bgnd, menu->gc, menu->map.width - 1, 0, menu->map.width - 1, menu->map.height - 1);
    XDrawLine(menu->display, menu->bgnd, menu->gc, menu->map.width - 1, menu->map.height - 1, 0, menu->map.height - 1);
    // Update window.
    XCopyArea(text->display, text->bgnd, text->window, text->gc,
              0, 0, text->map.width, text->map.height, 0, 0);
    */
  }
}

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

int text_enable_text(pText text)
{
  int ref = -1;
  if(text)
  {
    ref = text->btext;
    text->btext += 1;
    report(dbglevl_debug, "text_enable_text(%i).\n", text->btext);
  }
  return ref;
}

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

int text_disable_text(pText text)
{
  int ref = -1;
  if(text)
  {
    ref = text->btext;
    // FIXME: should catch -1 but not yet.
    text->btext -= 1;
    report(dbglevl_debug, "text_disable_text(%i).\n", text->btext);
  }
  return ref;
}

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

void text_show(pText text, XEvent event)
{
  if(text)
  {
    report(dbglevl_debug, " text show.\n");
    XMapWindow(text->display, text->window);
  }
}

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

void text_hide(pText text)
{
  if(text)
  {
    XUnmapWindow(text->display, text->window);
    report(dbglevl_debug, " text hide.\n");
  }
}

//-----------------------------------------------------------------------------
/*
static void text_notify_parent(pText text)
{
  XEvent event;

  memset(&event, 0, sizeof(event));

  event.xclient.type         = ClientMessage;
  event.xclient.display      = text->display;
  event.xclient.window       = text->window;
  event.xclient.message_type = text->message;
  event.xclient.format       = 32;
  event.xclient.data.l[0]    = text->window;
  event.xclient.data.l[1]    = text->itemid;
  XSendEvent(text->display, text->parent, 0, 0, &event);
}
*/
//-----------------------------------------------------------------------------

void text_init(pText text, char *content)
{
  int direction, ascent, descent;

  if(text)
  {
    if(text->text)
    {
      free(text->text);
      text->text = NULL;
      memset(&text->xchar, 0, sizeof(text->xchar));
    }
    if(content)
    {
      text->text = malloc(strlen(content) + 4);
      if(text->text)
      {
	strcpy(text->text, content);
	if(text->font)
	{
	  XQueryTextExtents(text->display, text->font, text->text, strlen(text->text),
			    &direction, &ascent, &descent, &text->xchar);
	  text->xchar.ascent = ascent;
	}
	report(dbglevl_debug, " text_init(%s) - ascent=%i descent=%i width=%i.\n",
	       text->text, text->xchar.ascent, text->xchar.descent, text->xchar.width);
      }
    }
  }
}

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

void text_set_font(pText text, char *sfont)
{
  if(text)
  {
    if(text->font)
    {
      XUnloadFont(text->display, text->font);
    }
    text->font = XLoadFont(text->display, sfont);
    report(dbglevl_debug, " text_set_font(%s).\n", sfont);
  }
}

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

void text_set_image(pText text, char *bits, int width, int height)
{
  if(text)
  {
    if(text->image)
    {
      report(dbglevl_debug, "Destroying text XImage.\n");
      XDestroyImage(text->image);
      text->image = NULL;
    }
    if(bits)
    {
      XImage *image = XCreateImage(text->display,
				   DefaultVisual(text->display, 0), // visual.
				   DefaultDepth(text->display, 0), // depth.
				   ZPixmap, // type.
				   0, // offset
				   bits, // image data.
				   width, height, // dimentions.
				   32, // pad.
				   width * 4); // bytes/line.
      if(image)
      {
	report(dbglevl_debug, "Setting text XImage - %i x %i.\n", width, height);
	text->image = image;
      }
    }
   }
}

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

void text_destroy(pText *text)
{
  if(text)
  {
    pText txt = *text;
    if(txt)
    {
      report(dbglevl_debug, " Destroying static text : %08X window=%08X.\n", txt, txt->window);
      if(txt->font)
      {
	XUnloadFont(txt->display, txt->font);
      }
      if(txt->bdeleteGC)
      {
	XFreeGC(txt->display, txt->gc);
      }
      if(txt->image)
      {
	report(dbglevl_debug, "  destroying static XImage.\n");
	XDestroyImage(txt->image);
      }
      if(txt->text)
      {
	free(txt->text);
      }
      free(txt);
    }
    *text = NULL;
  }
}

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

pText text_create(Display *display, Window parent, GC gc, int x, int y, int width, int height, Atom message)
{
  pText text = malloc(sizeof(Text));
  if(text)
  {
    memset(text, 0, sizeof(Text));
    text->display        = display;
    text->parent         = parent;
    text->screen         = DefaultScreen(display); // FIXME: pass from caller.
    text->gc             = gc;
    text->map.x          = x;
    text->map.y          = y;
    text->map.width      = width;
    text->map.height     = height;
    text->message        = message;
    text->clrBorder      = deftxtBorder;
    text->clrFace        = deftxtFace;
    text->clrAlert       = deftxtAlert;
    text->clrHilite      = deftxtHilite;
    text->clrShadow      = deftxtShadow;
    text->clrText        = deftxtText;
    text->clrTextHilite  = deftxtTextHilite;
    text->clrTextShadow  = deftxtTextShadow;
    text->clrBackground  = deftxtBackground;
    text->iconsize       = deftxtIconSize;
    text->txtborder      = deftxtSizeBorder;
    text->itmborder      = deftxtItemBorder;
    text->window  = XCreateSimpleWindow(display,
					parent,
					text->map.x,
					text->map.y,
					text->map.width,
					text->map.height,
					0,
					text->clrText,
					text->clrFace);
    XSelectInput(text->display, text->window, ExposureMask);
    if(text->gc == NULL)
    {
      text->gc = XCreateGC(text->display, text->window, 0, NULL);
      text->bdeleteGC = 1;
    }
    xwin_set_window_property_atoms(text->display, text->window, _NET_WM_WINDOW_TYPE,
				   (unsigned char*)&_NET_WM_WINDOW_TYPE_STATIC, 1);
    report(dbglevl_debug, " Created static-text : %08X window=%08X.\n", text, text->window);
  }
  return text;
}

//-----------------------------------------------------------------------------
// end: text.c
//

  

And The Companion Header...

//-----------------------------------------------------------------------------
// text.h
//
//  X11 static text window 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$
//
//-----------------------------------------------------------------------------

typedef struct _text Text, *pText;

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

extern Window text_get_window(pText);
extern void text_draw(pText);
extern int text_enable_text(pText);
extern int text_disable_text(pText);
extern void text_show(pText, XEvent);
extern void text_hide(pText);
extern void text_init(pText, char*);
extern void text_set_font(pText, char*);
extern void text_set_image(pText, char*, int, int);
extern void text_destroy(pText*);
extern pText text_create(Display*, Window, GC, int, int, int, int, Atom);

//-----------------------------------------------------------------------------
// end: text.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.

6989