LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 10-23-2010, 12:09 AM   #1
adixon
Member
 
Registered: Oct 2010
Posts: 34

Rep: Reputation: 3
X11 Menus (how to)


Hey people,
I'm currently wanting to add menus to my X11 gui, if possible in the platform recommended way. For example on windows I can just create a resource file, is there something similar on linux?
Thanks, Alex
 
Old 10-23-2010, 09:18 AM   #2
x-nc
Member
 
Registered: Feb 2007
Location: VA, USA
Distribution: CentOS, Fedora
Posts: 53

Rep: Reputation: 5
Thumbs up

Quote:
Originally Posted by adixon View Post
Hey people,
I'm currently wanting to add menus to my X11 gui, if possible in the platform recommended way. For example on windows I can just create a resource file, is there something similar on linux?
Thanks, Alex
This depends on which desktop or window manager you are using. It is likely to be GNOME or KDE, in most cases. The conceptual/functional equivalent you are looking for the the .desktop file. This is part of the Freedesktop project and you can find information and software relating to it at -

http://www.freedesktop.org/
 
Old 10-23-2010, 09:50 AM   #3
adixon
Member
 
Registered: Oct 2010
Posts: 34

Original Poster
Rep: Reputation: 3
Hey x-nc,
thanks for reply; are you saying that by modifying a .desktop file my app
(which im restricting to pure X11, so no glut,gtk,xt,etc.) will run with menus? Im not sure, but I think this freedesktop project is about the main menu (analogous to windows 'start menu').


I want something along the lines of

..
Code:
IDR_MYMENU MENU DISCARDABLE 

BEGIN

    POPUP "&File"

    BEGIN

        MENUITEM "E&xit",                       ID_FILE_EXIT

    END

    POPUP "&Stuff"

    BEGIN

        MENUITEM "&Go",                         ID_STUFF_GO

        MENUITEM "Go &Somewhere Else",          ID_STUFF_GOSOMEWHEREELSE

        , GRAYED

    END

END
.. (this code would add my funcionality for windows development)

in some resource file which I can compile into my X11 gui, alternatively if this resource thing is not how things are done on linux, im interested in how people normally add menus to their gui's.

thanks, alex
 
Old 10-24-2010, 12:11 AM   #4
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
X11, by itself, doesn't do menus. That is why toolkits like GTK, Qt, Motif, etc were created. If you want to roll your own, you will be doing a lot of work, but will learn a huge amount about how those other nice tools came to exist.

--- rod.
 
1 members found this post helpful.
Old 10-24-2010, 12:57 AM   #5
adixon
Member
 
Registered: Oct 2010
Posts: 34

Original Poster
Rep: Reputation: 3
Thanks theNbomr,
I guess ill have to make my own,
regards, alex
 
Old 10-24-2010, 12:37 PM   #6
x-nc
Member
 
Registered: Feb 2007
Location: VA, USA
Distribution: CentOS, Fedora
Posts: 53

Rep: Reputation: 5
Question

Sorry, adixon, I misunderstood what you meant. theNbomr got to it before I did but I was only going to say the same thing anyway. One question, though...

When you say make your own, you don't mean a toolkit (i.e. GTK+, Qt, etc.), do you? That would be like recreating DirectX just to write a basic form. Also, if you are coming from WinXX programing and have worked with C#/.NET, you might want to look at the Mono or DotGNU projects.
 
Old 10-29-2010, 11:01 PM   #7
adixon
Member
 
Registered: Oct 2010
Posts: 34

Original Poster
Rep: Reputation: 3
Hey x-nc,
sorry to get back so late;
basically I'm making my own primitive menu handling system, not as you say a whole toolkit.
You're right, c# .net with form builders, etc. would make this sort of task very easy.
Mostly though I'm trying to write a very minimal c gui in both X11 and windows; not linking to a library like glut only to use a few functions - and at the end I want to speed test X11 against a similarly coded glut of the same gui, and the same for the windows. The point is to measure the speed gain of platform-specific code, and develop a nice app at same time.
 
Old 10-30-2010, 12:15 AM   #8
x-nc
Member
 
Registered: Feb 2007
Location: VA, USA
Distribution: CentOS, Fedora
Posts: 53

Rep: Reputation: 5
Quote:
Originally Posted by adixon View Post
sorry to get back so late;
No problem at all.

Your idea sounds like fun. Let us know when you have something to play with.
 
