1 /*
2  * vala-panel-appmenu
3  * Copyright (C) 2018 Konstantin Pugin <ria.freelander@gmail.com>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "section.h"
20 #include "item.h"
21 enum
22 {
23 	PROP_NULL          = 0,
24 	PROP_PARENT_MODEL  = 1,
25 	PROP_SECTION_INDEX = 2,
26 	NUM_PROPS
27 };
28 
29 static GParamSpec *properties[NUM_PROPS] = { NULL };
30 
G_DEFINE_TYPE(DBusMenuSectionModel,dbus_menu_section_model,G_TYPE_MENU_MODEL)31 G_DEFINE_TYPE(DBusMenuSectionModel, dbus_menu_section_model, G_TYPE_MENU_MODEL)
32 
33 static int dbus_menu_section_model_is_mutable(GMenuModel *model)
34 {
35 	return true;
36 }
37 
dbus_menu_section_model_get_n_items(GMenuModel * model)38 static gint dbus_menu_section_model_get_n_items(GMenuModel *model)
39 {
40 	DBusMenuSectionModel *menu = DBUS_MENU_SECTION_MODEL(model);
41 	GSequence *items           = dbus_menu_model_items(menu->parent_model);
42 	int begin = 0, end = -1;
43 	for (GSequenceIter *iter = g_sequence_get_begin_iter(items); !g_sequence_iter_is_end(iter);
44 	     iter                = g_sequence_iter_next(iter))
45 	{
46 		DBusMenuItem *item = (DBusMenuItem *)g_sequence_get(iter);
47 		if (item->section_num == menu->section_index && item->place == -1)
48 			begin = g_sequence_iter_get_position(iter);
49 		end = g_sequence_iter_get_position(iter);
50 		if (item->section_num == menu->section_index + 1 && item->place == -1)
51 		{
52 			end--;
53 			break;
54 		}
55 	}
56 	return end - begin;
57 }
58 
dbus_menu_section_model_get_item_attributes(GMenuModel * model,gint position,GHashTable ** table)59 static void dbus_menu_section_model_get_item_attributes(GMenuModel *model, gint position,
60                                                         GHashTable **table)
61 {
62 	DBusMenuSectionModel *menu = DBUS_MENU_SECTION_MODEL(model);
63 	GSequence *items           = dbus_menu_model_items(menu->parent_model);
64 	for (GSequenceIter *iter = g_sequence_get_begin_iter(items); !g_sequence_iter_is_end(iter);
65 	     iter                = g_sequence_iter_next(iter))
66 	{
67 		DBusMenuItem *item = (DBusMenuItem *)g_sequence_get(iter);
68 		if (item->section_num == menu->section_index && item->place == position)
69 		{
70 			*table = g_hash_table_ref(item->attrs);
71 			return;
72 		}
73 	}
74 }
75 
dbus_menu_section_model_get_item_links(GMenuModel * model,gint position,GHashTable ** table)76 static void dbus_menu_section_model_get_item_links(GMenuModel *model, gint position,
77                                                    GHashTable **table)
78 {
79 	DBusMenuSectionModel *menu = DBUS_MENU_SECTION_MODEL(model);
80 	GSequence *items           = dbus_menu_model_items(menu->parent_model);
81 	for (GSequenceIter *iter = g_sequence_get_begin_iter(items); !g_sequence_iter_is_end(iter);
82 	     iter                = g_sequence_iter_next(iter))
83 	{
84 		DBusMenuItem *item = (DBusMenuItem *)g_sequence_get(iter);
85 		if (item->section_num == menu->section_index && item->place == position)
86 		{
87 			if (g_hash_table_contains(item->links, G_MENU_LINK_SECTION))
88 				g_warning("Item has section, but should not\n");
89 			*table = g_hash_table_ref(item->links);
90 			return;
91 		}
92 	}
93 }
dbus_menu_section_model_init(DBusMenuSectionModel * menu)94 static void dbus_menu_section_model_init(DBusMenuSectionModel *menu)
95 {
96 	menu->parent_model = NULL;
97 }
98 
dbus_menu_section_model_finalize(GObject * object)99 static void dbus_menu_section_model_finalize(GObject *object)
100 {
101 	G_OBJECT_CLASS(dbus_menu_section_model_parent_class)->finalize(object);
102 }
103 
install_properties(GObjectClass * object_class)104 static void install_properties(GObjectClass *object_class)
105 {
106 	properties[PROP_PARENT_MODEL] =
107 	    g_param_spec_object("parent-model",
108 	                        "parent-model",
109 	                        "parent-model",
110 	                        dbus_menu_model_get_type(),
111 	                        (GParamFlags)(G_PARAM_CONSTRUCT_ONLY | G_PARAM_READABLE |
112 	                                      G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
113 
114 	properties[PROP_SECTION_INDEX] =
115 	    g_param_spec_uint("section-index",
116 	                      "section-index",
117 	                      "section-index",
118 	                      0,
119 	                      UINT_MAX,
120 	                      0,
121 	                      (GParamFlags)(G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE |
122 	                                    G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
123 
124 	g_object_class_install_properties(object_class, NUM_PROPS, properties);
125 }
126 
dbus_menu_section_model_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)127 static void dbus_menu_section_model_set_property(GObject *object, guint property_id,
128                                                  const GValue *value, GParamSpec *pspec)
129 {
130 	DBusMenuSectionModel *menu = DBUS_MENU_SECTION_MODEL(object);
131 
132 	switch (property_id)
133 	{
134 	case PROP_PARENT_MODEL:
135 		menu->parent_model = DBUS_MENU_MODEL(g_value_get_object(value));
136 		break;
137 	case PROP_SECTION_INDEX:
138 		menu->section_index = g_value_get_uint(value);
139 		break;
140 	default:
141 		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
142 		break;
143 	}
144 }
145 
dbus_menu_section_model_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)146 static void dbus_menu_section_model_get_property(GObject *object, guint property_id, GValue *value,
147                                                  GParamSpec *pspec)
148 {
149 	DBusMenuSectionModel *menu = DBUS_MENU_SECTION_MODEL(object);
150 
151 	switch (property_id)
152 	{
153 	case PROP_PARENT_MODEL:
154 		g_value_set_object(value, menu->parent_model);
155 		break;
156 	case PROP_SECTION_INDEX:
157 		g_value_set_uint(value, menu->section_index);
158 		break;
159 	default:
160 		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
161 		break;
162 	}
163 }
164 
dbus_menu_section_model_constructed(GObject * object)165 static void dbus_menu_section_model_constructed(GObject *object)
166 {
167 	G_OBJECT_CLASS(dbus_menu_section_model_parent_class)->constructed(object);
168 }
169 
dbus_menu_section_model_class_init(DBusMenuSectionModelClass * klass)170 static void dbus_menu_section_model_class_init(DBusMenuSectionModelClass *klass)
171 {
172 	GMenuModelClass *model_class = G_MENU_MODEL_CLASS(klass);
173 	GObjectClass *object_class   = G_OBJECT_CLASS(klass);
174 
175 	object_class->finalize     = dbus_menu_section_model_finalize;
176 	object_class->set_property = dbus_menu_section_model_set_property;
177 	object_class->get_property = dbus_menu_section_model_get_property;
178 	object_class->constructed  = dbus_menu_section_model_constructed;
179 
180 	model_class->is_mutable          = dbus_menu_section_model_is_mutable;
181 	model_class->get_n_items         = dbus_menu_section_model_get_n_items;
182 	model_class->get_item_attributes = dbus_menu_section_model_get_item_attributes;
183 	model_class->get_item_links      = dbus_menu_section_model_get_item_links;
184 	install_properties(object_class);
185 }
186 
dbus_menu_section_model_new(DBusMenuModel * parent,int section_index)187 DBusMenuSectionModel *dbus_menu_section_model_new(DBusMenuModel *parent, int section_index)
188 {
189 	return DBUS_MENU_SECTION_MODEL(g_object_new(dbus_menu_section_model_get_type(),
190 	                                            "parent-model",
191 	                                            parent,
192 	                                            "section-index",
193 	                                            section_index,
194 	                                            NULL));
195 }
196