Patch for modal windows, and more.



This is a rather crude hack to try get the ball rolling with modal
dialogs. It will drive you crazy if you have your WM in FocusFollowsMouse
mode, but the point of it is to make sure the modal window always has
focus.

Please take this and add features on to it so eventually this
wonderful-and-perfect modal dialog box patch will evolve. I think the next
logical step would be to find a way to make it so that the WM never
removes focus from the window if the focusout is going to another window
for the client. Perhaps also filter out all mouse events so they don't go
to other windows of the client while a modal is popped up.

Also, if anyone wants to play with drag and drop, try out
ftp://ftp.redhat.com/sopwith/gtk-xde5.patch.gz please - it is more or less
how I think D&D should be done, it's not hard to add D&D to existing gtk
apps (and I hope to add some D&D to the main gtk widgets sometime).

Hope this helps,
-- "hacking gtk to bits" Elliot 
--- gimp-0.99.10/gtk+/gdk/gdkwindow.c.sopwith	Fri Jul  4 12:17:35 1997
+++ gimp-0.99.10/gtk+/gdk/gdkwindow.c	Fri Jul  4 15:49:42 1997
@@ -207,6 +207,8 @@
 
   switch (private->window_type)
     {
+    case GDK_WINDOW_DIALOG_MODAL:
+      gdk_window_modal_push(window);
     case GDK_WINDOW_DIALOG:
       XSetTransientForHint (private->xdisplay, private->xwindow, xparent);
     case GDK_WINDOW_TOPLEVEL:
@@ -272,6 +274,8 @@
 
   switch (private->window_type)
     {
+    case GDK_WINDOW_DIALOG_MODAL:
+      gdk_window_modal_pop(window);
     case GDK_WINDOW_TOPLEVEL:
     case GDK_WINDOW_CHILD:
     case GDK_WINDOW_DIALOG:
@@ -959,4 +963,26 @@
   g_free (new_windows);
   if (old_windows)
     XFree (old_windows);
+}
+
+void
+gdk_window_modal_push(GdkWindow *window)
+{
+    g_return_if_fail(window != NULL);
+    g_return_if_fail(((GdkWindowPrivate *)window)->window_type
+		     == GDK_WINDOW_DIALOG_MODAL);
+    g_return_if_fail(gdk_modals_stack->data != (gpointer)window);
+    gdk_modals_stack = g_slist_prepend(gdk_modals_stack, (gpointer) window);
+}
+
+void
+gdk_window_modal_pop(GdkWindow *window)
+{
+    GSList *tmp = gdk_modals_stack;
+
+    g_return_if_fail((gpointer)window == tmp->data);
+
+    gdk_modals_stack = g_slist_remove_link(gdk_modals_stack,
+					   gdk_modals_stack);    
+    g_slist_free(tmp);
 }
--- gimp-0.99.10/gtk+/gdk/gdk.c.sopwith	Fri Jul  4 12:22:19 1997
+++ gimp-0.99.10/gtk+/gdk/gdk.c	Fri Jul  4 15:47:52 1997
@@ -307,6 +307,8 @@
   gdk_wm_window_protocols[1] = gdk_wm_take_focus;
   gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False);
 
+  gdk_modals_stack = g_slist_alloc();
+
   XGetKeyboardControl (gdk_display, &keyboard_state);
   autorepeat = keyboard_state.global_auto_repeat;
 
@@ -1746,13 +1748,35 @@
 	    }
 	  else if (xevent->xclient.data.l[0] == gdk_wm_take_focus)
 	    {
+		/* We use this for modal dialogs */
+
 	      /* Print debugging info.
 	       */
 	      if (gdk_show_events)
 		g_print ("take focus:\t\twindow: %ld\n",
 			 xevent->xclient.window - base_id);
 
-	      /* Not currently handled */
+		if(gdk_modals_stack->data != NULL 
+		   && gdk_modals_stack->data != (gpointer)window) {
+		    /* We want to refocus on our modal window */
+		    XRaiseWindow(gdk_display, 
+				   ((GdkWindowPrivate *)
+				    gdk_modals_stack->data)->xwindow);
+		    XBell(gdk_display, 0); /* XXX do we need this? */
+		    XSetInputFocus(gdk_display,
+				   ((GdkWindowPrivate *)
+				    gdk_modals_stack->data)->xwindow,
+				   RevertToPointerRoot, xevent->xclient.data.l[1]);
+		    g_print("Set focus on %ld\n",
+			     ((GdkWindowPrivate *)
+			      gdk_modals_stack->data)->xwindow);
+#ifndef NDEBUG
+		} else {
+		    if(gdk_show_events)
+			g_print("Window %ld can keep focus\n",
+				xevent->xfocus.window - base_id);
+		}
+#endif
 	    }
 	}
       break;