Old 10-30-2010, 12:45 PM   #9
adixon
Member
 
Registered: Oct 2010
Posts: 34

Original Poster
Rep: Reputation: 3
Hey x-nc,
This is my minimal menu header:

Code:
#ifndef __menu__

#define __menu__

#include <string.h>

#define item_name_limit 50

#define none_selected -1

#define no_menu -1

#define max_font_name_length 60

#define GetNumMenus(X) X->num_menus

#define GetNumFonts(X) X->num_fonts

#define LineHeight(X,Y,Z) ((double)(X->size[2]+X->size[3])*(Y-Z))/(double)X->gwa.height

#define MenuName(X,Y) X->menus[Y].menu_name

#define MenuStart(X,Y) x_left+(X->menus[Y].x_start/(double)X->gwa.width)*(x_right-x_left)

#define MenuWidth(X,Y) ((double)X->menus[Y].width/(double)window_info->gwa.width)*(x_right-x_left)

#define GetState(X) (X->state-1)



typedef struct Menu Menu;

typedef struct Item Item;

struct Menu

{

 Item *items;

 int num_items;

 int active;

 int selected;

 int menu_id;

 char *menu_name;

 double x_start;

 double x_end;

 double width;

};

struct Item

{

 char *item_name;

 int menu_id;

 void (*action)(void *data);

};

int create_item(Item *item,char *name,int submenu_id, void (*callbk)(void *data))

{

 if (strlen(name) > item_name_limit)

 {

  return 1;

 }

 item->item_name = (char*)malloc((strlen(name)+1)*sizeof(char));

 if (memcpy(item->item_name,name,strlen(name)*sizeof(char)) == NULL)

 {

  return 1;

 }

 item->item_name[strlen(name)]='\0';

 item->menu_id = submenu_id;

 item->action = callbk;

 return 0;

}

int create_menu(Menu *menu,Item *item,int number_items,int id,char *name)

{

 menu->num_items = number_items;

 menu->items = (Item *)malloc(menu->num_items * sizeof(Item));

 if (memcpy(menu->items,item,menu->num_items * sizeof(Item)) == NULL)

 {

  return 1;

 }

 menu->selected = none_selected;

 menu->menu_id = id;



 menu->menu_name = (char*)malloc((strlen(name)+1)*sizeof(char));

 if (memcpy(menu->menu_name,name,strlen(name)*sizeof(char)) == NULL)

 {

  return 1;

 }

 menu->menu_name[strlen(name)] = '\0';

 return 0;

}



typedef struct

{

 XWindowAttributes gwa;

 int state;

 Menu *menus;

 int num_menus;

 char **font_names;

 int num_fonts;

 int *size;

 GLuint *font_lists;

 XFontStruct *font_info;

}WindowInfo;



void create_WindowInfo(WindowInfo *window_info,int num_menu,int numFonts)

{

 int index = 0;

 window_info->num_menus = num_menu;

 window_info->menus = (Menu*)malloc(GetNumMenus(window_info)*sizeof(Menu));

 window_info->num_fonts = numFonts;

 window_info->font_lists = (GLuint*)malloc(GetNumFonts(window_info)*sizeof(GLuint));

 window_info->font_info = (XFontStruct*)malloc(GetNumFonts(window_info)*sizeof(XFontStruct));

 window_info->size = (int*)malloc(GetNumFonts(window_info)*2*sizeof(int));

 window_info->state=0;

 window_info->font_names = (char**)malloc(GetNumFonts(window_info)*sizeof(char*));

 while (index<(window_info->num_fonts))

 {

  window_info->font_names[index] = (char*)malloc(max_font_name_length*sizeof(char));

  ++index;

 }

}





#endif

and the trivial test program

Code:
#include <stdio.h>
#ifdef __WIN32__
int main(int argc, char **argv)
{
 fprintf(stdout,"\tnot for windows\n");
 return 0;
}
#endif
#ifdef __linux__
#include <string.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h>
#include <X11/Xatom.h>
#include "menu.h"
#define x_left -1
#define x_right 8.2
#define y_bot -1
#define y_top 17
#define left_click Button1
#define right_click Button3
#define open_menu 1
#define close_menu 3
#define run_command 4
#define left_menu_padding 10
#define top_menu_padding 0.1

void test(void *data)
{
 fprintf(stdout,"\tcallback test..\n");
}

