I need to create a Tray Icon for my application using purely the Xlib. After some searching, reading the XEmbed documentation and some stuff on SO, this is what the code looks like so far (mostly copy & paste). I understand what it does, but not why. It is creating a tray icon appearantly, but only 1px wide in my mate-panels area. What am I doing wrong? Why is it not the size of a normal tray icon?
Here is my code:
#include <X11/Xutil.h>
#include <string.h>
#define MIN(A, B) ((A) < (B) ? (A) : (B))
/* --------- XEMBED and systray stuff */
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
static int trapped_error_code = 0;
static int (*old_error_handler) (Display *, XErrorEvent *);
static int
error_handler(Display *display, XErrorEvent *error) {
trapped_error_code = error->error_code;
return 0;
}
void
trap_errors(void) {
trapped_error_code = 0;
old_error_handler = XSetErrorHandler(error_handler);
}
int
untrap_errors(void) {
XSetErrorHandler(old_error_handler);
return trapped_error_code;
}
void
send_systray_message(Display* dpy, long message, long data1, long data2, long data3) {
XEvent ev;
Atom selection_atom = XInternAtom (dpy,"_NET_SYSTEM_TRAY_S0",False);
Window tray = XGetSelectionOwner (dpy,selection_atom);
if ( tray != None)
XSelectInput (dpy,tray,StructureNotifyMask);
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = tray;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1; // <--- your window is only here
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, tray, False, NoEventMask, &ev);
XSync(dpy, False);
usleep(10000);
if (untrap_errors()) {
/* Handle errors */
}
}
/* ------------ Regular X stuff */
int
main(int argc, char **argv) {
int width, height;
XWindowAttributes wa;
XEvent ev;
Display *dpy;
int screen;
Window root, win;
/* init */
if (!(dpy=XOpenDisplay(NULL)))
return 1;
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
if(!XGetWindowAttributes(dpy, root, &wa))
return 1;
width = height = MIN(wa.width, wa.height);
/* create window */
win = XCreateSimpleWindow(dpy, root, 0, 0, width, height, 0, 0, 0x7F7F997F);
send_systray_message(dpy, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0); // pass win only once
XMapWindow(dpy, win);
XSync(dpy, False);
/* run */
while(1) {
while(XPending(dpy)) {
XNextEvent(dpy, &ev); /* just waiting until we error because window closed */
}
}
}
I am thankful for everything that will point me in the right direction, even if its just some documentation that I have not found so far.
Related
Given the code:
/*
* XWindows study on if we can turn the frame on and off.
*/
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAPIT
#define REPEAT
void waitxevt(Display* d, int type)
{
XEvent e; /* XEvent holder */
do { XNextEvent(d, &e); } while (e.type != type);
}
void frame(Display* d, Window w, int e)
{
Atom window_type;
long value;
#ifdef MAPIT
XUnmapWindow(d, w);
waitxevt(d, UnmapNotify);
#endif
window_type = XInternAtom(d, "_NET_WM_WINDOW_TYPE", False);
if (e) value = XInternAtom(d, "_NET_WM_WINDOW_TYPE_NORMAL", False);
else value = XInternAtom(d, "_NET_WM_WINDOW_TYPE_DOCK", False);
XChangeProperty(d, w, window_type, XA_ATOM, 32, PropModeReplace, (unsigned char *) &value, 1);
#ifdef MAPIT
XMapWindow(d, w);
waitxevt(d, MapNotify);
#endif
}
int main(void) {
Display* d;
Window w;
XEvent e;
const char* msg = "Hello, World!";
int s;
GC gracxt;
int frmenb = 0;
d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "Cannot open display\n");
exit(1);
}
s = DefaultScreen(d);
gracxt = XDefaultGC(d, s);
w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 640, 480, 5,
BlackPixel(d, s), WhitePixel(d, s));
XSelectInput(d, w, ExposureMask|KeyPressMask|StructureNotifyMask);
XMapWindow(d, w);
waitxevt(d, MapNotify);
while (1) {
XNextEvent(d, &e);
if (e.type == Expose) XDrawString(d, w, gracxt, 10, 50, msg, strlen(msg));
if (e.type == KeyPress) {
frame(d, w, frmenb);
frmenb = !frmenb;
#ifdef REPEAT
frame(d, w, frmenb);
frmenb = !frmenb;
#endif
}
}
XCloseDisplay(d);
return 0;
}
The purpose of the code is to turn the frame on and off for the window w. With no map/unmap operation, The "off" call works correctly, and the window changes (onscreen) to have no frame, and is not sizable, and the titlebar no longer appears.
However, on turning it back on using the routine, the titlebar is not visible, but it is sizable. If you resize the window, the titlebars reappear.
The suggestion was made to unmap the window before setting the property and remap after. The result of this is that the window without frame no longer can have focus, and thus cannot get a key to change back. I put in a "repeat" flag to make it immediately revert back to full frame mode, and thus prove that the return to framing works. It does. Another side effect is that the position of the window gets reset after the map operation, but I can compensate for that.
This is on Ubuntu 20.04.
What is the purpose? This code is part of a toolkit to port between Windows and Linux. The frame on/off is used for two purposes (so far):
To make component windows (widgets) without frames.
To toggle the frame. For example, I have a clock program that if you click on it, it will remove the frame, making it both smaller and immobile. Another click restores it.
The first one works now, since it only turns off the frame once, and that happens before mapping. The second one does not work.
New program, now works, using the suggestions:
/*
* XWindows study on if we can turn the frame on and off.
*/
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct MwmHints {
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long input_mode;
unsigned long status;
};
enum {
MWM_HINTS_FUNCTIONS = (1L << 0),
MWM_HINTS_DECORATIONS = (1L << 1),
MWM_FUNC_ALL = (1L << 0),
MWM_FUNC_RESIZE = (1L << 1),
MWM_FUNC_MOVE = (1L << 2),
MWM_FUNC_MINIMIZE = (1L << 3),
MWM_FUNC_MAXIMIZE = (1L << 4),
MWM_FUNC_CLOSE = (1L << 5)
};
void frame(Display* d, Window w, int e)
{
Atom mwmHintsProperty;
struct MwmHints hints;
mwmHintsProperty = XInternAtom(d, "_MOTIF_WM_HINTS", 0);
hints.flags = MWM_HINTS_DECORATIONS;
hints.decorations = !!e;
XChangeProperty(d, w, mwmHintsProperty, mwmHintsProperty, 32,
PropModeReplace, (unsigned char *)&hints, 5);
}
int main(void) {
Display* d;
Window w;
XEvent e;
const char* msg = "Hello, World!";
int s;
GC gracxt;
int frmenb = 0;
d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "Cannot open display\n");
exit(1);
}
s = DefaultScreen(d);
gracxt = XDefaultGC(d, s);
w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 640, 480, 5,
BlackPixel(d, s), WhitePixel(d, s));
XSelectInput(d, w, ExposureMask|KeyPressMask|StructureNotifyMask);
XMapWindow(d, w);
while (1) {
XNextEvent(d, &e);
if (e.type == Expose) XDrawString(d, w, gracxt, 10, 50, msg, strlen(msg));
if (e.type == KeyPress) {
frame(d, w, frmenb);
frmenb = !frmenb;
}
}
XCloseDisplay(d);
return 0;
}
I'm writing this simple program to learn how to work with audio with SDL. The program opens a window with a button that says go and when you hit the button it should play a WAV of a drum sample. There are no errors and the program doesn't crash it's just that instead of playing the drum sound it makes a weird buzzing noise that doesn't stop until you exit the program. I think it's something to do with the audio callback function but I am very new to this so I'm not sure exactly how it works.
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <SDL2/SDL_audio.h>
TTF_Font* font;
SDL_Color white = {255, 255, 255};
SDL_AudioSpec frmt;
bool run = true;
bool playing = false;
struct sample
{
Uint8 *data;
Uint32 dpos;
Uint32 dlen;
} sound;
bool buttonPress(int x, int y, SDL_Rect r)
{
if (x < (r.x + r.w) && x > r.x)
{
if (y < (r.y + r.h) && y > r.y)
{
return true;
}
}
return false;
}
void mixing(void *unused, Uint8 *stream, int len)
{
Uint32 amount;
if (playing)
{
amount = sound.dlen - sound.dpos;
if ( amount > len ) {
amount = len;
}
SDL_MixAudio(stream, &sound.data[sound.dpos], amount, SDL_MIX_MAXVOLUME);
sound.dpos += amount;
}
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
frmt.channels = 1;
frmt.format = AUDIO_S16;
frmt.freq = 22050;
frmt.samples = 512;
frmt.userdata = NULL;
frmt.callback = mixing;
int mX, mY;
Uint32 fpsTimer = SDL_GetTicks();
font = TTF_OpenFont("octaFont.TTF", 20);
SDL_Window* window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 400, 200, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_Surface* surface = TTF_RenderText_Solid(font, "Go!", white);
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_Rect button;
button.w = 50;
button.h = 35;
button.x = 10;
button.y = 10;
SDL_Rect bg;
bg.w = 400;
bg.h = 200;
bg.x = 0;
bg.y = 0;
SDL_Event e;
if (SDL_OpenAudio(&frmt, NULL) < 0)
{
fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError());
return 1;
}
SDL_PauseAudio(0);
SDL_AudioSpec wave;
SDL_AudioCVT cvt;
Uint8 *data;
Uint32 dlen;
if (SDL_LoadWAV("sound.wav", &wave, &data, &dlen) == NULL)
{
fprintf(stderr, "Unable to load wave: %s\n", SDL_GetError());
return 1;
}
SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq, AUDIO_S16, 1, 22050);
cvt.buf = malloc(dlen*cvt.len_mult);
memcpy(cvt.buf, data, dlen);
cvt.len = dlen;
SDL_ConvertAudio(&cvt);
SDL_FreeWAV(data);
SDL_LockAudio();
free(sound.data);
sound.data = cvt.buf;
sound.dlen = cvt.len_cvt;
sound.dpos = 0;
SDL_UnlockAudio();
while (run)
{
while (SDL_PollEvent(&e))
{
switch (e.type)
{
case SDL_QUIT:
run = false;
break;
case SDL_KEYDOWN:
switch (e.key.keysym.sym)
{
case SDLK_SPACE:
playing = false;
break;
default:
break;
}
break;
case SDL_MOUSEBUTTONDOWN:
SDL_GetMouseState(&mX, &mY);
if (buttonPress(mX, mY, button))
{
playing = true;
}
break;
default:
break;
}
}
if (SDL_GetTicks() - fpsTimer >= 16)
{
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderFillRect(renderer, &bg);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(renderer, &button);
SDL_RenderCopy(renderer, texture, NULL, &button);
SDL_RenderPresent(renderer);
fpsTimer = SDL_GetTicks();
}
}
SDL_CloseAudio();
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
TTF_Quit();
SDL_Quit();
return 0;
}
The issue may be that you're using SDL_MixAudio.
Your code mixes in the data from the .wav file, but mixes it into what?
What is in stream before calling SDL_MixAudio?
I get the same buzz, but when I use memset to zero out the stream buffer before calling SDL_MixAudio, I get the correct sound from the .wav file.
I don't know for sure but I believe that on the second and subsequent calls to your mixing function, the data from the prior callback is still in the stream buffer.
Side note: When the .wav data has finished playing, we can reset sound.dpos to replay the file again.
Here's the refactored code:
void
mixing(void *unused, Uint8 *stream, int len)
{
Uint32 amount;
// NOTE/DEBUG: force sound on
#if 1
playing = 1;
#endif
// NOTE/FIX: zero out stream data so we don't mix in random data (from the
// prior round)
#if 1
memset(stream,0,len);
#endif
if (playing) {
amount = sound.dlen - sound.dpos;
if (amount > len) {
amount = len;
}
#if 1
SDL_MixAudio(stream, &sound.data[sound.dpos], amount, SDL_MIX_MAXVOLUME);
#else
memcpy(stream,&sound.data[sound.dpos],amount);
#endif
sound.dpos += amount;
// NOTE/FIX(?) -- start wav at beginning after all data has been output
#if 1
if (sound.dpos >= sound.dlen)
sound.dpos = 0;
#endif
}
}
This is a working example of X11 code that handles Ctrl-q event to quit application:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
void exitOnCondition(char cond, const char *msg, int exitCode, Display *dpy, Window *w, GC *gc) {
if(cond) {
printf("%s\n", msg);
if(dpy && gc) XFreeGC(dpy, *gc);
if(dpy && w) XDestroyWindow(dpy, *w);
if(dpy) XCloseDisplay(dpy);
exit(exitCode);
}
}
int main(int argc, char **argv) {
Display *dpy = XOpenDisplay(0);
exitOnCondition(dpy == 0, "Error: XOpenDisplay failed", -1, dpy, 0, 0);
int blackColor = BlackPixel(dpy, DefaultScreen(dpy));
int whiteColor = WhitePixel(dpy, DefaultScreen(dpy));
Window w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0,
200, 100, 0, blackColor, blackColor);
//Tell X Server to send MapNotify events
XSelectInput(dpy, w, StructureNotifyMask | KeyPressMask);
//Make window appear
XMapWindow(dpy, w);
//Graphics Context
GC gc = XCreateGC(dpy, w, 0, 0);
//Set white color for drawing
XSetForeground(dpy, gc, whiteColor);
//Wait for the MapNotify event
for(;;) {
XEvent e;
XNextEvent(dpy, &e);
if (e.type == MapNotify) {
break;
}
}
//Draw the line
XDrawLine(dpy, w, gc, 10, 60, 180, 20);
//Send the "DrawLine" request to the server
XFlush(dpy);
char text[255];
XEvent e;
KeySym key;
int numKeys = 0;
for(;;) {
XNextEvent(dpy, &e);
if(e.type == KeyPress) {
//With modifier XLookupString will return garbage(?) in text[0] and key as latin1
if((numKeys = XLookupString(&e.xkey, text, 255, &key, 0))) {
printf("lookup returned:\n");
for(int i = 0; i < numKeys; i++) {
printf("text[%d]=%x\n", i, text[i]);
}
if(e.xkey.state == ControlMask && key == XK_q) {
exitOnCondition(1, "C-Q pressed", 0, dpy, &w, &gc);
}
}
}
}
XFreeGC(dpy, gc);
XDestroyWindow(dpy,w);
XCloseDisplay(dpy);
}
Will this code correctly handle Ctrl-q event on any system?
Can I use e.xkey.state to check for Ctrl modifier after XLookupString for any keyboard layout even when Ctrl is rebound to CAPS Lock(or anything else)?
Why does XLookupString return one symbol text[0]==0x11 for Ctrl-q event and not text[0]==CtrlModifierCode text[1]=='q'?
XLookupString returns a sequence of ISO-8859-1 characters (at least according to the manual I have; I do not know how up-to-date it is). There is no character code in ISO-8859-1 for the "ctrl" key by itself. Strictly speaking, there isn't one for the ctrl-q combination either, but tradition dictates that ctrl + (A...Z) map to the 1...26 range.
I'm a fortran programmer working with a program written in C (which I have Little to no experience with).
I have a program written in fortan that creates an image in the form of a multidimentional array of pixels with their X value, Y value, and RGB values (0-4 for each color). It then passes the array, the size of the array in the x and y dimensions, the color map containing all the colors arranged in a spectrum, and the number of colors in the spectrum to a program written in C that is supposed to plot the image using Xlib.
The program works when I pass a particular one color map with 125 colors (5 values for red/green/blue) but when I try to increase the amount of colors I pass to the C program I exceed some sort of limit and the program shuts down. How do I raise the limit in the C source code?
Here is the program:
#define USEPIXMAP /* sets drawing into background pixmap of window */
#include "putras.h"
#include <stdlib.h>
static unsigned def_map[256];
void putras_(int *pixel_values, int *arrayx, int *arrayy,
int *colormap_entries, int *colormap_size)
{
extern Colormap cmap;
extern Window window;
extern Display *dpy;
extern XColor color;
extern XWindowAttributes window_attr;
extern GC gc;
extern XGCValues gcv;
extern Pixmap pixmap;
static int call_flag = 0;
char *display_name=NULL;
char *dummy;
unsigned pixel;
int i, j;
XPoint *pointarray[256];
unsigned arraylen[256];
unsigned maxlen[256];
int remain_len;
if(call_flag == 0) {
/* THis only gets done on the first call to putras */
call_flag = 1;
if( (dpy = XOpenDisplay(display_name) ) == NULL){
fprintf(stderr,"Error: Couldn't open display\n");
exit(1);
}
XGetWindowAttributes(dpy, RootWindow(dpy,DefaultScreen(dpy)),
&window_attr);
window=XCreateSimpleWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)), 0, 0,
*arrayx, *arrayy,window_attr.border_width,
BlackPixel(dpy, DefaultScreen(dpy)),
WhitePixel(dpy, DefaultScreen(dpy)));
#ifdef USEPIXMAP
pixmap=XCreatePixmap(dpy, window, *arrayx, *arrayy,
DefaultDepth(dpy,DefaultScreen(dpy)) );
XMapWindow(dpy, window);
XClearWindow(dpy, window);
XCopyArea(dpy, window, pixmap, DefaultGC(dpy, DefaultScreen(dpy)),
0,0,*arrayx, *arrayy, 0,0);
XFlush(dpy);
#else
XMapWindow(dpy, window);
#endif
cmap=DefaultColormap(dpy,DefaultScreen(dpy));
color.flags=DoRed|DoBlue|DoGreen;
for (i=0;i<(*colormap_size);i++){
color.pixel= colormap_entries[4*i];
j = color.pixel;
color.red=colormap_entries[4*i+1];
color.green=colormap_entries[4*i+2];
color.blue=colormap_entries[4*i+3];
XAllocColor(dpy, cmap, &color);
def_map[j] = color.pixel;
}
gc = XCreateGC(dpy, window, 0, NULL);
} /* Endif - first time through */
/* The following gets done on each call */
for (i=0; i<256; i++){
pointarray[i]=(XPoint *)malloc((*arrayx)*(*arrayy)/128*sizeof(XPoint));
maxlen[i]=(*arrayx)*(*arrayy)/128 -1;
arraylen[i]=0;
}
for (j=0; j<(*arrayy); j++) {
for (i=0; i<(*arrayx); i++) {
/*pixel = def_map[pixel_values[j * (*arrayx) + i]];*/
pixel=pixel_values[j*(*arrayx)+i];
/*pixel=1;*/
if (arraylen[pixel]==maxlen[pixel]) {
pointarray[pixel]= (XPoint *)realloc(pointarray[pixel],
2*maxlen[pixel]*sizeof(XPoint));
maxlen[pixel]=2*maxlen[pixel];
}
pointarray[pixel][arraylen[pixel]].x=i;
pointarray[pixel][(arraylen[pixel])++].y=j;
} /* end for loop*/
} /* end for loop*/
for (i=0; i<256; i++) {
XSetForeground(dpy, gc, def_map[i]);/*dpy,gc,i);*/
if (arraylen[i]>=MAXPOINT) {
for (j=0; j<=(arraylen[i]/MAXPOINT); j++) {
remain_len=(arraylen[i]-MAXPOINT*j);
#ifdef USEPIXMAP
XDrawPoints(dpy, pixmap, gc,(pointarray[i]+j*MAXPOINT),
((remain_len<MAXPOINT)?remain_len:MAXPOINT),
CoordModeOrigin);
#else
XDrawPoints(dpy, window, gc,(pointarray[i]+j*MAXPOINT),
((remain_len<MAXPOINT)?remain_len:MAXPOINT),
CoordModeOrigin);
#endif
} /* end for loop */
} else {
#ifdef USEPIXMAP
XDrawPoints(dpy, pixmap, gc, pointarray[i], arraylen[i],
CoordModeOrigin);
#else
XDrawPoints(dpy, window, gc, pointarray[i], arraylen[i],
CoordModeOrigin);
#endif
} /* end if */
} /* end for loop 256 */
#ifdef USEPIXMAP
XSetWindowBackgroundPixmap(dpy, window, pixmap);
XClearWindow(dpy, window);
#endif
XFlush(dpy);
for (i=0; i<256;i++)
free(pointarray[i]);
return;
}
void unmap(void)
{
/* extern Pixmap pmap; */
extern Window window;
extern Display *dpy;
/* int width, height; */
XUnmapWindow(dpy, window);
XFlush(dpy);
return;
}
void remap(void)
{
extern Window window;
extern Display *dpy;
XMapRaised(dpy, window);
XFlush(dpy);
return;
}
I'm writing a simple text user interface with libX11 and I've got a set of code working for a basic library abstraction.
The problem is when I try to draw text, the title bar blocks the first line. So now I have to offset the vertical printing by about 20 pixels. Is there a way to determine the exact size of the title bar, so that I can properly offset each line of text?
Here's the code I have so far, and tui_puts is the function I need to do this for:
#include "tui.h"
#include <X11/Xlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
struct tui_data {
Display * display;
Window id_window;
GC context_graphics;
XIM method_input;
XIC context_input;
XWindowAttributes spec_window;
XFontStruct * spec_font;
size_t offset_y;
size_t offset_x;
};
int tui_init (struct tui_session * ptr_tui){
memset (ptr_tui, 0, sizeof (struct tui_session));
ptr_tui->ptr_data = calloc (sizeof (struct tui_data), 1);
if (!ptr_tui->ptr_data) return -1;
ptr_tui->ptr_data->display = XOpenDisplay (0);
if (!ptr_tui->ptr_data->display) return -1;
int color_black = BlackPixel(ptr_tui->ptr_data->display, DefaultScreen(ptr_tui->ptr_data->display));
int color_white = WhitePixel(ptr_tui->ptr_data->display, DefaultScreen(ptr_tui->ptr_data->display));
ptr_tui->ptr_data->id_window = XCreateSimpleWindow(ptr_tui->ptr_data->display,
DefaultRootWindow(ptr_tui->ptr_data->display),
0, 0, 640, 480, 0, color_black, color_black);
XSelectInput (ptr_tui->ptr_data->display,
ptr_tui->ptr_data->id_window,
StructureNotifyMask);
XMapWindow (ptr_tui->ptr_data->display,
ptr_tui->ptr_data->id_window);
ptr_tui->ptr_data->context_graphics = XCreateGC(ptr_tui->ptr_data->display,
ptr_tui->ptr_data->id_window, 0, 0);
for (;;){
XEvent e;
XNextEvent (ptr_tui->ptr_data->display, &e);
if (e.type == MapNotify) break;
}
XSetForeground (ptr_tui->ptr_data->display,
ptr_tui->ptr_data->context_graphics,
color_white);
XGetWindowAttributes (ptr_tui->ptr_data->display,
ptr_tui->ptr_data->id_window,
&ptr_tui->ptr_data->spec_window);
XSelectInput (ptr_tui->ptr_data->display,
ptr_tui->ptr_data->id_window,
ExposureMask | KeyPressMask | ResizeRedirectMask);
ptr_tui->ptr_data->method_input = XOpenIM (ptr_tui->ptr_data->display, 0, 0, 0);
if (!ptr_tui->ptr_data->method_input){
return -1;
}
ptr_tui->ptr_data->context_input = XCreateIC (ptr_tui->ptr_data->method_input,
XNInputStyle, XIMPreeditNothing
| XIMStatusNothing, XNClientWindow,
ptr_tui->ptr_data->id_window, NULL);
if (!ptr_tui->ptr_data->context_input){
return -1;
}
XSetICFocus (ptr_tui->ptr_data->context_input);
ptr_tui->ptr_data->spec_font = XLoadQueryFont (ptr_tui->ptr_data->display,
"-misc-fixed-medium-"
"r-normal-*-*-120-*-*");
if (!ptr_tui->ptr_data->spec_font){
return -1;
}
XSetFont (ptr_tui->ptr_data->display,
ptr_tui->ptr_data->context_graphics,
ptr_tui->ptr_data->spec_font->fid);
ptr_tui->max_x = ptr_tui->ptr_data->spec_window.width
/ ptr_tui->ptr_data->spec_font->max_bounds.width;
ptr_tui->max_y = ptr_tui->ptr_data->spec_window.height
/ (ptr_tui->ptr_data->spec_font->max_bounds.ascent
+ ptr_tui->ptr_data->spec_font->max_bounds.descent);
return 0;
}
int tui_free (struct tui_session * ptr_tui){
if (ptr_tui->ptr_data){
XFreeFont (ptr_tui->ptr_data->display, ptr_tui->ptr_data->spec_font);
XFreeGC (ptr_tui->ptr_data->display, ptr_tui->ptr_data->context_graphics);
XSetCloseDownMode(ptr_tui->ptr_data->display, DestroyAll);
XCloseDisplay (ptr_tui->ptr_data->display);
free (ptr_tui->ptr_data);
}
memset (ptr_tui, 0, sizeof (struct tui_session));
return 0;
}
int tui_refresh (struct tui_session * ptr_tui){
XFlush (ptr_tui->ptr_data->display);
return 0;
}
int tui_clear (struct tui_session * ptr_tui){
XClearWindow (ptr_tui->ptr_data->display,
ptr_tui->ptr_data->id_window);
return 0;
}
int tui_puts (struct tui_session * ptr_tui,
const void * ptr_data, size_t len_data,
size_t index_x, size_t index_y, uint32_t flags){
if (((index_x + len_data) >= ptr_tui->max_x)
|| (index_y >= ptr_tui->max_y)) return -1;
XDrawImageString (ptr_tui->ptr_data->display,
ptr_tui->ptr_data->id_window,
ptr_tui->ptr_data->context_graphics,
ptr_tui->ptr_data->spec_window.border_width
+ ptr_tui->ptr_data->spec_font->max_bounds.width * index_x,
(ptr_tui->ptr_data->spec_font->max_bounds.ascent
+ ptr_tui->ptr_data->spec_font->max_bounds.descent)
* index_y + 20, ptr_data, len_data);
return 0;
}
int tui_message (struct tui_session * ptr_tui, const char * format, ...){
return -1;
}
int tui_prompt (struct tui_session * ptr_tui, const char * format, ...){
return -1;
}
int tui_input (struct tui_session * ptr_tui, tui_event * ptr_event){
XEvent event;
Status status = 0;
KeySym keysym = 0;
char buffer[4];
int count = 0;
XNextEvent(ptr_tui->ptr_data->display, &event);
switch (event.type){
case KeyPress:
count = Xutf8LookupString (ptr_tui->ptr_data->context_input,
(XKeyPressedEvent*) &event, buffer,
sizeof (buffer), &keysym, &status);
if (count){
ptr_event->type = TUI_EVENT_KEYPRESS;
ptr_event->value = buffer[0];
}
break;
case Expose:
ptr_event->type = TUI_EVENT_REPRINT;
ptr_event->value = 0;
break;
case ResizeRequest:
XGetWindowAttributes (ptr_tui->ptr_data->display,
ptr_tui->ptr_data->id_window,
&ptr_tui->ptr_data->spec_window);
ptr_event->type = TUI_EVENT_REPRINT;
ptr_event->value = 0;
break;
default:
ptr_event->type = 0;
ptr_event->value = 0;
}
return 0;
}
int tui_scroll (struct tui_session * ptr_tui, int offset){
return -1;
}
Also, here's an important structure:
typedef struct {
int x, y; /* location of window */
int width, height; /* width and height of window */
int border_width; /* border width of window */
int depth; /* depth of window */
Visual *visual; /* the associated visual structure */
Window root; /* root of screen containing window */
int class; /* InputOutput, InputOnly*/
int bit_gravity; /* one of the bit gravity values */
int win_gravity; /* one of the window gravity values */
int backing_store; /* NotUseful, WhenMapped, Always */
unsigned long backing_planes; /* planes to be preserved if possible */
unsigned long backing_pixel; /* value to be used when restoring planes */
Bool save_under; /* boolean, should bits under be saved? */
Colormap colormap; /* color map to be associated with window */
Bool map_installed; /* boolean, is color map currently installed*/
int map_state; /* IsUnmapped, IsUnviewable, IsViewable */
long all_event_masks; /* set of events all people have interest in*/
long your_event_mask; /* my event mask */
long do_not_propagate_mask; /* set of events that should not propagate */
Bool override_redirect; /* boolean value for override-redirect */
Screen *screen; /* back pointer to correct screen */
} XWindowAttributes;
And this was helpful for getting the horizontal offset of the client area, but I don't see anything that would help me get the vertical offset.
The origin is at the base line, so you have to add ptr_tui->ptr_data->spec_font->max_bounds.ascent instead of 20 if I'm not lost in your code.