diff options
author | Kristian Høgsberg <krh@redhat.com> | 2006-06-18 05:42:28 -0400 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2006-06-18 05:42:28 -0400 |
commit | 0b9d4f39d46da7c9a05863eb8d9bbe5f0df1a8e3 (patch) | |
tree | 95d6b38058d5e112787ae957573838a7fcabd43e | |
parent | bdd48abdb6dee06124f0208931b8622ccec436b1 (diff) |
Make the dock a GtkWidget.
-rw-r--r-- | dock.c | 597 |
1 files changed, 375 insertions, 222 deletions
@@ -4,6 +4,7 @@ */ #include <gtk/gtk.h> +#include <gtk/gtkprivate.h> #include <cairo.h> #include <cairo-xlib.h> #include <gdk/gdkx.h> @@ -19,25 +20,47 @@ #define KIBA_GCONF_PATH "/apps/kiba" #define PIXMAP_PATH "/usr/share/pixmaps" -typedef struct Dock Dock; -typedef struct Launcher Launcher; +GQuark kiba_error_quark (void) +{ + static GQuark q = 0; -struct Dock { - GtkWidget *window; - Model model; - int width, height; - int spacing; - int num_launchers; - GList *launchers; - int drag_offset_x, drag_offset_y; + if (q == 0) + q = g_quark_from_static_string ("kiba-quark"); + + return q; +} + +#define KIBA_ERROR kiba_error_quark () + +typedef struct _KibaDock KibaDock; +typedef struct _KibaDockClass KibaDockClass; +typedef struct _KibaLauncher KibaLauncher; + +struct _KibaDock +{ + GtkWidget widget; + + Model model; + int width; + int height; + int spacing; + int num_launchers; + GList *launchers; + int drag_offset_x; + int drag_offset_y; GConfClient *gconf_client; }; -struct Launcher { +struct _KibaDockClass +{ + GtkWidgetClass parent_class; +}; + +struct _KibaLauncher { GdkWindow *window; GdkPixbuf *pixbuf; - Dock *dock; + KibaDock *dock; Object *object; char *name; char *exec; @@ -45,27 +68,296 @@ struct Launcher { char *icon; }; -GQuark kiba_error_quark (void) +#define KIBA_TYPE_DOCK (kiba_dock_get_type ()) +#define KIBA_DOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), KIBA_TYPE_DOCK, KibaDock)) +#define KIBA_DOCK_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), KIBA_DOCK, KibaDockClass)) +#define KIBA_IS_DOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), KIBA_TYPE_DOCK)) +#define KIBA_IS_DOCK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), KIBA_TYPE_DOCK)) +#define KIBA_DOCK_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), KIBA_TYPE_DOCK, KibaDockClass)) + +static void kiba_dock_realize (GtkWidget *widget); +static void kiba_dock_show (GtkWidget *widget); +static void kiba_dock_map (GtkWidget *widget); +static gboolean kiba_dock_expose_event (GtkWidget *clock, + GdkEventExpose *event); +static gboolean kiba_dock_button_press_event (GtkWidget *widget, + GdkEventButton *event); +static gboolean kiba_dock_button_release_event (GtkWidget *widget, + GdkEventButton *event); +static gboolean kiba_dock_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event); + +static void kiba_dock_drag_data_received (GtkWidget *widget, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time); + +static void kiba_dock_init_model (Model *model, + int num_items, + int width, int height, + int spacing); + +static KibaLauncher *kiba_launcher_new (KibaDock *dock, Object *object, + const char *gconf_path); +static gint timeout_callback (gpointer data); + +G_DEFINE_TYPE (KibaDock, kiba_dock, GTK_TYPE_WIDGET) + +static void +kiba_dock_class_init (KibaDockClass *class) { - static GQuark q = 0; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + widget_class->realize = kiba_dock_realize; + widget_class->show = kiba_dock_show; + widget_class->map = kiba_dock_map; + widget_class->expose_event = kiba_dock_expose_event; + widget_class->drag_data_received = kiba_dock_drag_data_received; + widget_class->button_press_event = kiba_dock_button_press_event; + widget_class->button_release_event = kiba_dock_button_release_event; + widget_class->motion_notify_event = kiba_dock_motion_notify_event; +} - if (q == 0) - q = g_quark_from_static_string ("kiba-quark"); +static void +kiba_dock_init (KibaDock *dock) +{ + GSList *launchers, *l; + int num_launchers; + GError *error = NULL; + GdkScreen *screen; + int width, height, i; + KibaLauncher *launcher; + static const GtkTargetEntry targets[] = { + { "text/plain", 0, 0 } + }; - return q; + GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (dock), GTK_NO_WINDOW); + GTK_WIDGET_SET_FLAGS (GTK_WIDGET (dock), GTK_TOPLEVEL); + + GTK_PRIVATE_SET_FLAG (GTK_WIDGET (dock), GTK_ANCHORED); + + dock->gconf_client = gconf_client_get_default (); + + gconf_client_add_dir (dock->gconf_client, KIBA_GCONF_PATH, + GCONF_CLIENT_PRELOAD_NONE, NULL); + + launchers = gconf_client_all_dirs (dock->gconf_client, + KIBA_GCONF_PATH "/launchers", + &error); + if (error != NULL) { + printf ("error getting launchers: %s\n", error->message); + g_free (error->message); + } + + num_launchers = g_slist_length (launchers); + + screen = gdk_screen_get_default (); + width = gdk_screen_get_width (screen); + height = gdk_screen_get_height (screen); + + dock->spacing = 50; + dock->num_launchers = num_launchers; + + kiba_dock_init_model (&dock->model, num_launchers, + width, height, dock->spacing); + + for (l = launchers, i = 0; l != NULL; l = l->next, i++) { + char *path = l->data; + launcher = kiba_launcher_new (dock, &dock->model.objects[i + 1], path); + if (launcher == NULL) + continue; + dock->launchers = g_list_prepend (dock->launchers, launcher); + } + + gtk_drag_dest_set(GTK_WIDGET (dock), + GTK_DEST_DEFAULT_ALL, + targets, G_N_ELEMENTS (targets), + GDK_ACTION_MOVE | GDK_ACTION_COPY); + gtk_drag_dest_add_uri_targets (GTK_WIDGET (dock)); + + g_timeout_add (20, timeout_callback, dock); } -#define KIBA_ERROR kiba_error_quark () +GtkWidget* +kiba_dock_new (void) +{ + return g_object_new (KIBA_TYPE_DOCK, NULL); +} + +static void +kiba_dock_paint_dock (KibaDock *dock) +{ + GtkWidget *widget = GTK_WIDGET (dock); + cairo_pattern_t *gradient; + cairo_t *cr; + const int hmargin = 5, vmargin = 40, radius = 5; + + cr = gdk_cairo_create (widget->window); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_move_to (cr, hmargin, dock->height); + cairo_line_to (cr, hmargin, vmargin + radius); + cairo_arc (cr, hmargin + radius, vmargin + radius, + radius, M_PI, 3 * M_PI / 2); + cairo_line_to (cr, dock->width - hmargin - radius, vmargin); + cairo_arc (cr, dock->width - hmargin - radius, vmargin + radius, + radius, 3 * M_PI / 2, 2 * M_PI); + cairo_line_to (cr, dock->width - hmargin, dock->height); + + gradient = cairo_pattern_create_linear (dock->width / 2 - 1, vmargin, + dock->width / 2 + 1, dock->height); + cairo_pattern_add_color_stop_rgba (gradient, 0, 1, 1, 1, 0.4); + cairo_pattern_add_color_stop_rgba (gradient, 1, 1, 1, 1, 0.6); + cairo_set_source (cr, gradient); + cairo_fill_preserve (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 1); + cairo_set_line_width (cr, 1); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + + cairo_destroy (cr); + +} + +static void +kiba_launcher_paint (KibaLauncher *launcher) +{ + cairo_t *cr; + + cr = gdk_cairo_create (launcher->window); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + cairo_destroy (cr); + + gdk_pixbuf_render_to_drawable_alpha + (launcher->pixbuf, + launcher->window, + 0, 0, 0, 0, + gdk_pixbuf_get_width (launcher->pixbuf), + gdk_pixbuf_get_height (launcher->pixbuf), + GDK_PIXBUF_ALPHA_FULL, 0, + GDK_RGB_DITHER_NONE, 0, 0); +} + +static gboolean +kiba_dock_expose_event (GtkWidget *widget, + GdkEventExpose *event) +{ + KibaDock *dock = KIBA_DOCK (widget); + KibaLauncher *launcher; + GList *l; + + if (event->window == widget->window) + kiba_dock_paint_dock (dock); + else + { + for (l = dock->launchers; l != NULL; l = l->next) + { + launcher = l->data; + if (launcher->window != event->window) + continue; + + kiba_launcher_paint (launcher); + break; + } + } + + return TRUE; +} + +static void +kiba_dock_realize (GtkWidget *widget) +{ + KibaDock *dock = KIBA_DOCK (widget); + GdkScreen *screen; + GdkWindowAttr attributes; + gint attributes_mask; + + g_return_if_fail (KIBA_IS_DOCK (widget)); + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + screen = gdk_screen_get_default (); + + attributes.window_type = GDK_WINDOW_TEMP; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gdk_screen_get_rgba_visual (screen); + attributes.colormap = gdk_screen_get_rgba_colormap (screen); + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + + widget->window = gdk_window_new (gdk_screen_get_root_window (screen), + &attributes, attributes_mask); + gdk_window_set_user_data (widget->window, dock); +} + +static void +kiba_dock_show (GtkWidget *widget) +{ + KibaDock *dock = KIBA_DOCK (widget); + GtkAllocation allocation; + GdkScreen *screen; + int width, height; + const int padding = 20; + + GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE); + + if (!GTK_WIDGET_REALIZED (widget)) + { + screen = gdk_screen_get_default (); + width = gdk_screen_get_width (screen); + height = gdk_screen_get_height (screen); + + allocation.width = dock->num_launchers * dock->spacing + 2 * padding; + allocation.height = dock->spacing + padding; + allocation.x = (width - allocation.width + dock->spacing) / 2; + allocation.y = height - allocation.height; + + /* Technically, this should be in kiba_dock_size_allocate (). */ + dock->width = allocation.width; + dock->height = allocation.height; + + gtk_widget_size_allocate (widget, &allocation); + gtk_widget_realize (widget); + } + + gtk_widget_map (widget); +} + +static void +kiba_dock_map (GtkWidget *widget) +{ + KibaDock *dock = KIBA_DOCK (widget); + GList *l; + + GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + gdk_window_show (widget->window); + + for (l = dock->launchers; l != NULL; l = l->next) { + KibaLauncher *launcher = l->data; + gdk_window_show (launcher->window); + } +} static gint timeout_callback (gpointer data) { - Dock *dock = data; + KibaDock *dock = data; GList *l; int i; for (l = dock->launchers; l != NULL; l = l->next) { - Launcher *launcher = l->data; + KibaLauncher *launcher = l->data; gdk_window_move (launcher->window, launcher->object->position.x + 0.5, launcher->object->position.y + 0.5); @@ -78,8 +370,8 @@ timeout_callback (gpointer data) } static void -model_init_dock (Model *model, int num_items, - int width, int height, int spacing) +kiba_dock_init_model (Model *model, int num_items, + int width, int height, int spacing) { const int num_objects = num_items + 1; const int num_spacers = (num_objects - 1) * (num_objects - 2) / 2; @@ -140,96 +432,69 @@ model_init_dock (Model *model, int num_items, } } -static GdkFilterReturn -window_event (GdkXEvent *xevent, GdkEvent *event, gpointer data) +static gboolean +kiba_dock_button_press_event (GtkWidget *widget, + GdkEventButton *event) { - Dock *dock = data; + KibaDock *dock = KIBA_DOCK (widget); GList *l; - GdkModifierType state; - XEvent *ev = (XEvent *) xevent; - int x, y; - switch (ev->type) { - case ButtonPress: - dock->drag_offset_x = ev->xbutton.x; - dock->drag_offset_y = ev->xbutton.y; - for (l = dock->launchers; l != NULL; l = l->next) { - Launcher *launcher = l->data; - if (launcher->window == event->any.window) { - dock->model.mouse_anchor.x = launcher->object->position.x; - dock->model.mouse_anchor.y = launcher->object->position.y; - dock->model.mouse_anchor.object = launcher->object; - } - } - break; + dock->drag_offset_x = event->x; + dock->drag_offset_y = event->y; - case ButtonRelease: - dock->model.mouse_anchor.object = NULL; - break; + for (l = dock->launchers; l != NULL; l = l->next) + { + KibaLauncher *launcher = l->data; - case MotionNotify: - gdk_window_get_pointer (gdk_get_default_root_window(), &x, &y, &state); - dock->model.mouse_anchor.x = x - dock->drag_offset_x; - dock->model.mouse_anchor.y = y - dock->drag_offset_y; - break; + if (launcher->window != event->window) + continue; - default: - break; - } + dock->model.mouse_anchor.x = launcher->object->position.x; + dock->model.mouse_anchor.y = launcher->object->position.y; + dock->model.mouse_anchor.object = launcher->object; + break; + } - return GDK_FILTER_CONTINUE; + return TRUE; } static gboolean -dock_paint (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) +kiba_dock_button_release_event (GtkWidget *widget, + GdkEventButton *event) { - Dock *dock = user_data; - cairo_t *cr; - cairo_pattern_t *gradient; - const int hmargin = 5, vmargin = 40, radius = 5; + KibaDock *dock = KIBA_DOCK (widget); - cr = gdk_cairo_create (widget->window); - cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); - cairo_paint (cr); + dock->model.mouse_anchor.object = NULL; - cairo_set_operator (cr, CAIRO_OPERATOR_OVER); - cairo_move_to (cr, hmargin, dock->height); - cairo_line_to (cr, hmargin, vmargin + radius); - cairo_arc (cr, hmargin + radius, vmargin + radius, - radius, M_PI, 3 * M_PI / 2); - cairo_line_to (cr, dock->width - hmargin - radius, vmargin); - cairo_arc (cr, dock->width - hmargin - radius, vmargin + radius, - radius, 3 * M_PI / 2, 2 * M_PI); - cairo_line_to (cr, dock->width - hmargin, dock->height); - - gradient = cairo_pattern_create_linear (dock->width / 2 - 1, vmargin, - dock->width / 2 + 1, dock->height); - cairo_pattern_add_color_stop_rgba (gradient, 0, 1, 1, 1, 0.4); - cairo_pattern_add_color_stop_rgba (gradient, 1, 1, 1, 1, 0.6); - cairo_set_source (cr, gradient); - cairo_fill_preserve (cr); + return TRUE; +} - cairo_set_source_rgba (cr, 1, 1, 1, 1); - cairo_set_line_width (cr, 1); - cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); - cairo_stroke (cr); +static gboolean +kiba_dock_motion_notify_event (GtkWidget *widget, + GdkEventMotion *event) +{ + KibaDock *dock = KIBA_DOCK (widget); + GdkModifierType state; + int x, y; - cairo_destroy (cr); + gdk_window_get_pointer (gdk_get_default_root_window(), &x, &y, &state); + dock->model.mouse_anchor.x = x - dock->drag_offset_x; + dock->model.mouse_anchor.y = y - dock->drag_offset_y; return TRUE; } static void -parse_desktop_file (Launcher *launcher, const char *uri, GError **error) +parse_desktop_file (KibaLauncher *launcher, const char *uri, GError **error) { static const char file_uri_prefix[] = "file://"; static const char desktop_file_suffix[] = ".desktop"; static const char desktop_entry_group[] = "Desktop Entry"; static const struct { const char *name; size_t offset; } fields[] = { - { "Icon", G_STRUCT_OFFSET (Launcher, icon) }, - { "Exec", G_STRUCT_OFFSET (Launcher, exec) }, - { "Name", G_STRUCT_OFFSET (Launcher, name) }, - { "Comment", G_STRUCT_OFFSET (Launcher, comment) }, + { "Icon", G_STRUCT_OFFSET (KibaLauncher, icon) }, + { "Exec", G_STRUCT_OFFSET (KibaLauncher, exec) }, + { "Name", G_STRUCT_OFFSET (KibaLauncher, name) }, + { "Comment", G_STRUCT_OFFSET (KibaLauncher, comment) }, }; GKeyFile *file; @@ -262,7 +527,7 @@ parse_desktop_file (Launcher *launcher, const char *uri, GError **error) } static gboolean -load_icon (Launcher *launcher, GError **error) +load_icon (KibaLauncher *launcher, GError **error) { char *path; char *suffix; @@ -293,13 +558,11 @@ load_icon (Launcher *launcher, GError **error) } static void -launcher_create_window (Launcher *launcher, GError **error) +kiba_launcher_create_window (KibaLauncher *launcher, GError **error) { GdkWindowAttr attributes; gint attributes_mask; - GdkScreen *screen; - screen = gdk_screen_get_default (); - cairo_t *cr; + GdkScreen *screen = gdk_screen_get_default (); if (!load_icon (launcher, error)) return; @@ -327,34 +590,18 @@ launcher_create_window (Launcher *launcher, GError **error) launcher->window = gdk_window_new (gdk_screen_get_root_window (screen), &attributes, attributes_mask); - gdk_window_show (launcher->window); - - cr = gdk_cairo_create (launcher->window); - cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); - cairo_paint (cr); - cairo_destroy (cr); - - gdk_pixbuf_render_to_drawable_alpha - (launcher->pixbuf, - launcher->window, - 0, 0, 0, 0, - gdk_pixbuf_get_width (launcher->pixbuf), - gdk_pixbuf_get_height (launcher->pixbuf), - GDK_PIXBUF_ALPHA_FULL, 0, - GDK_RGB_DITHER_NONE, 0, 0); - - gdk_window_add_filter (launcher->window, window_event, launcher->dock); + gdk_window_set_user_data (launcher->window, launcher->dock); } -static Launcher * -launcher_new (Dock *dock, Object *object, const char *gconf_path) +static KibaLauncher * +kiba_launcher_new (KibaDock *dock, Object *object, const char *gconf_path) { - Launcher *launcher; + KibaLauncher *launcher; GError *error = NULL; char *desktop_file; char *key; - launcher = g_new (Launcher, 1); + launcher = g_new (KibaLauncher, 1); key = g_strdup_printf ("%s/file", gconf_path); desktop_file = gconf_client_get_string (dock->gconf_client, key, &error); @@ -379,7 +626,7 @@ launcher_new (Dock *dock, Object *object, const char *gconf_path) launcher->object = object; launcher->dock = dock; - launcher_create_window (launcher, &error); + kiba_launcher_create_window (launcher, &error); if (error != NULL) { printf ("error creating launcher window: %s\n", error->message); g_error_free (error); @@ -391,11 +638,15 @@ launcher_new (Dock *dock, Object *object, const char *gconf_path) } static void -dock_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context, - gint x, gint y, GtkSelectionData *selection_data, - guint info, guint time, gpointer data) +kiba_dock_drag_data_received(GtkWidget *widget, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) { - Dock *dock = data; + KibaDock *dock = KIBA_DOCK (widget); GError *error = NULL; char *key; @@ -425,114 +676,16 @@ dock_drag_data_received(GtkWidget *widget, GdkDragContext *drag_context, g_free (key); } -static GtkWidget * -create_dock_window (Dock *dock) -{ - const int padding = 20; - GtkWidget *window; - GdkScreen *screen; - GdkColormap *colormap; - int screen_width, screen_height; - static const GtkTargetEntry targets[] = { - { "text/plain", 0, 0 } - }; - - screen = gdk_screen_get_default (); - - screen_width = gdk_screen_get_width (screen); - screen_height = gdk_screen_get_height (screen); - - dock->width = dock->num_launchers * dock->spacing + 2 * padding; - dock->height = dock->spacing + padding; - - window = gtk_window_new (GTK_WINDOW_POPUP); - colormap = gdk_screen_get_rgba_colormap (screen); - gtk_widget_set_colormap(GTK_WIDGET (window), colormap); - - gtk_drag_dest_set(window, - GTK_DEST_DEFAULT_ALL, - targets, G_N_ELEMENTS (targets), - GDK_ACTION_MOVE | GDK_ACTION_COPY); - gtk_drag_dest_add_uri_targets (window); - - gtk_window_set_default_size (GTK_WINDOW (window), - dock->width, dock->height); - gtk_window_move (GTK_WINDOW (window), - (screen_width - dock->width + dock->spacing) / 2, - screen_height - dock->height); - - g_signal_connect (window, "expose-event", - G_CALLBACK (dock_paint), dock); - g_signal_connect (window, "drag-data-received", - G_CALLBACK (dock_drag_data_received), dock); - gtk_widget_set_app_paintable (window, TRUE); - gtk_widget_realize (window); - gdk_window_set_back_pixmap (window->window, NULL, FALSE); - gtk_widget_show (window); - - return window; -} - -static Dock * -dock_new (void) -{ - Dock *dock; - GSList *launchers, *l; - int num_launchers; - GError *error = NULL; - GdkScreen *screen; - int width, height, i; - Launcher *launcher; - - dock = g_new0 (Dock, 1); - - dock->gconf_client = gconf_client_get_default (); - - gconf_client_add_dir (dock->gconf_client, KIBA_GCONF_PATH, - GCONF_CLIENT_PRELOAD_NONE, NULL); - - launchers = gconf_client_all_dirs (dock->gconf_client, - KIBA_GCONF_PATH "/launchers", - &error); - if (error != NULL) { - printf ("error getting launchers: %s\n", error->message); - g_free (error->message); - } - - num_launchers = g_slist_length (launchers); - - screen = gdk_screen_get_default (); - width = gdk_screen_get_width (screen); - height = gdk_screen_get_height (screen); - - dock->spacing = 50; - dock->num_launchers = num_launchers; - dock->window = create_dock_window (dock); - - model_init_dock (&dock->model, num_launchers, width, height, dock->spacing); - - for (l = launchers, i = 0; l != NULL; l = l->next, i++) { - char *path = l->data; - launcher = launcher_new (dock, &dock->model.objects[i + 1], path); - if (launcher == NULL) - continue; - dock->launchers = g_list_prepend (dock->launchers, launcher); - } - - g_timeout_add (20, timeout_callback, dock); - - return dock; -} - int main (int argc, char *argv[]) { - Dock *dock; + GtkWidget *dock; - gtk_init (&argc, &argv); + gtk_init (&argc, &argv); - dock = dock_new (); + dock = kiba_dock_new (); + gtk_widget_show (dock); - gtk_main (); + gtk_main (); - return 0; + return 0; } |