GnuCash  5.6-150-g038405b370+
cursors.c
1 /********************************************************************\
2  * cursor.c -- functions for changing cursors *
3  * *
4  * Copyright (C) 1997 Robin D. Clark <rclark@cs.hmc.edu> *
5  * Copyright (C) 1998-2000 Linas Vepstas <linas@linas.org> *
6  * *
7  * This program is free software; you can redistribute it and/or *
8  * modify it under the terms of the GNU General Public License as *
9  * published by the Free Software Foundation; either version 2 of *
10  * the License, or (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License*
18  * along with this program; if not, contact: *
19  * *
20  * Free Software Foundation Voice: +1-617-542-5942 *
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22  * Boston, MA 02110-1301, USA gnu@gnu.org *
23 \********************************************************************/
24 #include <config.h>
25 #include <gtk/gtk.h>
26 #include "gnc-ui.h"
27 
28 
29 typedef enum
30 {
31  GNC_CURSOR_NORMAL = -1,
32  GNC_CURSOR_BUSY = GDK_WATCH
33 } GNCCursorType;
34 
35 
36 /********************************************************************\
37  * gnc_ui_set_cursor *
38  * sets the cursor to the specified type *
39  * *
40  * Args: w - the widget over which to change the cursor *
41  * type - the type of cursor to make *
42  * Return: none *
43 \********************************************************************/
44 static void
45 gnc_ui_set_cursor (GdkWindow *win, GNCCursorType type, gboolean update_now)
46 {
47  GdkCursor *cursor = NULL;
48 
49  if (win == NULL)
50  return;
51 
52  if (type != GNC_CURSOR_NORMAL)
53  cursor = gdk_cursor_new_for_display (gdk_window_get_display (win),
54  (GdkCursorType)type);
55 
56  gdk_window_set_cursor (win, cursor);
57 
58  if (update_now && type != GNC_CURSOR_NORMAL)
59  {
60  while (gtk_events_pending ())
61  gtk_main_iteration ();
62  }
63 
64  if (type != GNC_CURSOR_NORMAL)
65  g_object_unref (cursor);
66 }
67 
68 
69 /********************************************************************\
70  * gnc_set_busy_cursor *
71  * sets the cursor to the busy watch for the given window. *
72  * if the window is null, sets the cursor for all toplevel windows*
73  * *
74  * Args: w - the widget over which to make cursor busy *
75  * update_now - if true the cursor will be changed when the *
76  * call returns. *
77  * Return: none *
78 \********************************************************************/
79 void
80 gnc_set_busy_cursor (GtkWidget *w, gboolean update_now)
81 {
82  if (w != NULL)
83  gnc_ui_set_cursor (gtk_widget_get_window(w), GNC_CURSOR_BUSY, update_now);
84  else
85  {
86  /* gnc_ui_set_cursor runs the event loop and if there's an
87  * idle waiting that destroys a toplevel further down the list
88  * then we'll get a use after free crash unless we have our
89  * own reference, so take a reference to all of the toplevels
90  * and release them all after the loop finishes.
91  */
92  GList *containerstop = gtk_window_list_toplevels (), *node;
93  g_list_foreach (containerstop, (GFunc)g_object_ref, NULL);
94 
95  for (node = containerstop; node; node = node->next)
96  {
97  w = node->data;
98 
99  if (!w || !GTK_IS_WIDGET (w) || (!gtk_widget_get_has_window(w)))
100  continue;
101 
102  gnc_ui_set_cursor (gtk_widget_get_window(w), GNC_CURSOR_BUSY, update_now);
103  }
104  g_list_free_full (containerstop, (GDestroyNotify)g_object_unref);
105  }
106 }
107 
108 
109 /********************************************************************\
110  * gnc_unset_busy_cursor *
111  * sets the cursor to the default cursor for the given window. *
112  * if the window is null, sets the cursor for all toplevel windows*
113  * *
114  * Args: w - the widget over which to make cursor normal *
115  * Return: none *
116 \********************************************************************/
117 void
118 gnc_unset_busy_cursor (GtkWidget *w)
119 {
120  if (w != NULL)
121  gnc_ui_set_cursor (gtk_widget_get_window(w), GNC_CURSOR_NORMAL, FALSE);
122  else
123  {
124  GList *containerstop, *node;
125 
126  for (containerstop = node = gtk_window_list_toplevels (); node; node = node->next)
127  {
128  w = GTK_WIDGET (node->data);
129 
130  if (!w || !GTK_IS_WIDGET (w) || (!gtk_widget_get_has_window(w)))
131  continue;
132 
133  gnc_ui_set_cursor (gtk_widget_get_window(w), GNC_CURSOR_NORMAL, FALSE);
134  }
135  g_list_free (containerstop);
136  }
137 }
138