Hi, James and others,

I've attached a patch that makes it much easier to set the cursor (e.g.,
to a watch / wait cursor) on an entire pygtk app, as you might do before
intensive processing that will lock up the entire gtk mainloop().

This both sets the cursor and prevents key clicks and pointer clicks from
entering any windows of the app, so it's really only for use when the
entire app is busy... it's much nicer for the user to use set_cursor() and
lock only a sub-part of the app instead, whenever possible.

Nevertheless, I needed this functionality and hope that some form of
it can be included in future versions of pygtk.

The patch is a cdiff based on a somewhat modified version of pygtk 0.6.5,
so I'm not sure whether it will apply automatically on later versions...
and in any case it's likely that you'll want to change how the
functionality is packaged.  But it's not very complicated; just a few
areas of added code.

The implementation is based on X windows FAQ item number 170.  However, it
doesn't actually make any X calls and uses only GDK.  I think it has a
reasonable chance of being portable to MS Windows if GDK there handles
input-only windows correctly... probably not hard to do but at this point
I have no idea what the actual status of this might be.

If you have any questions about this, let me know.

Thanks!

- Stephan

------------------------------------------------------------------------
Archaeopteryx Software, Inc.                        Wing IDE for Python 
www.archaeopteryx.com                               Take Flight!


----------------------------------

Index: gtk.py
===================================================================
RCS file: /home/cvs/src/ide/external/pygtk-0.6.5-wing/gtk.py,v
retrieving revision 1.8
diff -c -r1.8 gtk.py
*** gtk.py      2000/09/25 19:47:24     1.8
--- gtk.py      2000/10/20 23:54:57
***************
*** 876,881 ****
--- 876,891 ----
                _gtk.gtk_window_set_default_size(self._o, width, height)
        def set_modal(self, modal):
                _gtk.gtk_window_set_modal(self._o, modal)
+               
+       # WINGIDE_EXTENSIONS
+       def block_with_cursor(self, cursor):
+               """ Block typing and pointer activity in given window and
+               show the given cursor.  This returns a GdkWindow.  Tossing
+               your reference to it ends the block.  This is primarily
+               useful for setting the wait cursor during busy times. """
+               gdk_window = self.get_window()
+               _gtk.gdk_window_block_with_cursor(gdk_window, cursor)
+               return gdk_window
  
  class GtkColorSelectionDialog(GtkWindow):
        get_type = _gtk.gtk_color_selection_dialog_get_type
***************
*** 2737,2742 ****
--- 2747,2756 ----
  keyval_is_lower = _gtk.gdk_keyval_is_lower
  keyval_to_upper = _gtk.gdk_keyval_to_upper
  keyval_to_lower = _gtk.gdk_keyval_to_lower
+ 
+ # WINGIDE_EXTENSIONS
+ # See GtkWindow.block_with_cursor
+ gdk_window_block_with_cursor = _gtk.gdk_window_block_with_cursor
  
  # screen size
  def screen_width():
Index: gtkmodule.c
===================================================================
RCS file: /home/cvs/src/ide/external/pygtk-0.6.5-wing/gtkmodule.c,v
retrieving revision 1.10
diff -c -r1.10 gtkmodule.c
*** gtkmodule.c 2000/09/28 22:49:52     1.10
--- gtkmodule.c 2000/10/20 23:55:23
***************
*** 294,299 ****
--- 294,302 ----
    if (self == NULL)
      return NULL;
    self->obj = win;
+ #ifdef WINGIDE_EXTENSIONS
+   self->cursor_win = NULL;
+ #endif
    gdk_window_ref(self->obj);
    return (PyObject *)self;
  }
***************
*** 1321,1326 ****
--- 1324,1337 ----
      gdk_pixmap_unref(self->obj);
    else
      gdk_window_unref(self->obj);
+ #ifdef WINGIDE_EXTENSIONS
+   if (self->cursor_win != NULL) {
+     gdk_window_set_cursor(self->cursor_win->obj, NULL);
+     gdk_window_hide(self->cursor_win->obj);
+     Py_DECREF(self->cursor_win);
+     self->cursor_win = NULL;
+   }
+ #endif
    PyMem_DEL(self);
  }
  
***************
*** 6524,6529 ****
--- 6535,6601 ----
      return Py_BuildValue("i", lower_val);
  }
  