int load_font(XFontStruct *font_info,char *font,Display *dpy,GLuint font_base,int *size)
{
 font_info = XLoadQueryFont(dpy,font);
 size[0] = font_info->ascent;
 size[1] = font_info->descent;
 if (!font_info)
 {
  return 1;
 }
 glXUseXFont(font_info->fid,font_info->min_char_or_byte2,font_info->max_char_or_byte2-font_info->min_char_or_byte2+1,font_base+font_info->min_char_or_byte2);
 return 0;
}

int print_string(GLuint font_base, char* s)
{
 if (!glIsList(font_base)) 
 {
  return 1;
 }
 glPushAttrib(GL_LIST_BIT);
 glListBase(font_base);
 glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *)s);
 glPopAttrib();
 return 0;
}

int drawMenubar(WindowInfo *window_info)
{
 int index = 0, error = 0;
 double x,y;
 y = y_top - ((double)window_info->size[2]/(double)window_info->gwa.height)*(y_top-y_bot);
 while (index<(window_info->num_menus))
 {
  glColor3f(1,1,1);
  x = MenuStart(window_info,index);
  glRasterPos2f(x,y);
  error += print_string(window_info->font_lists[1],MenuName(window_info,index));
  ++index;
 }
 y = y_top-LineHeight(window_info,y_top,y_bot);
 glColor3f(0,0,0);
 glBegin(GL_POLYGON);
  glVertex3f(x_left,y_top,0);  glVertex3f(x_right,y_top,0);
  glVertex3f(x_right,y,0);   glVertex3f(x_left,y,0);
 glEnd();
 return error;
}

int drawMenu(WindowInfo *window_info)
{
 int error = 0, index = 0;
 double y, line_height, x;
 line_height = LineHeight(window_info,y_top,y_bot);
 y = (double)(2*window_info->size[2]+window_info->size[3]);
 y = y*(y_top-y_bot);
 y = y/(double)window_info->gwa.height;
 y = y_top - y;
 x = MenuStart(window_info,GetState(window_info));
 while (index < (window_info->menus[GetState(window_info)].num_items))
 {
  if (index == window_info->menus[GetState(window_info)].active)
  {
   glColor3f(0,1,0);
  }
  else
  {
   glColor3f(1,1,1);
  }
  glRasterPos2f(x,y);
  error += print_string(window_info->font_lists[1],window_info->menus[GetState(window_info)].items[index].item_name);
  y -= (line_height);
  ++index;
 }
 glColor3f(0,0,0);
 y = y_top - (window_info->menus[GetState(window_info)].num_items + 1)*line_height;
 glBegin(GL_POLYGON);
  glVertex3f(x,y,0);
  glVertex3f(x+MenuWidth(window_info,GetState(window_info))+0.1,y,0);
  glVertex3f(x+MenuWidth(window_info,GetState(window_info))+0.1,y_top - line_height,0);
  glVertex3f(x,y_top - line_height,0);
 glEnd();
 return error;
}

int draw(WindowInfo *window_info)
{
 int error = 0;
 glClearColor(1.0, 1.0, 1.0, 1.0);
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 glOrtho(x_left, x_right, y_bot, y_top, 1., 20.);

 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 gluLookAt(0., 0., 10., 0., 0., 0., 0., 1., 0.);

 error = drawMenubar(window_info); 

 if (window_info->state != 0)
 {
  error += drawMenu(window_info);
 }
 return error;
}

int initialize_menu(WindowInfo *window_info,Display *dpy)
{
 XFontStruct *menu_font;
 int error = 0, index = 0, item_index = 0;
 double x = 0, width = 0, temp;
 Item *items = (Item*)malloc(2*sizeof(Item));
 Item *items_two = (Item*)malloc(3*sizeof(Item));
 error = create_item(&items[0],"Crash\0",no_menu,&test) + create_item(&items[1],"Save\0",no_menu,&test);
 error += create_item(&items_two[0],"Calm\0",no_menu,&test) + create_item(&items_two[1],"Obsessive\0",no_menu,&test) +create_item(&items_two[2],"Godlike\0",no_menu,&test);
 if (error == 0)
 {
  error = create_menu(&(window_info->menus[0]),items,2,1,"File\0") + create_menu(&(window_info->menus[1]),items_two,3,2,"Mode\0");
 }
 free(items);
 free(items_two);
 menu_font = XLoadQueryFont(dpy,window_info->font_names[1]);
 while (index<(window_info->num_menus))
 {
  window_info->menus[index].x_start = x;
  x += XTextWidth(menu_font,window_info->menus[index].menu_name,strlen(window_info->menus[index].menu_name));
  window_info->menus[index].x_end = x;
  x += left_menu_padding;
  while (item_index < window_info->menus[index].num_items)
  {
   temp = XTextWidth(menu_font,window_info->menus[index].items[item_index].item_name,strlen(window_info->menus[index].items[item_index].item_name));
   width = (temp > width) ? temp : width;
   ++item_index;
  }item_index = 0;
  window_info->menus[index].width = width;
  ++index;
 }
 return error;
}

