GCC Code Coverage Report


Directory: ./
File: panels/keyboard/cc-input-row.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 110 0.0%
Functions: 0 19 0.0%
Branches: 0 29 0.0%

Line Branch Exec Source
1 /*
2 * Copyright © 2018 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <config.h>
19 #include "cc-input-row.h"
20 #include "cc-input-source-ibus.h"
21
22 struct _CcInputRow
23 {
24 AdwActionRow parent_instance;
25
26 CcInputSource *source;
27
28 GtkListBox *drag_widget;
29
30 GtkDragSource *drag_source;
31 gdouble drag_x;
32 gdouble drag_y;
33 };
34
35 G_DEFINE_TYPE (CcInputRow, cc_input_row, ADW_TYPE_ACTION_ROW)
36
37 enum
38 {
39 SIGNAL_SHOW_SETTINGS,
40 SIGNAL_SHOW_LAYOUT,
41 SIGNAL_MOVE_ROW,
42 SIGNAL_REMOVE_ROW,
43 SIGNAL_LAST
44 };
45
46 static guint signals[SIGNAL_LAST] = { 0, };
47
48 static GdkContentProvider *
49 drag_prepare_cb (CcInputRow *self,
50 double x,
51 double y)
52 {
53 self->drag_x = x;
54 self->drag_y = y;
55
56 return gdk_content_provider_new_typed (CC_TYPE_INPUT_ROW, self);
57 }
58
59 static void
60 drag_begin_cb (CcInputRow *self,
61 GdkDrag *drag)
62 {
63 GtkAllocation alloc;
64 CcInputRow *drag_row;
65 GtkWidget *drag_icon;
66
67 gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
68
69 self->drag_widget = GTK_LIST_BOX (gtk_list_box_new ());
70 gtk_widget_set_size_request (GTK_WIDGET (self->drag_widget), alloc.width, alloc.height);
71
72 drag_row = cc_input_row_new (self->source);
73 gtk_list_box_append (self->drag_widget, GTK_WIDGET (drag_row));
74 gtk_list_box_drag_highlight_row (self->drag_widget, GTK_LIST_BOX_ROW (drag_row));
75
76 drag_icon = gtk_drag_icon_get_for_drag (drag);
77 gtk_drag_icon_set_child (GTK_DRAG_ICON (drag_icon), GTK_WIDGET (self->drag_widget));
78 gdk_drag_set_hotspot (drag, self->drag_x, self->drag_y);
79 }
80
81 static gboolean
82 drop_cb (CcInputRow *self,
83 const GValue *value,
84 gdouble x,
85 gdouble y)
86 {
87 CcInputRow *source;
88
89 if (!G_VALUE_HOLDS (value, CC_TYPE_INPUT_ROW))
90 return FALSE;
91
92 source = g_value_get_object (value);
93
94 g_signal_emit (source,
95 signals[SIGNAL_MOVE_ROW],
96 0,
97 self);
98
99 return TRUE;
100 }
101
102 static void
103 move_up_cb (GtkWidget *widget,
104 const char *action_name,
105 GVariant *parameter)
106 {
107 CcInputRow *self = CC_INPUT_ROW (widget);
108 GtkListBox *list_box = GTK_LIST_BOX (gtk_widget_get_parent (GTK_WIDGET (self)));
109 gint previous_idx = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (self)) - 1;
110 GtkListBoxRow *previous_row = gtk_list_box_get_row_at_index (list_box, previous_idx);
111
112 if (previous_row == NULL || !CC_IS_INPUT_ROW (previous_row))
113 {
114 gtk_widget_action_set_enabled (widget, "row.move-up", FALSE);
115 gtk_widget_action_set_enabled (GTK_WIDGET (gtk_list_box_get_row_at_index (list_box, 0)), "row.move-up", TRUE);
116 return;
117 }
118
119 g_signal_emit (self,
120 signals[SIGNAL_MOVE_ROW],
121 0,
122 previous_row);
123 }
124
125 static void
126 move_down_cb (GtkWidget *widget,
127 const char *action_name,
128 GVariant *parameter)
129 {
130 CcInputRow *self = CC_INPUT_ROW (widget);
131 GtkListBox *list_box = GTK_LIST_BOX (gtk_widget_get_parent (GTK_WIDGET (self)));
132 gint next_idx = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (self)) + 1;
133 GtkListBoxRow *next_row = gtk_list_box_get_row_at_index (list_box, next_idx);
134
135 if (next_row == NULL || !CC_IS_INPUT_ROW (next_row))
136 {
137 gtk_widget_action_set_enabled (widget, "row.move-down", FALSE);
138 gtk_widget_action_set_enabled (GTK_WIDGET (gtk_list_box_get_row_at_index (list_box, next_idx-1)), "row.move-down", TRUE);
139 return;
140 }
141
142 g_signal_emit (next_row,
143 signals[SIGNAL_MOVE_ROW],
144 0,
145 self);
146 }
147
148 static void
149 show_settings_cb (GtkWidget *widget,
150 const char *action_name,
151 GVariant *parameter)
152 {
153 CcInputRow *self = CC_INPUT_ROW (widget);
154 g_signal_emit (self,
155 signals[SIGNAL_SHOW_SETTINGS],
156 0);
157 }
158
159 static void
160 show_layout_cb (GtkWidget *widget,
161 const char *action_name,
162 GVariant *parameter)
163 {
164 CcInputRow *self = CC_INPUT_ROW (widget);
165 g_signal_emit (self,
166 signals[SIGNAL_SHOW_LAYOUT],
167 0);
168 }
169
170 static void
171 remove_cb (GtkWidget *widget,
172 const char *action_name,
173 GVariant *parameter)
174 {
175 CcInputRow *self = CC_INPUT_ROW (widget);
176 g_signal_emit (self,
177 signals[SIGNAL_REMOVE_ROW],
178 0);
179 }
180
181 static void
182 cc_input_row_dispose (GObject *object)
183 {
184 CcInputRow *self = CC_INPUT_ROW (object);
185
186 g_clear_object (&self->source);
187
188 G_OBJECT_CLASS (cc_input_row_parent_class)->dispose (object);
189 }
190
191 void
192 cc_input_row_class_init (CcInputRowClass *klass)
193 {
194 GObjectClass *object_class = G_OBJECT_CLASS (klass);
195 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
196
197 object_class->dispose = cc_input_row_dispose;
198
199 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/keyboard/cc-input-row.ui");
200
201 signals[SIGNAL_SHOW_SETTINGS] =
202 g_signal_new ("show-settings",
203 G_TYPE_FROM_CLASS (object_class),
204 G_SIGNAL_RUN_LAST,
205 0,
206 NULL, NULL,
207 NULL,
208 G_TYPE_NONE,
209 0);
210
211 signals[SIGNAL_SHOW_LAYOUT] =
212 g_signal_new ("show-layout",
213 G_TYPE_FROM_CLASS (object_class),
214 G_SIGNAL_RUN_LAST,
215 0,
216 NULL, NULL,
217 NULL,
218 G_TYPE_NONE,
219 0);
220
221 signals[SIGNAL_MOVE_ROW] =
222 g_signal_new ("move-row",
223 G_TYPE_FROM_CLASS (object_class),
224 G_SIGNAL_RUN_LAST,
225 0,
226 NULL, NULL,
227 NULL,
228 G_TYPE_NONE,
229 1, CC_TYPE_INPUT_ROW);
230
231 signals[SIGNAL_REMOVE_ROW] =
232 g_signal_new ("remove-row",
233 G_TYPE_FROM_CLASS (object_class),
234 G_SIGNAL_RUN_LAST,
235 0,
236 NULL, NULL,
237 NULL,
238 G_TYPE_NONE,
239 0);
240
241 gtk_widget_class_install_action (widget_class, "row.move-up", NULL, move_up_cb);
242 gtk_widget_class_install_action (widget_class, "row.move-down", NULL, move_down_cb);
243 gtk_widget_class_install_action (widget_class, "row.show-layout", NULL, show_layout_cb);
244 gtk_widget_class_install_action (widget_class, "row.show-settings", NULL, show_settings_cb);
245 gtk_widget_class_install_action (widget_class, "row.remove", NULL, remove_cb);
246 }
247
248 void
249 cc_input_row_init (CcInputRow *self)
250 {
251 GtkDropTarget *drop_target;
252
253 gtk_widget_init_template (GTK_WIDGET (self));
254
255 self->drag_source = gtk_drag_source_new ();
256 gtk_drag_source_set_actions (self->drag_source, GDK_ACTION_MOVE);
257 g_signal_connect_swapped (self->drag_source, "prepare", G_CALLBACK (drag_prepare_cb), self);
258 g_signal_connect_swapped (self->drag_source, "drag-begin", G_CALLBACK (drag_begin_cb), self);
259 gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->drag_source));
260
261 drop_target = gtk_drop_target_new (CC_TYPE_INPUT_ROW, GDK_ACTION_MOVE);
262 gtk_drop_target_set_preload (drop_target, TRUE);
263 g_signal_connect_swapped (drop_target, "drop", G_CALLBACK (drop_cb), self);
264 gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (drop_target));
265 }
266
267 static void
268 label_changed_cb (CcInputRow *self)
269 {
270 g_autofree gchar *label = cc_input_source_get_label (self->source);
271 adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self), label);
272 }
273
274 CcInputRow *
275 cc_input_row_new (CcInputSource *source)
276 {
277 CcInputRow *self;
278
279 self = g_object_new (CC_TYPE_INPUT_ROW, NULL);
280 self->source = g_object_ref (source);
281
282 g_signal_connect_object (source, "label-changed", G_CALLBACK (label_changed_cb), self, G_CONNECT_SWAPPED);
283 label_changed_cb (self);
284
285 gtk_widget_action_set_enabled (GTK_WIDGET (self), "row.show-settings", CC_IS_INPUT_SOURCE_IBUS (source));
286
287 return self;
288 }
289
290 CcInputSource *
291 cc_input_row_get_source (CcInputRow *self)
292 {
293 g_return_val_if_fail (CC_IS_INPUT_ROW (self), NULL);
294 return self->source;
295 }
296
297 void
298 cc_input_row_set_removable (CcInputRow *self,
299 gboolean removable)
300 {
301 g_return_if_fail (CC_IS_INPUT_ROW (self));
302 gtk_widget_action_set_enabled (GTK_WIDGET (self), "row.remove", removable);
303 }
304
305 void
306 cc_input_row_set_draggable (CcInputRow *self,
307 gboolean draggable)
308 {
309 gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->drag_source),
310 draggable ? GTK_PHASE_BUBBLE : GTK_PHASE_NONE);
311 }
312
313