implement lucca_layouttile_resize (untested)
[luccawm.git] / layout / lucca-layout.c
blob91870da861809b2c9efbfa7dde11e75d9e9dd384
1 /* Copyright (c) 2008 Vincent Povirk
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation
5 files (the "Software"), to deal in the Software without
6 restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following
10 conditions:
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
25 #include "lucca-layout-private.h"
27 /* Implementation of LuccaLayout */
29 static GObjectClass* parent_class = NULL;
31 /* property id's */
32 enum {
33 PROP_WIDTH=1,
34 PROP_HEIGHT,
35 PROP_BORDERSIZE,
38 static void lucca_layout_init(GTypeInstance* instance, gpointer g_class) {
39 LuccaLayout* layout = LUCCA_LAYOUT(instance);
41 layout->width = 0;
42 layout->height = 0;
43 layout->border_size = 0;
44 layout->tiles = NULL;
46 layout->dispose_has_run = FALSE;
49 static void _unref_tile(gpointer data, gpointer user_data) {
50 LuccaLayoutTile* tile = LUCCA_LAYOUTTILE(data);
52 g_object_unref(tile);
54 static void lucca_layout_dispose(GObject* obj) {
55 LuccaLayout* layout = LUCCA_LAYOUT(obj);
57 if (layout->dispose_has_run) {
58 return;
60 layout->dispose_has_run = TRUE;
62 /* The layout should currently hold no references because of deinit() */
63 if (layout->tiles) {
64 g_warning("LuccaLayout at %p was disposed before calling lucca_layout_deinit()\n", layout);
66 g_slist_foreach(layout->tiles, _unref_tile, NULL);
67 g_slist_free(layout->tiles);
68 layout->tiles = NULL;
71 G_OBJECT_CLASS(parent_class)->dispose(obj);
74 static void lucca_layout_get_property(GObject* object, guint property_id, GValue* value, GParamSpec* pspec) {
75 LuccaLayout* layout = LUCCA_LAYOUT(object);
77 switch (property_id) {
78 case PROP_WIDTH:
79 g_value_set_uint(value, layout->width);
80 break;
81 case PROP_HEIGHT:
82 g_value_set_uint(value, layout->height);
83 break;
84 case PROP_BORDERSIZE:
85 g_value_set_uint(value, layout->border_size);
86 break;
87 default:
88 G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
89 break;
93 static void lucca_layout_class_init(gpointer g_class, gpointer class_data) {
94 LuccaLayoutClass* klass = (LuccaLayoutClass*)g_class;
95 GObjectClass* gobclass = G_OBJECT_CLASS(g_class);
96 GParamSpec *pspec;
98 /* method overrides */
99 gobclass->dispose = lucca_layout_dispose;
100 gobclass->get_property = lucca_layout_get_property;
102 /* properties */
103 pspec = g_param_spec_uint(
104 "width",
105 "Layout width",
106 "Get layout width in pixels",
107 0, /* minimum value */
108 G_MAXUINT, /* maximum value */
109 0, /* default value */
110 G_PARAM_READABLE);
111 g_object_class_install_property(gobclass, PROP_WIDTH, pspec);
113 pspec = g_param_spec_uint(
114 "height",
115 "Layout height",
116 "Get layout height in pixels",
117 0, /* minimum value */
118 G_MAXUINT, /* maximum value */
119 0, /* default value */
120 G_PARAM_READABLE);
121 g_object_class_install_property(gobclass, PROP_HEIGHT, pspec);
123 pspec = g_param_spec_uint(
124 "border-size",
125 "Tile border size",
126 "Get size of gaps between tiles in pixels",
127 0, /* minimum value */
128 G_MAXUINT, /* maximum value */
129 0, /* default value */
130 G_PARAM_READABLE);
131 g_object_class_install_property(gobclass, PROP_BORDERSIZE, pspec);
133 /* signals */
134 klass->new_tile_signal_id = g_signal_new(
135 "new-tile",
136 G_TYPE_FROM_CLASS(g_class),
137 G_SIGNAL_RUN_LAST,
138 0, /* class_offset */
139 NULL, /* accumulator */
140 NULL, /* accu_data */
141 g_cclosure_marshal_VOID__OBJECT,
142 G_TYPE_NONE,
143 1, /* n_params */
144 LUCCA_TYPE_LAYOUTTILE
147 parent_class = g_type_class_peek_parent(klass);
150 GType lucca_layout_get_type() {
151 static GType type = 0;
152 if (type == 0) {
153 static const GTypeInfo info = {
154 sizeof (LuccaLayoutClass),
155 NULL, /* base_init */
156 NULL, /* base_finalize */
157 lucca_layout_class_init,
158 NULL, /* class_finalize */
159 NULL, /* class_data */
160 sizeof (LuccaLayout),
161 0, /* n_preallocs */
162 lucca_layout_init
164 type = g_type_register_static (G_TYPE_OBJECT, "LuccaLayoutType", &info, 0);
166 return type;
170 Method definitions.
173 void lucca_layout_initialize(LuccaLayout* layout, guint width, guint height, guint border_size, GdkGeometry geometry, GdkWindowHints geom_mask) {
174 LuccaLayoutTile* tile;
175 g_assert(layout->tiles == NULL);
176 g_assert(width >= 1 && height >= 1);
178 layout->width = width;
179 layout->height = height;
180 layout->border_size = border_size;
182 layout->rect = lucca_rect_from_xywh(0, 0, width+border_size, height+border_size);
184 tile = g_object_new(LUCCA_TYPE_LAYOUTTILE, NULL);
185 tile->layout = layout;
186 g_object_ref(layout);
187 tile->rect = layout->rect;
188 tile->valid = TRUE;
190 /* FIXME: We should verify that the layout isn't smaller than the geometry's minimum size. */
191 tile->geometry = geometry;
192 tile->geom_mask = geom_mask;
194 layout->tiles = g_slist_prepend(layout->tiles, tile);
196 /* emit the new-tile signal */
197 g_signal_emit(layout, LUCCA_LAYOUT_GET_CLASS(layout)->new_tile_signal_id, 0, tile);
200 static void _invalidate_tile(gpointer data, gpointer user_data) {
201 LuccaLayoutTile* tile = LUCCA_LAYOUTTILE(data);
203 tile->valid = FALSE;
205 static void _emitdelete_tile(gpointer data, gpointer user_data) {
206 LuccaLayoutTile* tile = LUCCA_LAYOUTTILE(data);
208 g_signal_emit(tile, LUCCA_LAYOUTTILE_GET_CLASS(tile)->delete_signal_id, 0);
210 void lucca_layout_deinit(LuccaLayout* layout) {
211 GSList* tiles;
213 tiles = layout->tiles;
215 /* Mark all tiles as invalid */
216 g_slist_foreach(tiles, _invalidate_tile, NULL);
218 /* "Remove" all tiles from the layout. */
219 layout->tiles = NULL;
221 /* Emit a delete signal on each tile*/
222 g_slist_foreach(tiles, _emitdelete_tile, NULL);
224 /* Actually unref the tiles */
225 g_slist_foreach(tiles, _unref_tile, NULL);
227 /* Delete the linked list of tiles */
228 g_slist_free(tiles);
231 LuccaLayoutTile* lucca_layout_get_tile_at_position(LuccaLayout* layout, gint x, gint y) {
232 GSList* i;
233 LuccaLayoutTile* t;
235 for (i=layout->tiles; i != NULL; i=i->next) {
236 t = LUCCA_LAYOUTTILE(i->data);
238 if (lucca_rect_contains_point(tile_rect(t), x, y))
239 return t;
242 return NULL;
245 GList* lucca_layout_get_tiles_in_rectangle(LuccaLayout* layout, gint x, gint y, gint width, gint height) {
246 GList* result=NULL;
247 GSList* i;
248 LuccaLayoutTile* t;
249 LuccaRect r;
251 r = lucca_rect_from_xywh(x, y, width, height);
253 for (i=layout->tiles; i != NULL; i=i->next) {
254 t = LUCCA_LAYOUTTILE(i->data);
256 if (lucca_rects_intersect(tile_rect(t), r)) {
257 result = g_list_prepend(result, (gpointer)t);
261 return result;
264 GList* lucca_layout_get_tiles(LuccaLayout* layout) {
265 GList* result=NULL;
266 GSList* i;
268 for (i=layout->tiles; i != NULL; i=i->next) {
269 result = g_list_prepend(result, i->data);
272 return result;
275 LuccaLayoutTile* lucca_layout_newtile_at_point(LuccaLayout* layout, gint x, gint y) {
276 GSList* i;
277 LuccaLayoutTile* t;
279 for (i=layout->tiles; i != NULL; i=i->next) {
280 t = LUCCA_LAYOUTTILE(i->data);
282 if (!t->new_valid)
283 continue;
285 if (lucca_rect_contains_point(t->new_rect, x, y))
286 return t;
289 return NULL;