Using select() with gtk/gdk/gnome...



Ok, I finally figured out the resizing problem with my windows.
Apparently I have to resize both the subwindow (GtkDrawingArea)
and the top-level window (GnomeApp) (and perhaps all intervening
windows, if there were any).

I'm still stuck with my select problem, where I'm polling several
file descriptors to see when input is available, including the
X11 file descriptor that gdk is using.  This doesn't seem
to work properly with gdk, when using gtk_events_pending() and 
gtk_main_iteration_do(FALSE);

Here's the code, it's pretty simple stuff.  I don't understand
why this doesn't work properly...  There should be a usable mechanism
to do what I want to do here, without me resorting to having gdk do
the select call, and incurring all the overhead of that.

If you compile and run the program what happens is the window
comes up and initially resizes properly.  If you don't do anything
then every 2 seconds select should timeout and the window should grow
or shrink by 10 pixels.  This doesn't happen.  HOWEVER, if you generate
any events to the app (just move the cursor over the menu bar for example)
the last resize happens.

Looks to me like the gtk_events_pending() call is returning FALSE
while there is still stuff queued up, because it takes a new event,
like a window crossing event, coming from the X server to drop out
of select.

Note that if the code does the gtk loop every time through the while(1)
loop, everything draws properly.  

i.e. if I change if(FD_ISSET(fd, &readfds)) to if(1 | FD_ISSET(fd, &readfds))

This tells me that there's still stuff to do, i.e. events to process,
that gtk_events_pending() isn't catching, and that are not in the X11
socket waiting to be read.  If there were anything in the X11 display
socket then select() would return and the gtk loop would be executed.
What is gdk_events_pending missing?  Why is it returning when there are
apparently still things to do?  Are there timers going off and queueing
up things to do that select doesn't catch?  Signal handlers?  What is
going on here?

Here is some very simple code generated by Glade-2 and modified by me
to do select() on the X11 socket...

--Al Amaral--


/* Start of main.c */
/*
 * Initial main.c file generated by Glade. Edit as required.
 * Glade will not overwrite this file.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gnome.h>

#include <X11/Xlib.h>
#include "interface.h"
#include "support.h"
#include <sys/select.h>


int
main (int argc, char *argv[])
{
  GtkWidget *app1;

  gnome_program_init (PACKAGE, VERSION, LIBGNOMEUI_MODULE,
                      argc, argv,
                      GNOME_PARAM_APP_DATADIR, PACKAGE_DATA_DIR,
                      NULL);

  /*
   * The following code was added by Glade to create one of each component
   * (except popup menus), just so that you see something after building
   * the project. Delete any components that you don't want shown initially.
   */
  app1 = create_app1 ();
  gtk_widget_show (app1);

#if 0
  gtk_main ();
#else
{
    GdkDisplay *pDisplay;               /* Gdk Display */
    Display *xDisplay;
    fd_set readfds;
    int size = 200;
    struct timeval timeout;
    GtkDrawingArea *pDrawingArea;
    int iter = 0;
    int delta = 10;

    int n;
    int fd;

    pDisplay = gdk_display_get_default();
    xDisplay = (Display *)gdk_x11_display_get_xdisplay(pDisplay);
    fd = ConnectionNumber(xDisplay);

    pDrawingArea = (GtkDrawingArea *)lookup_widget(app1, "drawingarea1");

    gtk_drawing_area_size(pDrawingArea, size, size);

    while(1) {

        timeout.tv_sec = 2;
        timeout.tv_usec = 0;

        FD_ZERO(&readfds);

        FD_SET(fd, &readfds);

        gdk_flush();

        /* Select on fd's, process input as needed */
        n = select(fd + 1, &readfds, NULL, NULL, &timeout);

        /* On timeout resize the window */
        if(n == 0) {

            gtk_drawing_area_size(pDrawingArea, size +=delta, size +=delta);
            gtk_window_resize (GTK_WINDOW (app1), 64, 40);

            printf("resizing by %d\n", delta);

            /* Switch resize direction after 5 iters */
            if(++iter > 5) {
                delta *= -1;
                iter = 0;
            }
        }

        /* Data on the pipe? */
        if(FD_ISSET(fd, &readfds)) {
            while(gtk_events_pending()) {
                gtk_main_iteration_do(FALSE);
            }
        }
    }
}
#endif
  return 0;
}
/* End of main.c */
/* Start of support.c */
/*
 * DO NOT EDIT THIS FILE - it is generated by Glade.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#include <gnome.h>

#include "support.h"

GtkWidget*
lookup_widget                          (GtkWidget       *widget,
                                        const gchar     *widget_name)
{
  GtkWidget *parent, *found_widget;

  for (;;)
    {
      if (GTK_IS_MENU (widget))
        parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
      else
        parent = widget->parent;
      if (!parent)
        parent = gtk_object_get_data (GTK_OBJECT (widget), "GladeParentKey");
      if (parent == NULL)
        break;
      widget = parent;
    }

  found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget),
                                                   widget_name);
  if (!found_widget)
    g_warning ("Widget not found: %s", widget_name);
  return found_widget;
}

/* This is an internally used function to create pixmaps. */
GtkWidget*
create_pixmap                          (GtkWidget       *widget,
                                        const gchar     *filename)
{
  GtkWidget *pixmap;
  gchar *pathname;

  if (!filename || !filename[0])
      return gtk_image_new ();

  pathname = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_PIXMAP,
                                        filename, TRUE, NULL);
  if (!pathname)
    {
      g_warning (_("Couldn't find pixmap file: %s"), filename);
      return gtk_image_new ();
    }

  pixmap = gtk_image_new_from_file (pathname);
  g_free (pathname);
  return pixmap;
}