--- gimp-0.99.10/gtk+/gdk/gdkglobals.c.sopwith	Fri Jul  4 12:22:21 1997
+++ gimp-0.99.10/gtk+/gdk/gdkglobals.c	Fri Jul  4 14:30:51 1997
@@ -21,7 +21,7 @@
 #include "gdkprivate.h"
 
 gint              gdk_debug_level = 0;
-gint              gdk_show_events = FALSE;
+gint              gdk_show_events = TRUE;
 gint              gdk_use_xshm = TRUE;
 gchar            *gdk_display_name = NULL;
 Display          *gdk_display = NULL;
@@ -37,3 +37,4 @@
 gchar            *gdk_progname = NULL;
 gint              gdk_error_code;
 gint              gdk_error_warnings = TRUE;
+GSList           *gdk_modals_stack = NULL;
--- gimp-0.99.10/gtk+/gdk/gdkprivate.h.sopwith	Fri Jul  4 12:22:25 1997
+++ gimp-0.99.10/gtk+/gdk/gdkprivate.h	Fri Jul  4 12:43:08 1997
@@ -152,6 +152,7 @@
 extern gchar            *gdk_progname;
 extern gint              gdk_error_code;
 extern gint              gdk_error_warnings;
+extern GSList           *gdk_modals_stack;
 
 
 #ifdef __cplusplus
--- gimp-0.99.10/gtk+/gdk/gdk.h.sopwith	Fri Jul  4 12:32:18 1997
+++ gimp-0.99.10/gtk+/gdk/gdk.h	Fri Jul  4 15:16:55 1997
@@ -182,6 +182,8 @@
 GdkWindow*    gdk_window_get_parent      (GdkWindow       *window);
 GdkWindow*    gdk_window_get_toplevel    (GdkWindow       *window);
 GList*        gdk_window_get_children    (GdkWindow       *window);
+void          gdk_window_modal_push      (GdkWindow *window);
+void          gdk_window_modal_pop       (GdkWindow *window);
 
 
 /* Cursors
--- gimp-0.99.10/gtk+/gtk/gtkwindow.c.sopwith	Fri Jul  4 14:03:26 1997
+++ gimp-0.99.10/gtk+/gtk/gtkwindow.c	Fri Jul  4 14:04:10 1997
@@ -456,6 +456,9 @@
     case GTK_WINDOW_DIALOG:
       attributes.window_type = GDK_WINDOW_DIALOG;
       break;
+    case GTK_WINDOW_DIALOG_MODAL:
+      attributes.window_type = GDK_WINDOW_DIALOG_MODAL;
+      break;
     case GTK_WINDOW_POPUP:
       attributes.window_type = GDK_WINDOW_TEMP;
       break;
--- gimp-0.99.10/gtk+/gtk/gtkenums.h.sopwith	Fri Jul  4 13:45:21 1997
+++ gimp-0.99.10/gtk+/gtk/gtkenums.h	Fri Jul  4 14:11:06 1997
@@ -54,7 +54,8 @@
 {
   GTK_WINDOW_TOPLEVEL,
   GTK_WINDOW_DIALOG,
-  GTK_WINDOW_POPUP
+  GTK_WINDOW_POPUP,
+  GTK_WINDOW_DIALOG_MODAL
 } GtkWindowType;
 
 /* Focus movement types */
--- gimp-0.99.10/gtk+/gtk/testgtk.c.sopwith	Fri Jul  4 14:25:28 1997
+++ gimp-0.99.10/gtk+/gtk/testgtk.c	Fri Jul  4 14:25:41 1997
@@ -49,7 +49,7 @@
 
   if (!window)
     {
-      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+      window = gtk_window_new (GTK_WINDOW_DIALOG_MODAL);
       gtk_signal_connect (GTK_OBJECT (window), "destroy",
 			  (GtkSignalFunc) destroy_window,
 			  &window);


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