gnome-shell-3.6.3.1/src/st/st-focus-manager.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found st/st-focus-manager.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2 /*
  3  * st-focus-manager.c: Keyboard focus manager
  4  *
  5  * Copyright 2010 Red Hat, Inc.
  6  *
  7  * This program is free software; you can redistribute it and/or modify
  8  * it under the terms of the GNU Lesser General Public License as
  9  * published by the Free Software Foundation, either version 2.1 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * This program is distributed in the hope it will be useful, but WITHOUT ANY
 13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 14  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 15  * more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public License
 18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
 19  */
 20 
 21 /**
 22  * SECTION:st-focus-manager
 23  * @short_description: Keyboard focus management
 24  *
 25  * #StFocusManager handles keyboard focus for all actors on the stage.
 26  */
 27 
 28 #ifdef HAVE_CONFIG_H
 29 #include "config.h"
 30 #endif
 31 
 32 #include <clutter/clutter.h>
 33 
 34 #include "st-focus-manager.h"
 35 
 36 #define ST_FOCUS_MANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_FOCUS_MANAGER, StFocusManagerPrivate))
 37 
 38 struct _StFocusManagerPrivate
 39 {
 40   GHashTable *groups;
 41 };
 42 
 43 G_DEFINE_TYPE (StFocusManager, st_focus_manager, G_TYPE_OBJECT)
 44 
 45 static void
 46 st_focus_manager_dispose (GObject *object)
 47 {
 48   StFocusManager *manager = ST_FOCUS_MANAGER (object);
 49 
 50   if (manager->priv->groups)
 51     {
 52       g_hash_table_destroy (manager->priv->groups);
 53       manager->priv->groups = NULL;
 54     }
 55 
 56   G_OBJECT_CLASS (st_focus_manager_parent_class)->dispose (object);
 57 }
 58 
 59 static void
 60 st_focus_manager_class_init (StFocusManagerClass *klass)
 61 {
 62   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 63 
 64   g_type_class_add_private (klass, sizeof (StFocusManagerPrivate));
 65 
 66   object_class->dispose = st_focus_manager_dispose;
 67 }
 68 
 69 static void
 70 st_focus_manager_init (StFocusManager *manager)
 71 {
 72   manager->priv = ST_FOCUS_MANAGER_GET_PRIVATE (manager);
 73   manager->priv->groups = g_hash_table_new (NULL, NULL);
 74 }
 75 
 76 static gboolean
 77 st_focus_manager_stage_event (ClutterActor *stage,
 78 			      ClutterEvent *event,
 79 			      gpointer      user_data)
 80 {
 81   StFocusManager *manager = user_data;
 82   GtkDirectionType direction;
 83   gboolean wrap_around = FALSE;
 84   ClutterActor *focused, *group;
 85 
 86   if (event->type != CLUTTER_KEY_PRESS)
 87     return FALSE;
 88 
 89   switch (event->key.keyval)
 90     {
 91     case CLUTTER_KEY_Up:
 92       direction = GTK_DIR_UP;
 93       break;
 94     case CLUTTER_KEY_Down:
 95       direction = GTK_DIR_DOWN;
 96       break;
 97     case CLUTTER_KEY_Left:
 98       direction = GTK_DIR_LEFT;
 99       break;
100     case CLUTTER_KEY_Right:
101       direction = GTK_DIR_RIGHT;
102       break;
103     case CLUTTER_KEY_Tab:
104       if (event->key.modifier_state & CLUTTER_SHIFT_MASK)
105         direction = GTK_DIR_TAB_BACKWARD;
106       else
107         direction = GTK_DIR_TAB_FORWARD;
108       wrap_around = TRUE;
109       break;
110     case CLUTTER_KEY_ISO_Left_Tab:
111       direction = GTK_DIR_TAB_BACKWARD;
112       wrap_around = TRUE;
113       break;
114 
115     default:
116       return FALSE;
117     }
118 
119   focused = clutter_stage_get_key_focus (CLUTTER_STAGE (stage));
120   if (!focused)
121     return FALSE;
122 
123   for (group = focused; group != stage; group = clutter_actor_get_parent (group))
124     {
125       if (g_hash_table_lookup (manager->priv->groups, group))
126         {
127           return st_widget_navigate_focus (ST_WIDGET (group), focused,
128                                            direction, wrap_around);
129         }
130     }
131   return FALSE;
132 }
133 
134 /**
135  * st_focus_manager_get_for_stage:
136  * @stage: a #ClutterStage
137  *
138  * Gets the #StFocusManager for @stage, creating it if necessary.
139  *
140  * Return value: (transfer none): the focus manager for @stage
141  */
142 StFocusManager *
143 st_focus_manager_get_for_stage (ClutterStage *stage)
144 {
145   StFocusManager *manager;
146 
147   manager = g_object_get_data (G_OBJECT (stage), "st-focus-manager");
148   if (!manager)
149     {
150       manager = g_object_new (ST_TYPE_FOCUS_MANAGER, NULL);
151       g_object_set_data_full (G_OBJECT (stage), "st-focus-manager",
152 			      manager, g_object_unref);
153 
154       g_signal_connect (stage, "event",
155 			G_CALLBACK (st_focus_manager_stage_event), manager);
156     }
157 
158   return manager;
159 }
160 
161 static void
162 remove_destroyed_group (ClutterActor *actor,
163                         gpointer      user_data)
164 {
165   StFocusManager *manager = user_data;
166 
167   st_focus_manager_remove_group (manager, ST_WIDGET (actor));
168 }
169 
170 /**
171  * st_focus_manager_add_group:
172  * @manager: the #StFocusManager
173  * @root: the root container of the group
174  *
175  * Adds a new focus group to @manager. When the focus is in an actor
176  * that is a descendant of @root, @manager will handle moving focus
177  * from one actor to another within @root based on keyboard events.
178  */
179 void
180 st_focus_manager_add_group (StFocusManager *manager,
181                             StWidget       *root)
182 {
183   gpointer count_p = g_hash_table_lookup (manager->priv->groups, root);
184   int count = count_p ? GPOINTER_TO_INT (count_p) : 0;
185 
186   g_signal_connect (root, "destroy",
187                     G_CALLBACK (remove_destroyed_group),
188                     manager);
189   g_hash_table_insert (manager->priv->groups, root, GINT_TO_POINTER (++count));
190 }
191 
192 /**
193  * st_focus_manager_remove_group:
194  * @manager: the #StFocusManager
195  * @root: the root container of the group
196  *
197  * Removes the group rooted at @root from @manager
198  */
199 void
200 st_focus_manager_remove_group (StFocusManager *manager,
201                                StWidget       *root)
202 {
203   gpointer count_p = g_hash_table_lookup (manager->priv->groups, root);
204   int count = count_p ? GPOINTER_TO_INT (count_p) : 0;
205 
206   if (count == 0)
207     return;
208   if (count == 1)
209     g_hash_table_remove (manager->priv->groups, root);
210   else
211     g_hash_table_insert (manager->priv->groups, root, GINT_TO_POINTER(--count));
212 }
213 
214 /**
215  * st_focus_manager_get_group:
216  * @manager: the #StFocusManager
217  * @widget: an #StWidget
218  *
219  * Checks if @widget is inside a focus group, and if so, returns
220  * the root of that group.
221  *
222  * Return value: (transfer none): the focus group root, or %NULL if
223  * @widget is not in a focus group
224  */
225 StWidget *
226 st_focus_manager_get_group (StFocusManager *manager,
227                             StWidget       *widget)
228 {
229   ClutterActor *actor = CLUTTER_ACTOR (widget);
230 
231   while (actor && !g_hash_table_lookup (manager->priv->groups, actor))
232     actor = clutter_actor_get_parent (actor);
233 
234   return ST_WIDGET (actor);
235 }