/* This is an internally used function to create pixmaps. */
GdkPixbuf*
create_pixbuf                          (const gchar     *filename)
{
  gchar *pathname = NULL;
  GdkPixbuf *pixbuf;
  GError *error = NULL;

  if (!filename || !filename[0])
      return NULL;

  pathname = gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_PIXMAP,
                                        filename, TRUE, NULL);

  if (!pathname)
    {
      g_warning (_("Couldn't find pixmap file: %s"), filename);
      return NULL;
    }

  pixbuf = gdk_pixbuf_new_from_file (pathname, &error);
  if (!pixbuf)
    {
      fprintf (stderr, "Failed to load pixbuf file: %s: %s\n",
               pathname, error->message);
      g_error_free (error);
    }
  g_free (pathname);
  return pixbuf;
}

/* This is used to set ATK action descriptions. */
void
glade_set_atk_action_description       (AtkAction       *action,
                                        const gchar     *action_name,
                                        const gchar     *description)
{
  gint n_actions, i;

  n_actions = atk_action_get_n_actions (action);
  for (i = 0; i < n_actions; i++)
    {
      if (!strcmp (atk_action_get_name (action, i), action_name))
        atk_action_set_description (action, i, description);
    }
}
/* end of support.c */
/* Start of support.h */
/*
 * DO NOT EDIT THIS FILE - it is generated by Glade.
 */

#include <gnome.h>

/*
 * Public Functions.
 */

/*
 * This function returns a widget in a component created by Glade.
 * Call it with the toplevel widget in the component (i.e. a window/dialog),
 * or alternatively any widget in the component, and the name of the widget
 * you want returned.
 */
GtkWidget*  lookup_widget              (GtkWidget       *widget,
                                        const gchar     *widget_name);



/*
 * Private Functions.
 */

/* This is used to create the pixmaps used in the interface. */
GtkWidget*  create_pixmap              (GtkWidget       *widget,
                                        const gchar     *filename);

/* This is used to create the pixbufs used in the interface. */
GdkPixbuf*  create_pixbuf              (const gchar     *filename);

/* This is used to set ATK action descriptions. */
void        glade_set_atk_action_description (AtkAction       *action,
                                              const gchar     *action_name,
                                              const gchar     *description);

