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
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
;
38 static void lucca_layout_init(GTypeInstance
* instance
, gpointer g_class
) {
39 LuccaLayout
* layout
= LUCCA_LAYOUT(instance
);
43 layout
->border_size
= 0;
46 layout
->dispose_has_run
= FALSE
;
49 static void _unref_tile(gpointer data
, gpointer user_data
) {
50 LuccaLayoutTile
* tile
= LUCCA_LAYOUTTILE(data
);
54 static void lucca_layout_dispose(GObject
* obj
) {
55 LuccaLayout
* layout
= LUCCA_LAYOUT(obj
);
57 if (layout
->dispose_has_run
) {
60 layout
->dispose_has_run
= TRUE
;
62 /* The layout should currently hold no references because of deinit() */
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
);
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
) {
79 g_value_set_uint(value
, layout
->width
);
82 g_value_set_uint(value
, layout
->height
);
85 g_value_set_uint(value
, layout
->border_size
);
88 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
,property_id
,pspec
);
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
);
98 /* method overrides */
99 gobclass
->dispose
= lucca_layout_dispose
;
100 gobclass
->get_property
= lucca_layout_get_property
;
103 pspec
= g_param_spec_uint(
106 "Get layout width in pixels",
107 0, /* minimum value */
108 G_MAXUINT
, /* maximum value */
109 0, /* default value */
111 g_object_class_install_property(gobclass
, PROP_WIDTH
, pspec
);
113 pspec
= g_param_spec_uint(
116 "Get layout height in pixels",
117 0, /* minimum value */
118 G_MAXUINT
, /* maximum value */
119 0, /* default value */
121 g_object_class_install_property(gobclass
, PROP_HEIGHT
, pspec
);
123 pspec
= g_param_spec_uint(
126 "Get size of gaps between tiles in pixels",
127 0, /* minimum value */
128 G_MAXUINT
, /* maximum value */
129 0, /* default value */
131 g_object_class_install_property(gobclass
, PROP_BORDERSIZE
, pspec
);
134 klass
->new_tile_signal_id
= g_signal_new(
136 G_TYPE_FROM_CLASS(g_class
),
138 0, /* class_offset */
139 NULL
, /* accumulator */
140 NULL
, /* accu_data */
141 g_cclosure_marshal_VOID__OBJECT
,
144 LUCCA_TYPE_LAYOUTTILE
147 parent_class
= g_type_class_peek_parent(klass
);
150 GType
lucca_layout_get_type() {
151 static GType 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
),
164 type
= g_type_register_static (G_TYPE_OBJECT
, "LuccaLayoutType", &info
, 0);
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
;
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
);
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
) {
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 */
231 LuccaLayoutTile
* lucca_layout_get_tile_at_position(LuccaLayout
* layout
, gint x
, gint y
) {
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
))
245 GList
* lucca_layout_get_tiles_in_rectangle(LuccaLayout
* layout
, gint x
, gint y
, gint width
, gint height
) {
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
);
264 GList
* lucca_layout_get_tiles(LuccaLayout
* layout
) {
268 for (i
=layout
->tiles
; i
!= NULL
; i
=i
->next
) {
269 result
= g_list_prepend(result
, i
->data
);
275 LuccaLayoutTile
* lucca_layout_newtile_at_point(LuccaLayout
* layout
, gint x
, gint y
) {
279 for (i
=layout
->tiles
; i
!= NULL
; i
=i
->next
) {
280 t
= LUCCA_LAYOUTTILE(i
->data
);
285 if (lucca_rect_contains_point(t
->new_rect
, x
, y
))