Page 1 of 1

Linux : Writing Our First X-Windows Application X-Windows 'Hello World' tutorial Rate Topic: -----

#1 Martyn.Rae  Icon User is offline

  • The programming dinosaur
  • member icon

Reputation: 540
  • View blog
  • Posts: 1,406
  • Joined: 22-August 09

Posted 08 April 2010 - 03:55 AM

*
POPULAR

Linux : Writing Our First X-Windows Application

Introduction

This tutorial looks at writing a simple X-Windows application that displays the text 'Hello World' in the middle of the frame window. When the window is re-sized, the text is re-positioned accordingly.

Throughout this tutorial, I shall be making references to the equivalent Microsoft Windows API routines, for those of you who are more familiar with that environment.

The X-Windows environment

One of the major differences between the Microsoft Windows and X-Windows systems is that X-Windows is client/server based. This has a significant impact on networked machines, as the application may be running on the server, yet displaying windows on a client machine. Seen from the users perspective, the application looks like it is running locally, when in actual fact it isn't. The downside to this approach is that response times from client to server and back to client are limited to the bandwidth of the network connection.

Accordingly, there are some X-Windows calls that may seen a little strange, but I will discuss them as we progress through the tutorial.

The code

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

int main (int argc, char *argv[])
{
    Display                 *display;
    Visual                  *visual;
    int                     depth;
    int                     text_x;
    int                     text_y;
    XSetWindowAttributes    frame_attributes;
    Window                  frame_window;
    XFontStruct             *fontinfo;
    XGCValues               gr_values;
    GC                      graphical_context;
    XKeyEvent               event;
    char                    hello_string[] = "Hello World";
    int                     hello_string_length = strlen(hello_string);

    display = XOpenDisplay(NULL);
    visual = DefaultVisual(display, 0);
    depth  = DefaultDepth(display, 0);
    
    frame_attributes.background_pixel = XWhitePixel(display, 0);
    /* create the application window */
    frame_window = XCreateWindow(display, XRootWindow(display, 0),
                                 0, 0, 400, 400, 5, depth,
                                 InputOutput, visual, CWBackPixel,
                                 &frame_attributes);
    XStoreName(display, frame_window, "Hello World Example");
    XSelectInput(display, frame_window, ExposureMask | StructureNotifyMask);

    fontinfo = XLoadQueryFont(display, "10x20");
    gr_values.font = fontinfo->fid;
    gr_values.foreground = XBlackPixel(display, 0);
    graphical_context = XCreateGC(display, frame_window, 
                                  GCFont+GCForeground, &gr_values);
    XMapWindow(display, frame_window);

    while ( 1 ) {
        XNextEvent(display, (XEvent *)&event);
        switch ( event.type ) {
            case Expose:
            {
                XWindowAttributes window_attributes;
                int font_direction, font_ascent, font_descent;
                XCharStruct text_structure;
                XTextExtents(fontinfo, hello_string, hello_string_length, 
                             &font_direction, &font_ascent, &font_descent, 
                             &text_structure);
                XGetWindowAttributes(display, frame_window, &window_attributes);
                text_x = (window_attributes.width - text_structure.width)/2;
                text_y = (window_attributes.height - 
                          (text_structure.ascent+text_structure.descent))/2;
                XDrawString(display, frame_window, graphical_context,
                            text_x, text_y, hello_string, hello_string_length);
                break;
            }
            default:
                break;
        }
    }
    return(0);
}



The code in detail

The first three lines of code open a connection to the X-Windows server and obtain a handle to the display, the visual type of display and the plane depth (Microsoft Windows uses a single plane display) of the display.

    display = XOpenDisplay(NULL);
    visual = DefaultVisual(display, 0);
    depth  = DefaultDepth(display, 0);



The next two lines sets the background colour for the window we are about to open and then opens the window. This is very similar to the Microsoft CreateWindow API call.

    frame_attributes.background_pixel = XWhitePixel(display, 0);
    /* create the application window */
    frame_window = XCreateWindow(display, XRootWindow(display, 0),
                                 0, 0, 400, 400, 5, depth,
                                 InputOutput, visual, CWBackPixel,
                                 &frame_attributes);