/* End of support.h */
/* Start of interface.c */
/*
 * DO NOT EDIT THIS FILE - it is generated by Glade.
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#include <bonobo.h>
#include <gnome.h>

#include "callbacks.h"
#include "interface.h"
#include "support.h"

#define GLADE_HOOKUP_OBJECT(component,widget,name) \
  gtk_object_set_data_full (GTK_OBJECT (component), name, \
    gtk_widget_ref (widget), (GtkDestroyNotify) gtk_widget_unref)

#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
  gtk_object_set_data (GTK_OBJECT (component), name, widget)

static GnomeUIInfo file1_menu_uiinfo[] =
{
  GNOMEUIINFO_MENU_NEW_ITEM (N_("_New"), NULL, NULL, NULL),
  GNOMEUIINFO_MENU_OPEN_ITEM (NULL, NULL),
  GNOMEUIINFO_MENU_SAVE_ITEM (NULL, NULL),
  GNOMEUIINFO_MENU_SAVE_AS_ITEM (NULL, NULL),
  GNOMEUIINFO_SEPARATOR,
  GNOMEUIINFO_MENU_EXIT_ITEM (NULL, NULL),
  GNOMEUIINFO_END
};

static GnomeUIInfo edit1_menu_uiinfo[] =
{
  GNOMEUIINFO_MENU_CUT_ITEM (NULL, NULL),
  GNOMEUIINFO_MENU_COPY_ITEM (NULL, NULL),
  GNOMEUIINFO_MENU_PASTE_ITEM (NULL, NULL),
  GNOMEUIINFO_MENU_CLEAR_ITEM (NULL, NULL),
  GNOMEUIINFO_SEPARATOR,
  GNOMEUIINFO_MENU_PROPERTIES_ITEM (NULL, NULL),
  GNOMEUIINFO_SEPARATOR,
  GNOMEUIINFO_MENU_PREFERENCES_ITEM (NULL, NULL),
  GNOMEUIINFO_END
};

static GnomeUIInfo view1_menu_uiinfo[] =
{
  GNOMEUIINFO_END
};

static GnomeUIInfo help1_menu_uiinfo[] =
{
  GNOMEUIINFO_MENU_ABOUT_ITEM (NULL, NULL),
  GNOMEUIINFO_END
};

static GnomeUIInfo menubar1_uiinfo[] =
{
  GNOMEUIINFO_MENU_FILE_TREE (file1_menu_uiinfo),
  GNOMEUIINFO_MENU_EDIT_TREE (edit1_menu_uiinfo),
  GNOMEUIINFO_MENU_VIEW_TREE (view1_menu_uiinfo),
  GNOMEUIINFO_MENU_HELP_TREE (help1_menu_uiinfo),
  GNOMEUIINFO_END
};

GtkWidget*
create_app1 (void)
{
  GtkWidget *app1;
  GtkWidget *bonobodock1;
  GtkWidget *drawingarea1;
  GtkWidget *appbar1;

  app1 = gnome_app_new ("gui", NULL);

  bonobodock1 = GNOME_APP (app1)->dock;
  gtk_widget_show (bonobodock1);

  gnome_app_create_menus (GNOME_APP (app1), menubar1_uiinfo);

  drawingarea1 = gtk_drawing_area_new ();
  gtk_widget_show (drawingarea1);
  gnome_app_set_contents (GNOME_APP (app1), drawingarea1);

  appbar1 = gnome_appbar_new (TRUE, TRUE, GNOME_PREFERENCES_NEVER);
  gtk_widget_show (appbar1);
  gnome_app_set_statusbar (GNOME_APP (app1), appbar1);

  gnome_app_install_menu_hints (GNOME_APP (app1), menubar1_uiinfo);

  /* Store pointers to all widgets, for use by lookup_widget(). */
  GLADE_HOOKUP_OBJECT_NO_REF (app1, app1, "app1");
  GLADE_HOOKUP_OBJECT (app1, bonobodock1, "bonobodock1");
  GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[0].widget, "file1");
  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[0].widget, "new1");
  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[1].widget, "open1");
  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[2].widget, "save1");
  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[3].widget, "save_as1");
  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[4].widget, "separator1");
  GLADE_HOOKUP_OBJECT (app1, file1_menu_uiinfo[5].widget, "quit1");
  GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[1].widget, "edit1");
  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[0].widget, "cut1");
  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[1].widget, "copy1");
  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[2].widget, "paste1");
  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[3].widget, "clear1");
  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[4].widget, "separator2");
  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[5].widget, "properties1");
  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[6].widget, "separator3");
  GLADE_HOOKUP_OBJECT (app1, edit1_menu_uiinfo[7].widget, "preferences1");
  GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[2].widget, "view1");
  GLADE_HOOKUP_OBJECT (app1, menubar1_uiinfo[3].widget, "help1");
  GLADE_HOOKUP_OBJECT (app1, help1_menu_uiinfo[0].widget, "about1");
  GLADE_HOOKUP_OBJECT (app1, drawingarea1, "drawingarea1");
  GLADE_HOOKUP_OBJECT (app1, appbar1, "appbar1");

  return app1;
}


/* End of interface.c */
/* Start of interface.h */
/*
 * DO NOT EDIT THIS FILE - it is generated by Glade.
 */

GtkWidget* create_app1 (void);

/* End of interface.h */
/* Start of Makefile.am */
## Process this file with automake to produce Makefile.in

INCLUDES = \
        -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
        -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
        @PACKAGE_CFLAGS@

bin_PROGRAMS = gui

gui_SOURCES = \
        main.c \
        support.c support.h \
        interface.c interface.h
        
gui_LDADD = @PACKAGE_LIBS@


/* End of Makefile.am */


------------------------------------------------------------------
Alan Amaral                                 al amaral east sun com
It's not a Sun product called PCi, it's a product called SunPCi...




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]