int whichMenu(WindowInfo *window_info,double x)
{
 int index = window_info->num_menus - 1;
 while (index > 0 && (MenuStart(window_info,index) > x))
 {
  --index;
 }
 return index + 1;
}

int whichActive(WindowInfo *window_info,double x,double y)
{
 int index = 0;
 double y_cat, line_height, x_min, x_max;
 line_height = LineHeight(window_info,y_top,y_bot);
 y_cat = y_top - line_height;
 x_min = MenuStart(window_info,GetState(window_info));
 x_max = x_min + MenuWidth(window_info,GetState(window_info));
 if (y > y_cat || x < x_min || x > x_max)
 {
  return -1;
 }
 y_cat -= line_height;
 while (x>x_min && x<x_max && y<y_cat && index<window_info->menus[GetState(window_info)].num_items)
 {
  y_cat -= (line_height);
  ++index;
 }
 return (index != window_info->menus[GetState(window_info)].num_items) ? index : -2;
}

int messageHandler(Display *dpy,XEvent xev,WindowInfo *window_info,Window win,Atom wmDeleteMessage)
{
 int buttoncase,click_x,click_y,error,check;
 double x_limit,y_limit,x,y;
 while(1) 
 {
  XNextEvent(dpy, &xev);
  switch(xev.type)
  {
   case MotionNotify:
    if (window_info->state !=0)
    {
     x = x_left+((double)xev.xmotion.x/(double)window_info->gwa.width)*(x_right-x_left);
     y = y_top - ((double)xev.xmotion.y/(double)window_info->gwa.height)*(y_top-y_bot);
     check = window_info->menus[GetState(window_info)].active;
     window_info->menus[GetState(window_info)].active = whichActive(window_info,x,y);
     if (check != window_info->menus[GetState(window_info)].active)
     {
      error = draw(window_info);
      glXSwapBuffers(dpy, win);
     }
    }
    break;
   case ButtonPress:
    x_limit = x_left + (window_info->menus[window_info->num_menus-1].x_end/(double)window_info->gwa.width)*(x_right-x_left);
    y_limit = y_top - LineHeight(window_info,y_top,y_bot);
    x = x_left+((double)xev.xbutton.x/(double)window_info->gwa.width) *(x_right-x_left);
    click_x = (x<0) ? -1 : (int)x;
    y = y_bot + ((double)(window_info->gwa.height)-(double)xev.xbutton.y)*((double)y_top - (double)y_bot)/((double)window_info->gwa.height);
    click_y = (y<0) ? -1 : (int)y;
    buttoncase = open_menu*(xev.xbutton.button == left_click)*(window_info->state==0)*(x<x_limit)*(y>y_limit);
    buttoncase += close_menu*(window_info->state!=0)*(whichActive(window_info,x,y) < 0);
    buttoncase += run_command*(window_info->state!=0)*(whichActive(window_info,x,y) >= 0);
    switch(buttoncase)
    {
     case open_menu:
      window_info->state = whichMenu(window_info,x);
      break;
     case close_menu:
      window_info->state = 0;
      break;
     case run_command:
      window_info->menus[GetState(window_info)].items[window_info->menus[GetState(window_info)].active].action(NULL);
      break;
     default:
      break;
    }
   case Expose: 
    XGetWindowAttributes(dpy, win, &(window_info->gwa));
    glViewport(0, 0, window_info->gwa.width, window_info->gwa.height);
    error = draw(window_info);
    if (error != 0)
    {
     fprintf(stdout,"\tfont failure: %d\n",error);
     return 0;
    } 
    glXSwapBuffers(dpy, win);
    break;
   case ClientMessage: 
    if(xev.xclient.data.l[0] == wmDeleteMessage)
    {        
     return 0;
    }
    break;
   default:
    break;
  }
 }
 return 0;
}

