GCC Code Coverage Report


Directory: ./
File: panels/search/cc-search-panel-row.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 107 0.0%
Functions: 0 16 0.0%
Branches: 0 25 0.0%

Line Branch Exec Source
1 /*
2 * Copyright © 2019 Red Hat, Inc.
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 * Author: Felipe Borges <felipeborges@gnome.org>
18 */
19
20 #include "cc-search-panel-row.h"
21
22 struct _CcSearchPanelRow
23 {
24 AdwActionRow parent_instance;
25
26 GAppInfo *app_info;
27
28 GtkImage *icon;
29 GtkSwitch *switcher;
30
31 GtkListBox *drag_widget;
32 gdouble drag_x;
33 gdouble drag_y;
34 };
35
36 G_DEFINE_TYPE (CcSearchPanelRow, cc_search_panel_row, ADW_TYPE_ACTION_ROW)
37
38 enum
39 {
40 SIGNAL_MOVE_ROW,
41 SIGNAL_LAST
42 };
43
44 static guint signals[SIGNAL_LAST] = { 0, };
45
46 static void
47 update_move_actions_after_row_moved_up (CcSearchPanelRow *self)
48 {
49 GtkListBox *list_box = GTK_LIST_BOX (gtk_widget_get_parent (GTK_WIDGET (self)));
50 gint previous_idx = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (self)) - 1;
51 GtkListBoxRow *previous_row = gtk_list_box_get_row_at_index (list_box, previous_idx);
52
53 if (gtk_list_box_get_row_at_index (list_box, previous_idx - 1) == NULL)
54 {
55 gtk_widget_action_set_enabled (GTK_WIDGET (self), "row.move-up", FALSE);
56 }
57
58 gtk_widget_action_set_enabled (GTK_WIDGET (previous_row), "row.move-up", TRUE);
59 gtk_widget_action_set_enabled (GTK_WIDGET (previous_row), "row.move-down", gtk_widget_get_next_sibling (GTK_WIDGET (self)) != NULL);
60 gtk_widget_action_set_enabled (GTK_WIDGET (self), "row.move-down", TRUE);
61 }
62
63 static void
64 update_move_actions_after_row_moved_down (CcSearchPanelRow *self)
65 {
66 GtkListBox *list_box = GTK_LIST_BOX (gtk_widget_get_parent (GTK_WIDGET (self)));
67 gint next_idx = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (self)) + 1;
68 GtkListBoxRow *next_row = gtk_list_box_get_row_at_index (list_box, next_idx);
69
70 if (gtk_widget_get_next_sibling (GTK_WIDGET (next_row)) == NULL)
71 {
72 gtk_widget_action_set_enabled (GTK_WIDGET (self), "row.move-down", FALSE);
73 }
74
75 gtk_widget_action_set_enabled (GTK_WIDGET (next_row), "row.move-up", next_idx-1 != 0);
76 gtk_widget_action_set_enabled (GTK_WIDGET (next_row), "row.move-down", TRUE);
77 gtk_widget_action_set_enabled (GTK_WIDGET (self), "row.move-up", TRUE);
78 }
79
80 static void
81 move_up_cb (GSimpleAction *action,
82 GVariant *parameter,
83 gpointer user_data)
84 {
85 CcSearchPanelRow *self = CC_SEARCH_PANEL_ROW (user_data);
86 GtkListBox *list_box = GTK_LIST_BOX (gtk_widget_get_parent (GTK_WIDGET (self)));
87 gint previous_idx = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (self)) - 1;
88 GtkListBoxRow *previous_row = gtk_list_box_get_row_at_index (list_box, previous_idx);
89
90 if (previous_row == NULL)
91 return;
92
93 update_move_actions_after_row_moved_up (self);
94
95 g_signal_emit (self,
96 signals[SIGNAL_MOVE_ROW],
97 0,
98 previous_row);
99 }
100
101 static void
102 move_down_cb (GSimpleAction *action,
103 GVariant *parameter,
104 gpointer user_data)
105 {
106 CcSearchPanelRow *self = CC_SEARCH_PANEL_ROW (user_data);
107 GtkListBox *list_box = GTK_LIST_BOX (gtk_widget_get_parent (GTK_WIDGET (self)));
108 gint next_idx = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (self)) + 1;
109 GtkListBoxRow *next_row = gtk_list_box_get_row_at_index (list_box, next_idx);
110
111 if (next_row == NULL)
112 return;
113
114 update_move_actions_after_row_moved_down (self);
115
116 g_signal_emit (next_row,
117 signals[SIGNAL_MOVE_ROW],
118 0,
119 self);
120 }
121
122 static GdkContentProvider *
123 drag_prepare_cb (CcSearchPanelRow *self,
124 double x,
125 double y)
126 {
127 self->drag_x = x;
128 self->drag_y = y;
129
130 return gdk_content_provider_new_typed (CC_TYPE_SEARCH_PANEL_ROW, self);
131 }
132
133 static void
134 drag_begin_cb (CcSearchPanelRow *self,
135 GdkDrag *drag)
136 {
137 CcSearchPanelRow *panel_row;
138 GtkAllocation alloc;
139 GtkWidget *drag_icon;
140
141 gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
142
143 self->drag_widget = GTK_LIST_BOX (gtk_list_box_new ());
144 gtk_widget_set_size_request (GTK_WIDGET (self->drag_widget), alloc.width, alloc.height);
145
146 panel_row = cc_search_panel_row_new (self->app_info);
147 gtk_switch_set_active (panel_row->switcher, gtk_switch_get_active (self->switcher));
148
149 gtk_list_box_append (GTK_LIST_BOX (self->drag_widget), GTK_WIDGET (panel_row));
150 gtk_list_box_drag_highlight_row (self->drag_widget, GTK_LIST_BOX_ROW (panel_row));
151
152 drag_icon = gtk_drag_icon_get_for_drag (drag);
153 gtk_drag_icon_set_child (GTK_DRAG_ICON (drag_icon), GTK_WIDGET (self->drag_widget));
154 gdk_drag_set_hotspot (drag, self->drag_x, self->drag_y);
155
156 }
157
158 static gboolean
159 drop_cb (CcSearchPanelRow *self,
160 const GValue *value,
161 gdouble x,
162 gdouble y)
163 {
164 CcSearchPanelRow *source;
165
166 g_message ("Drop");
167
168 if (!G_VALUE_HOLDS (value, CC_TYPE_SEARCH_PANEL_ROW))
169 return FALSE;
170
171 source = g_value_get_object (value);
172
173 g_signal_emit (source,
174 signals[SIGNAL_MOVE_ROW],
175 0,
176 self);
177
178 return TRUE;
179 }
180
181 static void
182 cc_search_panel_row_finalize (GObject *object)
183 {
184 CcSearchPanelRow *self = CC_SEARCH_PANEL_ROW (object);
185
186 g_clear_object (&self->app_info);
187
188 G_OBJECT_CLASS (cc_search_panel_row_parent_class)->finalize (object);
189 }
190
191 static void
192 cc_search_panel_row_class_init (CcSearchPanelRowClass *klass)
193 {
194 GObjectClass *object_class = G_OBJECT_CLASS (klass);
195 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
196
197 object_class->finalize = cc_search_panel_row_finalize;
198
199 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/search/cc-search-panel-row.ui");
200
201 gtk_widget_class_bind_template_child (widget_class, CcSearchPanelRow, icon);
202 gtk_widget_class_bind_template_child (widget_class, CcSearchPanelRow, switcher);
203
204 signals[SIGNAL_MOVE_ROW] =
205 g_signal_new ("move-row",
206 G_TYPE_FROM_CLASS (object_class),
207 G_SIGNAL_RUN_LAST,
208 0,
209 NULL, NULL,
210 NULL,
211 G_TYPE_NONE,
212 1, CC_TYPE_SEARCH_PANEL_ROW);
213 }
214
215 const GActionEntry row_entries[] = {
216 { "move-up", move_up_cb, NULL, NULL, NULL, { 0 } },
217 { "move-down", move_down_cb, NULL, NULL, NULL, { 0 } }
218 };
219
220 static void
221 cc_search_panel_row_init (CcSearchPanelRow *self)
222 {
223 GtkDragSource *drag_source;
224 GtkDropTarget *drop_target;
225 GSimpleActionGroup *group;
226
227 gtk_widget_init_template (GTK_WIDGET (self));
228
229 drag_source = gtk_drag_source_new ();
230 gtk_drag_source_set_actions (drag_source, GDK_ACTION_MOVE);
231 g_signal_connect_swapped (drag_source, "prepare", G_CALLBACK (drag_prepare_cb), self);
232 g_signal_connect_swapped (drag_source, "drag-begin", G_CALLBACK (drag_begin_cb), self);
233 gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (drag_source));
234
235 drop_target = gtk_drop_target_new (CC_TYPE_SEARCH_PANEL_ROW, GDK_ACTION_MOVE);
236 gtk_drop_target_set_preload (drop_target, TRUE);
237 g_signal_connect_swapped (drop_target, "drop", G_CALLBACK (drop_cb), self);
238 gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (drop_target));
239
240 group = g_simple_action_group_new ();
241 g_action_map_add_action_entries (G_ACTION_MAP (group),
242 row_entries,
243 G_N_ELEMENTS (row_entries),
244 self);
245 gtk_widget_insert_action_group (GTK_WIDGET (self), "row", G_ACTION_GROUP (group));
246 }
247
248 CcSearchPanelRow *
249 cc_search_panel_row_new (GAppInfo *app_info)
250 {
251 CcSearchPanelRow *self;
252 g_autoptr(GIcon) gicon = NULL;
253
254 self = g_object_new (CC_TYPE_SEARCH_PANEL_ROW, NULL);
255 self->app_info = g_object_ref (app_info);
256
257 gicon = g_app_info_get_icon (app_info);
258 if (gicon == NULL)
259 gicon = g_themed_icon_new ("application-x-executable");
260 else
261 g_object_ref (gicon);
262 gtk_image_set_from_gicon (self->icon, gicon);
263
264 adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self),
265 g_app_info_get_name (app_info));
266
267 return self;
268 }
269
270 GAppInfo *
271 cc_search_panel_row_get_app_info (CcSearchPanelRow *self)
272 {
273 return self->app_info;
274 }
275
276 GtkWidget *
277 cc_search_panel_row_get_switch (CcSearchPanelRow *self)
278 {
279 return GTK_WIDGET (self->switcher);
280 }
281