1 /* -*- mode: c; c-basic-offset: 2 -*-
6 #include <cairo-xlib.h>
12 #include <librsvg/rsvg.h>
13 #include <librsvg/rsvg-cairo.h>
17 typedef struct Closure Closure;
22 int drag_offset_x, drag_offset_y;
23 int anchor_x, anchor_y;
28 timeout_callback (gpointer data)
30 Closure *closure = data;
33 for (i = 0; i < closure->num_icons; i++) {
34 gdk_window_move (closure->windows[i],
35 closure->model.objects[i + 1].position.x + 0.5,
36 closure->model.objects[i + 1].position.y + 0.5);
39 for (i = 0; i < 4; i++)
40 model_step (&closure->model, 0.03);
46 create_window (GdkScreen *screen, int x, int y, int width, int height)
48 GdkWindowAttr attributes;
51 attributes.wclass = GDK_INPUT_OUTPUT;
52 attributes.visual = gdk_screen_get_rgba_visual (screen);
53 attributes.colormap = gdk_screen_get_rgba_colormap (screen);
54 attributes.window_type = GDK_WINDOW_TEMP;
58 attributes.width = width;
59 attributes.height = height;
60 attributes.event_mask =
62 GDK_BUTTON_PRESS_MASK |
63 GDK_BUTTON_RELEASE_MASK |
64 GDK_ENTER_NOTIFY_MASK |
65 GDK_LEAVE_NOTIFY_MASK |
66 GDK_POINTER_MOTION_MASK |
67 GDK_POINTER_MOTION_HINT_MASK;
69 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
71 return gdk_window_new (gdk_screen_get_root_window (screen),
72 &attributes, attributes_mask);
76 model_init_dock (Model *model, int num_items, int x, int y, int spacing)
78 const int num_objects = num_items + 1;
79 const int num_spacers = (num_objects - 1) * (num_objects - 2) / 2;
80 const int num_springs = num_objects - 1;
81 const int spread = spacing + 20;
87 memset (model, 0, sizeof *model);
88 model->objects = g_new (Object, num_objects);
89 model->num_objects = num_objects;
90 model->springs = g_new (Spring, num_springs);
91 model->num_springs = num_springs;
92 model->spacers = g_new (Spacer, num_spacers);
93 model->num_spacers = num_spacers;
94 model->anchors = g_new (Anchor, 1);
95 model->num_anchors = 1;
98 model->polygons = g_new (Polygon, 1);
99 model->num_polygons = 1;
100 polygon_init_enclosing_rectangle (&model->polygons[0], 0, 0, 1024 - 50, y);
102 model->anchors[0].x = x;
103 model->anchors[0].y = y;
104 model->anchors[0].object = &model->objects[0];
106 object_init (&model->objects[0], x, y, 0);
108 object = &model->objects[1];
109 spring = model->springs;
110 spacer = model->spacers;
111 left_edge = (1024 - (num_items - 1) * spread) / 2;
113 for (i = 1; i < num_objects; i++, object++) {
114 object_init (&model->objects[i], left_edge + (i - 1) * spread, y - 100, 1);
115 spring_init (spring++, &model->objects[0], object, spacing);
116 for (j = 1; j < num_objects - i; j++) {
117 spacer_init (spacer++, object, object + j, spacing);
122 static GdkFilterReturn
123 window_event (GdkXEvent *xevent, GdkEvent *event, gpointer data)
125 Closure *closure = data;
126 GdkModifierType state;
127 XEvent *ev = (XEvent *) xevent;
133 closure->drag_offset_x = ev->xbutton.x;
134 closure->drag_offset_y = ev->xbutton.y;
135 for (i = 0; i < closure->num_icons; i++) {
136 if (closure->windows[i] == event->any.window) {
137 object = &closure->model.objects[i + 1];
138 closure->model.mouse_anchor.x = object->position.x;
139 closure->model.mouse_anchor.y = object->position.y;
140 closure->model.mouse_anchor.object = object;
146 closure->model.mouse_anchor.object = NULL;
150 gdk_window_get_pointer (gdk_get_default_root_window(), &x, &y, &state);
151 closure->model.mouse_anchor.x = x - closure->drag_offset_x;
152 closure->model.mouse_anchor.y = y - closure->drag_offset_y;
153 if (closure->model.mouse_anchor.y > closure->anchor_y)
154 closure->model.mouse_anchor.y = closure->anchor_y;
161 return GDK_FILTER_CONTINUE;
164 static const char *icons[] = {
165 "svg/applications-office.svg",
166 "svg/camera-video.svg",
168 "svg/firefox-logo.svg",
169 "svg/gnome-dev-disc-dvdrom.svg",
170 "svg/gnome-terminal.svg",
171 "svg/help-browser.svg",
172 "svg/internet-group-chat.svg"
175 int main (int argc, char *argv[])
179 const int num_icons = G_N_ELEMENTS (icons);
180 int x, y, width, height, i;
182 RsvgDimensionData dimension;
184 const int screen_width = 1024, screen_height = 768, spacing = 50;
186 gtk_init (&argc, &argv);
190 screen = gdk_screen_get_default ();
192 closure.anchor_x = screen_width / 2;
193 closure.anchor_y = screen_height - 50;
194 closure.spacing = spacing;
195 closure.num_icons = num_icons;
196 closure.windows = g_new (GdkWindow *, num_icons);
198 model_init_dock (&closure.model, num_icons,
199 closure.anchor_x, closure.anchor_y, spacing);
201 for (i = 0; i < num_icons; i++) {
203 handle = rsvg_handle_new_from_file (icons[i], NULL);
204 rsvg_handle_get_dimensions (handle, &dimension);
206 x = closure.model.objects[i + 1].position.x;
207 y = closure.model.objects[i + 1].position.y;
208 width = dimension.width;
209 height = dimension.height;
210 closure.windows[i] = create_window (screen, x, y, width, height);
212 gdk_window_show (closure.windows[i]);
214 cr = gdk_cairo_create (closure.windows[i]);
215 cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
217 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
218 rsvg_handle_render_cairo (handle, cr);
219 rsvg_handle_free (handle);
222 gdk_window_add_filter (closure.windows[i], window_event, &closure);
225 g_timeout_add (20, timeout_callback, &closure);