int main(int argc, char **argv) 
{
 WindowInfo *window_info;
 int error;
 Display                 *dpy;
 Window                  root;
 GLint                   att[] = {GLX_RGBA,GLX_DEPTH_SIZE,24,GLX_DOUBLEBUFFER,None};
 XVisualInfo             *vi;
 Colormap                cmap;
 XSetWindowAttributes    swa;
 Window                  win;
 GLXContext              glc;
 XEvent                  xev;
 XSizeHints 		 *xsh;

 Atom wmDeleteMessage;

 xsh = XAllocSizeHints();
 xsh->flags = PMinSize | PMaxSize;
 xsh->min_height = 600;
 xsh->min_width  = 600;
 xsh->max_height = 600;
 xsh->max_width  = 600;

 window_info = (WindowInfo*)malloc(sizeof(WindowInfo));

 create_WindowInfo(window_info,2,2);

 memcpy(window_info->font_names[0],"lucidasans-italic-24\0",strlen("lucidasans-italic-24\0"));
 
 window_info->font_names[0][strlen("lucidasans-italic-24\0")] = '\0';

 memcpy(window_info->font_names[1],"lucidasans-italic-12\0",strlen("lucidasans-italic-12\0"));

 window_info->font_names[1][strlen("lucidasans-italic-12\0")] = '\0';

 dpy = XOpenDisplay(NULL);
 
 if(dpy == NULL) {
 	printf("\n\tcannot connect to X server\n\n");
        exit(0); }
        
 root = DefaultRootWindow(dpy);

 vi = glXChooseVisual(dpy, 0, att);

 if(vi == NULL) {
	printf("\n\tno appropriate visual found\n\n");
        exit(0); } 

 cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);

 swa.colormap = cmap;
 swa.event_mask = ExposureMask | ButtonPressMask | PointerMotionMask;
 
 win = XCreateWindow(dpy, root, 0, 0, 600, 600, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);



 wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
 XSetWMProtocols(dpy, win, &wmDeleteMessage, 1);
 XMapWindow(dpy, win);
 XStoreName(dpy, win, "menu_demo");
 
 glc = glXCreateContext(dpy, vi, NULL, GL_TRUE);
 glXMakeCurrent(dpy, win, glc);
 XSetWMNormalHints(dpy, win, xsh);

 window_info->font_lists[0] = glGenLists(256);
 if (!glIsList(window_info->font_lists[0])) 
 {
  fprintf(stdout,"\tfont list failure\n");
  return 0;
 }

 window_info->font_lists[1] = glGenLists(256);
 if (!glIsList(window_info->font_lists[1])) 
 {
  fprintf(stdout,"\tfont list failure\n");
  return 0;
 }

 if (load_font(window_info->font_info,window_info->font_names[0],dpy,window_info->font_lists[0],window_info->size) != 0)
 {
  fprintf(stdout,"\tfont load failure\n");
  return 0;
 }

 if (load_font(&(window_info->font_info[1]),window_info->font_names[1],dpy,window_info->font_lists[1],&(window_info->size[2])) != 0)
 {
  fprintf(stdout,"\tfont load failure\n");
  return 0;
 }
 error = initialize_menu(window_info,dpy);
 if (error !=0)
 {
  fprintf(stdout,"\tMenu failed\n");
  return 0;
 }


 glEnable(GL_DEPTH_TEST);

 error = messageHandler(dpy,xev,window_info,win,wmDeleteMessage);

 glXMakeCurrent(dpy, None, NULL);
 glXDestroyContext(dpy, glc);
 XDestroyWindow(dpy, win);
 XCloseDisplay(dpy);
 XFree(xsh);
 free(window_info);
 return 0;
}
#endif
it will compile with ansi, pedantic, Wall compiler options

let me know what you think;
regards, alex
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
X11(gnome) restarts when accessing menus bkerndt Linux - Software 0 11-23-2007 06:55 PM
xorg-x11-devel dependant on old version of xorg-x11-libs thetawaverider Linux - Software 1 11-09-2006 07:22 AM
Core 4 - X11-devel complains about X11-libs which are installed Ephracis Fedora 3 09-05-2005 09:32 AM
xorg-x11-libs required by xorg-x11-devel darknails Fedora 1 01-13-2005 02:34 PM
Roaming X11/Xfree86, X11 proxy zapp Linux - Software 1 09-12-2003 08:06 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:25 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration