Hi,

Here is a patch for pygtk that exposes some of the lower-level gdk_window
functionality (creation of a gdk_window, show, hide, & destroy) to Python.

The motivation for this was a need to use an INPUT_ONLY GDK window to set
the cursor on the entire surface of a window, and to block mouse and
keyboard interaction with that window during that time (as you would when
the GUI is going to be unresponsive for a while due to some more lengthy
syncronous operation).

This could be used for other things as well, wherever there is a need to
temporarily overlay an existing window with an event-trapping transparent
window.

With this patch, you can now say something like this to set up a watch
cursor on any gtk_window:

  gdk_window = my_gtkwindow.get_window()
  attribs = { 'wmclass': GDK.INPUT_ONLY,
              'window_type': GDK.WINDOW_CHILD,
              'event_mask': 0,
              'x': 0,
              'y': 0,
              'width': gtk.screen_width(),
              'height': gtk.screen_height() }
  cursor_win = gtk.gdk_window_new(gdk_window, attribs)
  gdk_cursor = gtk.cursor_new(GDK.WATCH)
  cursor_win.set_cursor(gdk_cursor)
  cursor_win._show()

To set things back to normal you do this:

  cursor_win._hide()

To show the watch again later:

  cursor_win._show()

And when you're done with the cursor-setting window you say:

  cursor_win.destroy()
  cursor_win = None

This patch replaces the one that was sent by me to this list on Fri, 20
Oct 2000 20:28:38 -0400 (EDT).  It is a cdiff based on a somewhat modified
pygtk 0.6.5, so may not apply automatically.  But hopefully it's not too
hard to figure out, since it's just a set of added functions in several
files.  The 'WINGIDE_EXTENSION' ifdefs and comments can of course be
removed.

Please let me know if you have any questions or run into any problems
with this.

I hope that it's something that can be considered for a future version
of pygtk.

Thanks,

- Stephan

------------------------------------------------------------------------
Archaeopteryx Software, Inc.                        Wing IDE for Python 
www.archaeopteryx.com                               Take Flight!
Index: GDK.py
===================================================================
RCS file: /home/cvs/src/ide/external/pygtk-0.6.5-wing/GDK.py,v
retrieving revision 1.1
diff -c -r1.1 GDK.py
*** GDK.py      2000/03/13 18:45:37     1.1
--- GDK.py      2000/10/27 15:04:30
***************
*** 294,299 ****
--- 294,313 ----
  XTERM = 152
  CURSOR_IS_PIXMAP = -1
  
+ # WINGIDE_EXTENSIONS
+ # GdkWindowClass's
+ INPUT_OUTPUT = 0
+ INPUT_ONLY = 1
+ 
+ # GdkWindowType's
+ WINDOW_ROOT = 0
+ WINDOW_TOPLEVEL = 1
+ WINDOW_CHILD = 2
+ WINDOW_DIALOG = 3
+ WINDOW_TEMP = 4
+ WINDOW_PIXMAP = 5
+ WINDOW_FOREIGN = 6
+ # END WINGIDE_EXTENSIONS
  
  # these are the Key Symbols for GDK
  # they were created with sed -n 's/#define GDK)\([^ ]*\)/\1 =/p' <gdkkeysyms.h
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/27 15:04:41
***************
*** 2738,2743 ****
--- 2738,2769 ----
  keyval_to_upper = _gtk.gdk_keyval_to_upper
  keyval_to_lower = _gtk.gdk_keyval_to_lower
  
+ # WINGIDE_EXTENSIONS
+ # Low-level function to create new gdk window
+ def gdk_window_new(parent, attribs):
+       """ Creates a new gdk window which must be destroyed with an
+       explicit call to the _destroy() method.  parent is the new 
+       window's parent PyGdkWindow or None if the window should be a 
+       child of the root window.  attribs must be a dictionary of 
+       attribute values for the window; the following attribs must 
+       be specified:
+         window_type -- GDK.WINDOW_TOPLEVEL, GDK.WINDOW_CHILD
+                        GDK.WINDOW_DIALOG, GDK.WINDOW_TEMP
+                        GDK.WINDOW_PIXMAP, or GDK.WINDOW_FOREIGN
+         event_mask -- the events to get
+         width -- width of window
+         height -- height of window
+       The following attributes are optional:
+         wmclass -- GDK.INPUT_OUTPUT or GDK.INPUT_ONLY
+         x -- x offset from parent
+         y -- y offset from parent
+         colormap -- PyGdkColormap to use to interpret colors
+         override_redirect -- see gdk / X documentation
+       """
+       
+       return _gtk.gdk_window_new(parent, attribs)
+ # END WINGIDE_EXTENSIONS
+ 
  # screen size
  def screen_width():
        return _gtk.gdk_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/27 15:05:30
***************
*** 1665,1670 ****
--- 1665,1700 ----
    return Py_None;
  }
  
+ #define WINGIDE_EXTENSIONS
+ #ifdef WINGIDE_EXTENSIONS
+ static PyObject *PyGdkWindow_Show(PyGdkWindow_Object *self,
+                                  PyObject *args) {
+   if (!PyArg_ParseTuple(args, ":GdkWindow._show"))
+     return NULL;
+   gdk_window_show(self->obj);
+   Py_INCREF(Py_None);
+   return Py_None;
+ }
+ 
+ static PyObject *PyGdkWindow_Hide(PyGdkWindow_Object *self,
+                                  PyObject *args) {
+   if (!PyArg_ParseTuple(args, ":GdkWindow._hide"))
+     return NULL;
+   gdk_window_hide(self->obj);
+   Py_INCREF(Py_None);
+   return Py_None;
+ }
+ 
+ static PyObject *PyGdkWindow_Destroy(PyGdkWindow_Object *self,
+                                  PyObject *args) {
+   if (!PyArg_ParseTuple(args, ":GdkWindow._destroy"))
+     return NULL;
+   gdk_window_destroy(self->obj);
+   Py_INCREF(Py_None);
+   return Py_None;
+ }
+ #endif
+ 
  static PyObject *PyGdkWindow_InputGetPointer(PyGdkWindow_Object *self,
                                             PyObject *args) {
    guint32 deviceid;
***************
*** 1685,1690 ****
--- 1715,1725 ----
    {"property_change", (PyCFunction)PyGdkWindow_PropertyChange, METH_VARARGS, NULL},
    {"property_delete", (PyCFunction)PyGdkWindow_PropertyDelete, METH_VARARGS, NULL},
    {"_raise", (PyCFunction)PyGdkWindow_Raise, METH_VARARGS, NULL},
+ #ifdef WINGIDE_EXTENSIONS
+   {"_show", (PyCFunction)PyGdkWindow_Show, METH_VARARGS, NULL},
+   {"_hide", (PyCFunction)PyGdkWindow_Hide, METH_VARARGS, NULL},
+   {"_destroy", (PyCFunction)PyGdkWindow_Destroy, METH_VARARGS, NULL},
+ #endif
    {"lower", (PyCFunction)PyGdkWindow_Lower, METH_VARARGS, NULL},
    {"input_get_pointer", (PyCFunction)PyGdkWindow_InputGetPointer, METH_VARARGS, 
NULL},
    {NULL, 0, 0, NULL}
***************
*** 6524,6529 ****
--- 6559,6706 ----
      return Py_BuildValue("i", lower_val);
  }
  
+ 
+ #ifdef WINGIDE_EXTENSIONS
+ static PyObject* _wrap_gdk_window_new(PyObject *self, PyObject *args) {
+     PyObject *parent;
+     PyObject *attr_map;
+     GdkWindow* gdk_parent;
+     GdkWindow* gdk_win;
+     PyObject* pygdk_win;
+     GdkWindowAttr attr;
+     guint attr_mask = 0;
+     PyObject *tmp;
+     
+     // Parse args
+     if (!PyArg_ParseTuple(args, "OO!:gdk_window_new", &parent, &PyDict_Type,
+                           &attr_map))
+       return NULL;
+ 
+     if (parent == Py_None) 
+         gdk_parent = NULL;
+     else if (PyGdkWindow_Check(parent))
+         gdk_parent = ((PyGdkWindow_Object *) parent)->obj;
+     else {
+         PyErr_SetString(PyExc_TypeError, "window must be a PyGdkWindow or None");
+         return NULL;
+     }
+ 
+     // Fill in attribs
+     tmp = PyDict_GetItemString(attr_map, "window_type");
+     if (tmp == NULL) {
+         PyErr_SetString(PyExc_ValueError, "window_type value must be specified");
+         return NULL;
+     }
+     else {
+         if (!PyInt_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "window_type value must be an int");
+             return NULL;
+         }
+         attr.window_type = PyInt_AsLong(tmp);
+     }
+     tmp = PyDict_GetItemString(attr_map, "event_mask");
+     if (tmp == NULL) {
+         PyErr_SetString(PyExc_ValueError, "event_mask value must be specified");
+         return NULL;
+     }
+     else {
+         if (!PyInt_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "event_mask value must be an int");
+             return NULL;
+         }
+         attr.event_mask = PyInt_AsLong(tmp);
+     }
+     tmp = PyDict_GetItemString(attr_map, "width");
+     if (tmp == NULL) {
+         PyErr_SetString(PyExc_ValueError, "width value must be specified");
+         return NULL;
+     }
+     else {
+         if (!PyInt_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "width value must be an int");
+             return NULL;
+         }
+         attr.width = PyInt_AsLong(tmp);
+     }
+     tmp = PyDict_GetItemString(attr_map, "height");
+     if (tmp == NULL) {
+         PyErr_SetString(PyExc_ValueError, "height value must be specified");
+         return NULL;
+     }
+     else {
+         if (!PyInt_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "height value must be an int");
+             return NULL;
+         }
+         attr.height = PyInt_AsLong(tmp);
+     }
+     tmp = PyDict_GetItemString(attr_map, "wclass");
+     if (tmp != NULL) {
+         if (!PyInt_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "wmclass value must be an int");
+             return NULL;
+         }
+         attr.wclass = PyInt_AsLong(tmp);
+         attr_mask |= GDK_WA_WMCLASS;
+     }
+ /*
+     tmp = PyDict_GetItemString(attr_map, "visual");
+     if (tmp != NULL) {
+         if (!PyGtkVisual_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "visual value must be a PyGtkVisual");
+             return NULL;
+         }
+         attr.visual = ((PyGtkVisual*)tmp)->obj;
+         attr_mask |= GDK_WA_VISUAL;
+     }
+ */
+     tmp = PyDict_GetItemString(attr_map, "colormap");
+     if (tmp != NULL) {
+         if (!PyGdkColormap_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "colormap value must be a 
+PyGdkColormap");
+             return NULL;
+         }
+         attr.colormap = ((PyGdkColormap_Object*)tmp)->obj;
+         attr_mask |= GDK_WA_COLORMAP;
+     }
+     tmp = PyDict_GetItemString(attr_map, "override_redirect");
+     if (tmp != NULL) {
+         if (!PyInt_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "override_redirect value must be an 
+int");
+             return NULL;
+         }
+         attr.override_redirect = PyInt_AsLong(tmp);
+         attr_mask |= GDK_WA_NOREDIR;
+     }
+     tmp = PyDict_GetItemString(attr_map, "x");
+     if (tmp != NULL) {
+         if (!PyInt_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "x value must be an int");
+             return NULL;
+         }
+         attr.x = PyInt_AsLong(tmp);
+         attr_mask |= GDK_WA_X;
+     }
+     tmp = PyDict_GetItemString(attr_map, "y");
+     if (tmp != NULL) {
+         if (!PyInt_Check(tmp)) {
+             PyErr_SetString(PyExc_TypeError, "y value must be an int");
+             return NULL;
+         }
+         attr.y = PyInt_AsLong(tmp);
+         attr_mask |= GDK_WA_Y;
+     }
+ 
+     gdk_win = gdk_window_new(gdk_parent, &attr, attr_mask);
+     pygdk_win = PyGdkWindow_New(gdk_win);
+     if (pygdk_win == NULL) {
+         gdk_window_destroy(gdk_win);
+         return NULL;
+     }
+     return pygdk_win;
+ }
+ #endif
+ 
  static PyMethodDef _gtkmoduleMethods[] = {
      { "gtk_signal_connect", _wrap_gtk_signal_connect, 1 },
      { "gtk_signal_connect_after", _wrap_gtk_signal_connect_after, 1 },
***************
*** 6566,6571 ****
--- 6743,6751 ----
      { "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_new", _wrap_gdk_window_new, 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 },

Reply via email to