The next line sets the text in the title bar to 'Hello World Example' and is equivalent to the Microsoft SetWindowText API call.

    XStoreName(display, frame_window, "Hello World Example");



The next line of code tells the X-Windows server the events that we are interested in for the window we have just created. Remember, because X-Windows is client/server based we have the ability to restrict the events that we receive for an individual window and thus reduce the amount of network traffic.

    XSelectInput(display, frame_window, ExposureMask | StructureNotifyMask);



The next four lines create a suitable font for our 'Hello World' text, and create a device context suitable for the display and window on that display. These are equivalent to Microsoft CreateFont and GetDC API calls.

    fontinfo = XLoadQueryFont(display, "10x20");
    gr_values.font = fontinfo->fid;
    gr_values.foreground = XBlackPixel(display, 0);
    graphical_context = XCreateGC(display, frame_window, GCFont+GCForeground, &gr_values);



The next line of code actually displays the frame window on the display and is equivalent to the Microsoft ShowWindow API call.

    XMapWindow(display, frame_window);



We then enter our event processing loop in a similar way we do for Microsoft Windows by entering a message processing loop.

The only event we are interested in is the Expose event.

Upon receipt of an expose event, we get the bounding rectangle size for the text 'Hello World' using the XTextExtents call (Microsoft GetTextExtentPoint32 API call); get the width and height of the window using the XGetWindowAttributes call (Microsoft GetWindowInfo API call) and finally draw the string using XDrawString call (Microsoft DrawText API call).

            case Expose:
            {
                XWindowAttributes window_attributes;
                int font_direction, font_ascent, font_descent;
                XCharStruct text_structure;
                XTextExtents(fontinfo, hello_string, hello_string_length, 
                             &font_direction, &font_ascent, &font_descent, 
                             &text_structure);
                XGetWindowAttributes(display, frame_window, &window_attributes);
                text_x = (window_attributes.width - text_structure.width)/2;
                text_y = (window_attributes.height - 
                          (text_structure.ascent+text_structure.descent))/2;
                XDrawString(display, frame_window, graphical_context,
                            text_x, text_y, hello_string, hello_string_length);
                break;
            }



Is This A Good Question/Topic? 6
  • +

Replies To: Linux : Writing Our First X-Windows Application

#2 could_use_a_job  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 16-June 12

Posted 16 June 2012 - 09:09 AM

I just wanted to point out a syntax error in this tutorial that causes a Segmentation Fault error.

Line 18:

XKeyEvent event;


should be:

XEvent event


Also, if anyone is having trouble getting this to compile you might be making the same mistake I was making.

Instead of "gcc -lX11 -o tutorial tutorial.cpp" use "gcc tutorial.cpp -lX11 -o tutorial".

They look like they'd do the same thing but I assure you there's a different.

Thanks for the useful tutorial!
Was This Post Helpful? 0
  • +
  • -

#3 could_use_a_job  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 16-June 12

Posted 16 June 2012 - 09:17 AM

Oops ... that was supposed to be:

XEvent event;


I was missing a semicolon and can't seem to edit my post once it's been posted.

... and that is why I'm unemployed. Enjoy!
Was This Post Helpful? 0
  • +
  • -

#4 GroogFish  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 10-April 11

Posted 24 February 2013 - 05:23 PM

I know this is a pretty old post but I'm getting and unusual error I think. When I compile and run this through the console I get "Segmentation fault". When I run it but clicking on the compiled file through gnome it pops up fine. I'd like to be able to run it through the console.

I used sudo in case it wasn't able to access some resources and I didn't get any message but nothing happened either. No window flashed- nothing.

How can I run this through the console?
Was This Post Helpful? 0
  • +
  • -

#5 Aphex19  Icon User is offline

  • Born again Pastafarian.
  • member icon

Reputation: 615
  • View blog
  • Posts: 1,873
  • Joined: 02-August 09

Posted 25 February 2013 - 06:27 AM

Thanks. Very helpful.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1