+ #ifdef WINGIDE_EXTENSIONS
+ // A function to start showing the given cursor on the entire given gdk window,
+ // regardless of what any sub-windows are doing, and to block all keyboard
+ // and other entry to windows.  The function returns a reference to a 
+ // GdkWindow and the cursor block will continue until that reference is
+ // discarded by the caller.
+ // This is based on X FAQ item number 170:  We install an INPUT_ONLY
+ // window as the child of the window given and set the cursor in it
+ // to the wait cursor
+ static PyObject *_wrap_gdk_window_block_with_cursor(PyObject *self, PyObject *args) {
+     PyObject *parent;
+     PyGdkWindow_Object *pygdkparent;
+     PyGdkWindow_Object *cursor_win;
+     GdkWindow *gdkparent;
+     GdkWindowAttr attr;
+     PyObject *cursor;
+     
+     // Parse args
+     if (!PyArg_ParseTuple(args, "OO:gdk_set_window_cursor", &parent, &cursor))
+       return NULL;
+     pygdkparent = (PyGdkWindow_Object *) parent;
+ 
+     // Bail out if already set
+     if (pygdkparent->cursor_win != NULL) {
+       Py_INCREF(Py_None);
+       return Py_None;
+     }
+ 
+     // Create the input-only window as child of given parent
+     attr.wclass = GDK_INPUT_ONLY;
+     attr.x = 0;
+     attr.y = 0;
+     attr.width = 32767;
+     attr.height = 32767;
+     cursor_win = (PyGdkWindow_Object *) 
+PyGdkWindow_New(gdk_window_new(pygdkparent->obj, &attr, 
+                                                         GDK_WA_X | GDK_WA_Y | 
+GDK_WA_WMCLASS));
+ 
+     // Set cursor on the window    
+     if (PyGdkCursor_Check(cursor))
+       gdk_window_set_cursor(cursor_win->obj, PyGdkCursor_Get(cursor));
+     else if (cursor == Py_None)
+       gdk_window_set_cursor(cursor_win->obj, NULL);
+     else {
+       PyErr_SetString(PyExc_TypeError, 
+                       "cursor must either be a GdkCursor instance or None");
+       return NULL;
+     }
+ 
+     // Map and raise the cursor window
+     gdk_window_show(cursor_win->obj);
+ 
+     // Save the window ref
+     pygdkparent->cursor_win = cursor_win;
+     
+     
+     // Success:  Return the parent
+     Py_INCREF(parent);
+     return parent;
+ }
+ #endif
+ 
  static PyMethodDef _gtkmoduleMethods[] = {
      { "gtk_signal_connect", _wrap_gtk_signal_connect, 1 },
      { "gtk_signal_connect_after", _wrap_gtk_signal_connect_after, 1 },
***************
*** 6566,6571 ****
--- 6638,6646 ----
      { "gtk_window_set_icon", _wrap_gtk_window_set_icon, 1 },
      { "gtk_window_set_icon_name", _wrap_gtk_window_set_icon_name, 1 },
      { "gtk_window_set_geometry_hints", _wrap_gtk_window_set_geometry_hints, 1 },
+ #ifdef WINGIDE_EXTENSIONS
+     { "gdk_window_block_with_cursor", _wrap_gdk_window_block_with_cursor, 1 },
+ #endif
      { "gtk_box_query_child_packing", _wrap_gtk_box_query_child_packing, 1 },
      { "gtk_button_box_get_child_size_default", 
_wrap_gtk_button_box_get_child_size_default, 1 },
      { "gtk_button_box_get_child_ipadding_default", 
_wrap_gtk_button_box_get_child_ipadding_default, 1 },
Index: pygtk.h
===================================================================
RCS file: /home/cvs/src/ide/external/pygtk-0.6.5-wing/pygtk.h,v
retrieving revision 1.1
diff -c -r1.1 pygtk.h
*** pygtk.h     2000/03/13 18:45:37     1.1
--- pygtk.h     2000/10/20 23:55:25
***************
*** 2,7 ****
--- 2,10 ----
  #ifndef _PYGTK_H_
  #define _PYGTK_H_
  
+ // Turn off to disable our extra calls
+ #define WINGIDE_EXTENSIONS
+ 
  #include <Python.h>
  #include <gtk/gtk.h>
  
***************
*** 103,111 ****
      PyObject *attrs;
  } PyGdkEvent_Object;
  
! typedef struct {
      PyObject_HEAD
      GdkWindow *obj;
  } PyGdkWindow_Object;
  
  typedef struct {
--- 106,117 ----
      PyObject *attrs;
  } PyGdkEvent_Object;
  
! typedef struct _PyGdkWindow_Object {
      PyObject_HEAD
      GdkWindow *obj;
+ #ifdef WINGIDE_EXTENSIONS
+     struct _PyGdkWindow_Object *cursor_win;
+ #endif
  } PyGdkWindow_Object;
  
  typedef struct {


_______________________________________________
pygtk mailing list   [EMAIL PROTECTED]
http://www.daa.com.au/mailman/listinfo/pygtk

Reply via email to