diff --git a/src/gtk-ui/Makefile.am b/src/gtk-ui/Makefile.am index a3d60af4..8c21c98c 100644 --- a/src/gtk-ui/Makefile.am +++ b/src/gtk-ui/Makefile.am @@ -19,7 +19,9 @@ ui.xml: ui.glade bin_PROGRAMS = \ sync-ui -sync_ui_SOURCES = sync-ui.c sync-ui-config.c sync-ui-config.h mux-bin.c mux-bin.h mux-window.c mux-window.h +sync_ui_SOURCES = \ + sync-ui.c sync-ui-config.c sync-ui-config.h \ + mux-bin.c mux-bin.h mux-window.c mux-window.h mux-icon-button.c mux-icon-button.h sync_ui_LDADD = $(GUI_LIBS) $(DBUS_GLIB_LIBS) -L$(top_builddir)/syncevo-dbus -lsyncevo-dbus sync_ui_CFLAGS = $(GUI_CFLAGS) $(DBUS_GLIB_CFLAGS) -DGLADEDIR=\""$(gladedir)"\" -DTHEMEDIR=\""$(themercdir)"\" diff --git a/src/gtk-ui/mux-icon-button.c b/src/gtk-ui/mux-icon-button.c new file mode 100644 index 00000000..26ecf66a --- /dev/null +++ b/src/gtk-ui/mux-icon-button.c @@ -0,0 +1,207 @@ +/* TODO: should probably ensure specific icon size? */ + +#include "mux-icon-button.h" + +enum { + PROP_0, + PROP_NORMAL_FILENAME, + PROP_HOVER_FILENAME, +}; + +G_DEFINE_TYPE (MuxIconButton, mux_icon_button, GTK_TYPE_BUTTON) + + +static void +mux_icon_button_get_property (GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + MuxIconButton *btn = MUX_ICON_BUTTON (object); + + switch (property_id) { + case PROP_NORMAL_FILENAME: + g_value_set_string (value, mux_icon_button_get_normal_filename (btn)); + break; + case PROP_HOVER_FILENAME: + g_value_set_string (value, mux_icon_button_get_hover_filename (btn)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +mux_icon_button_set_property (GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) +{ + MuxIconButton *btn = MUX_ICON_BUTTON (object); + + switch (property_id) { + case PROP_NORMAL_FILENAME: + mux_icon_button_set_normal_filename (btn, g_value_get_string (value)); + break; + case PROP_HOVER_FILENAME: + mux_icon_button_set_hover_filename (btn, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +mux_icon_button_dispose (GObject *object) +{ + G_OBJECT_CLASS (mux_icon_button_parent_class)->dispose (object); +} + +static void +mux_icon_button_finalize (GObject *object) +{ + G_OBJECT_CLASS (mux_icon_button_parent_class)->finalize (object); +} + +static void +mux_icon_button_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + MuxIconButton *btn = MUX_ICON_BUTTON (widget); + + if (btn->normal_pixbuf) { + requisition->width = gdk_pixbuf_get_width (btn->normal_pixbuf); + requisition->height = gdk_pixbuf_get_height (btn->normal_pixbuf); + } +} + +static gboolean +mux_icon_button_enter_notify (GtkWidget *widget, GdkEventCrossing *event) +{ + GTK_WIDGET_CLASS (mux_icon_button_parent_class)->enter_notify_event (widget, event); + gtk_widget_queue_draw (widget); + + return FALSE; +} + +static gboolean +mux_icon_button_leave_notify (GtkWidget *widget, GdkEventCrossing *event) +{ + GTK_WIDGET_CLASS (mux_icon_button_parent_class)->leave_notify_event (widget, event); + gtk_widget_queue_draw (widget); + + return FALSE; +} + +static gboolean +mux_icon_button_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GdkRectangle dirty_area, btn_area; + + MuxIconButton *btn = MUX_ICON_BUTTON (widget); + GdkPixbuf *pixbuf; + + if (btn->hover_pixbuf && GTK_BUTTON (btn)->in_button) { + pixbuf = btn->hover_pixbuf; + } else { + pixbuf = btn->normal_pixbuf; + } + + if (!pixbuf) + return FALSE; + + btn_area.width = gdk_pixbuf_get_width (pixbuf); + btn_area.height = gdk_pixbuf_get_height (pixbuf); + btn_area.x = widget->allocation.x + (widget->allocation.width - btn_area.width) / 2; + btn_area.y = widget->allocation.y + (widget->allocation.height - btn_area.height) / 2; + + if (gdk_rectangle_intersect (&event->area, &widget->allocation, &dirty_area) && + gdk_rectangle_intersect (&btn_area, &dirty_area, &dirty_area)) { + + gdk_draw_pixbuf (widget->window, NULL, pixbuf, + dirty_area.x - btn_area.x, dirty_area.y - btn_area.y, + dirty_area.x, dirty_area.y, + dirty_area.width, dirty_area.height, + GDK_RGB_DITHER_NORMAL, 0, 0); + } + return FALSE; +} + +static void +mux_icon_button_class_init (MuxIconButtonClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GParamSpec *pspec; + + object_class->get_property = mux_icon_button_get_property; + object_class->set_property = mux_icon_button_set_property; + object_class->dispose = mux_icon_button_dispose; + object_class->finalize = mux_icon_button_finalize; + + widget_class->size_request = mux_icon_button_size_request; + widget_class->expose_event = mux_icon_button_expose; + widget_class->enter_notify_event = mux_icon_button_enter_notify; + widget_class->leave_notify_event = mux_icon_button_leave_notify; + + pspec = g_param_spec_string ("normal-filename", + "Normal filename", + "Icon filename for normal state", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_NORMAL_FILENAME, pspec); + + pspec = g_param_spec_string ("hover-filename", + "Hover filename", + "Icon filename for hover state", + NULL, + G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_HOVER_FILENAME, pspec); +} + +static void +mux_icon_button_init (MuxIconButton *self) +{ +} + +GtkWidget* +mux_icon_button_new (const char *normal_file, const char *hover_file) +{ + return g_object_new (MUX_TYPE_ICON_BUTTON, + "normal-filename", normal_file, + "hover-filename", hover_file, + NULL); +} + +const char * +mux_icon_button_get_normal_filename (MuxIconButton *btn) +{ + return (btn->normal_filename); +} + +void +mux_icon_button_set_normal_filename (MuxIconButton *btn, const char *name) +{ + if (btn->normal_filename) + g_free (btn->normal_filename); + if (btn->normal_pixbuf) + g_object_unref (btn->normal_pixbuf); + + btn->normal_filename = g_strdup (name); + btn->normal_pixbuf = gdk_pixbuf_new_from_file (name, NULL); +} + +const char * +mux_icon_button_get_hover_filename (MuxIconButton *btn) +{ + return (btn->hover_filename); +} + +void +mux_icon_button_set_hover_filename (MuxIconButton *btn, const char *name) +{ + if (btn->hover_filename) + g_free (btn->hover_filename); + if (btn->hover_pixbuf) + g_object_unref (btn->hover_pixbuf); + + btn->hover_filename = g_strdup (name); + btn->hover_pixbuf = gdk_pixbuf_new_from_file (name, NULL); +} diff --git a/src/gtk-ui/mux-icon-button.h b/src/gtk-ui/mux-icon-button.h new file mode 100644 index 00000000..0793ce5c --- /dev/null +++ b/src/gtk-ui/mux-icon-button.h @@ -0,0 +1,50 @@ +#ifndef _MUX_ICON_BUTTON +#define _MUX_ICON_BUTTON + +#include + +G_BEGIN_DECLS + +#define MUX_TYPE_ICON_BUTTON mux_icon_button_get_type() + +#define MUX_ICON_BUTTON(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUX_TYPE_ICON_BUTTON, MuxIconButton)) + +#define MUX_ICON_BUTTON_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MUX_TYPE_ICON_BUTTON, MuxIconButtonClass)) + +#define MUX_IS_ICON_BUTTON(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUX_TYPE_ICON_BUTTON)) + +#define MUX_IS_ICON_BUTTON_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MUX_TYPE_ICON_BUTTON)) + +#define MUX_ICON_BUTTON_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MUX_TYPE_ICON_BUTTON, MuxIconButtonClass)) + +typedef struct { + GtkButton parent; + + char *normal_filename; + GdkPixbuf *normal_pixbuf; + char *hover_filename; + GdkPixbuf *hover_pixbuf; +} MuxIconButton; + +typedef struct { + GtkButtonClass parent_class; +} MuxIconButtonClass; + +GType mux_icon_button_get_type (void); + +GtkWidget* mux_icon_button_new (const char *normal_file, const char *hover_file); + +const char* mux_icon_button_get_normal_filename (MuxIconButton *btn); +void mux_icon_button_set_normal_filename (MuxIconButton *btn, const char *name); + +const char* mux_icon_button_get_hover_filename (MuxIconButton *btn); +void mux_icon_button_set_hover_filename (MuxIconButton *btn, const char *name); + +G_END_DECLS + +#endif diff --git a/src/gtk-ui/mux-window.c b/src/gtk-ui/mux-window.c new file mode 100644 index 00000000..731c7dce --- /dev/null +++ b/src/gtk-ui/mux-window.c @@ -0,0 +1,458 @@ +#include "mux-window.h" +#include "mux-icon-button.h" + +static GdkColor mux_window_default_title_bar_bg = { 0, 0x3300, 0x3300, 0x3300 }; +static GdkColor mux_window_default_title_bar_fg = { 0, 0x2c00, 0x2c00, 0x2c00 }; + +#define MUX_WINDOW_DEFAULT_TITLE_BAR_HEIGHT 63 + +GType +mux_decorations_get_type (void) +{ + static GType etype = 0; + if (etype == 0) { + static const GFlagsValue values[] = { + { MUX_DECOR_CLOSE, "MUX_CLOSE", "close" }, + { MUX_DECOR_SETTINGS, "MUX_SETTINGS", "settings" }, + { 0, NULL, NULL } + }; + etype = g_flags_register_static (g_intern_static_string ("MuxDecorations"), values); + } + return etype; +} + + +enum { + PROP_0, + PROP_DECORATIONS, +}; + +enum { + SETTINGS_CLICKED, + LAST_SIGNAL +}; + +static guint mux_window_signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (MuxWindow, mux_window, GTK_TYPE_WINDOW) + +#define GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), MUX_TYPE_WINDOW, MuxWindowPrivate)) + +typedef struct _MuxWindowPrivate MuxWindowPrivate; + +struct _MuxWindowPrivate { + int dummy; +}; + +static void +mux_window_get_property (GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + MuxWindow *win = MUX_WINDOW (object); + + switch (property_id) { + case PROP_DECORATIONS: + g_value_set_uint (value, win->decorations); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +mux_window_set_property (GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) +{ + MuxWindow *win = MUX_WINDOW (object); + + switch (property_id) { + case PROP_DECORATIONS: + mux_window_set_decorations (win, g_value_get_uint (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +mux_window_update_style (MuxWindow *win) +{ + GdkColor *title_bar_bg = NULL; + GdkColor *title_bar_fg = NULL; + guint title_bar_height; + char *title_bar_font = NULL; + + g_return_if_fail (win->title_bar && win->title_label); + + gtk_widget_style_get (GTK_WIDGET (win), + "title-bar-height", &title_bar_height, + "title-bar-bg", &title_bar_bg, + "title-bar-fg", &title_bar_fg, + "title-bar-font", &title_bar_font, + NULL); + + if (title_bar_bg) { + gtk_widget_modify_bg (win->title_bar, GTK_STATE_NORMAL, title_bar_bg); + gdk_color_free (title_bar_bg); + } else { + gtk_widget_modify_bg (win->title_bar, GTK_STATE_NORMAL, + &mux_window_default_title_bar_bg); + } + + if (title_bar_fg) { + gtk_widget_modify_fg (win->title_label, GTK_STATE_NORMAL, title_bar_fg); + gdk_color_free (title_bar_fg); + } else { + gtk_widget_modify_fg (win->title_label, GTK_STATE_NORMAL, + &mux_window_default_title_bar_fg); + } + + if (title_bar_font) { + PangoFontDescription *desc; + desc = pango_font_description_from_string (title_bar_font); + gtk_widget_modify_font (win->title_label, desc); + pango_font_description_free (desc); + g_free (title_bar_font); + } + + gtk_widget_set_size_request (win->title_bar, -1, title_bar_height); + gtk_misc_set_padding (GTK_MISC (win->title_label), title_bar_height / 3, 0); +} + +static void +mux_window_style_set (GtkWidget *widget, + GtkStyle *previous) +{ + MuxWindow *win = MUX_WINDOW (widget); + + mux_window_update_style (win); + + GTK_WIDGET_CLASS (mux_window_parent_class)->style_set (widget, previous); +} + +static void +mux_window_dispose (GObject *object) +{ + G_OBJECT_CLASS (mux_window_parent_class)->dispose (object); +} + +static void +mux_window_finalize (GObject *object) +{ + G_OBJECT_CLASS (mux_window_parent_class)->finalize (object); +} + +static gboolean +mux_window_expose(GtkWidget *widget, + GdkEventExpose *event) +{ + if (GTK_WIDGET_DRAWABLE (widget)) { + (* GTK_WIDGET_CLASS (mux_window_parent_class)->expose_event) (widget, event); + } + return FALSE; +} + +static void +mux_window_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + MuxWindow *mux_win = MUX_WINDOW (container); + GtkBin *bin = GTK_BIN (container); + + /* FIXME: call parents forall instead */ + if (bin->child) + (* callback) (bin->child, callback_data); + + if (mux_win->title_bar) + (* callback) (mux_win->title_bar, callback_data); +} + +static void +mux_window_remove (GtkContainer *container, + GtkWidget *child) +{ + MuxWindow *win = MUX_WINDOW (container); + + if (child == win->title_bar) { + gtk_widget_unparent (win->title_bar); + win->title_bar = NULL; + win->title_label = NULL; + } else { + GTK_CONTAINER_CLASS (mux_window_parent_class)->remove (container, child); + } +} + +static void +mux_window_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + MuxWindow *mux_win = MUX_WINDOW (widget); + GtkBin *bin = GTK_BIN (widget); + GtkRequisition child_req; + GtkRequisition title_req; + + child_req.width = child_req.height = 0; + if (bin->child) + gtk_widget_size_request (bin->child, &child_req); + + title_req.width = title_req.height = 0; + if (mux_win->title_bar) { + gtk_widget_size_request (mux_win->title_bar, &title_req); + } + + requisition->width = MAX (child_req.width, title_req.width) + + 2 * (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->xthickness); + requisition->height = title_req.height + child_req.height + + 2 * (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->ythickness); +} + +static void +mux_window_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin = GTK_BIN (widget); + MuxWindow *mux_win = MUX_WINDOW (widget); + GtkAllocation child_allocation; + int xmargin, ymargin, title_height; + + widget->allocation = *allocation; + xmargin = GTK_CONTAINER (widget)->border_width + + widget->style->xthickness; + ymargin = GTK_CONTAINER (widget)->border_width + + widget->style->ythickness; + title_height = 0; + + if (mux_win->title_bar) { + GtkAllocation title_allocation; + GtkRequisition title_req; + gtk_widget_get_child_requisition (mux_win->title_bar, &title_req); + + title_height = title_req.height; + title_allocation.x = allocation->x; + title_allocation.y = allocation->y; + title_allocation.width = allocation->width; + title_allocation.height = title_height; + gtk_widget_size_allocate (mux_win->title_bar, &title_allocation); + + } + + child_allocation.x = allocation->x + xmargin; + child_allocation.y = allocation->y + title_height + ymargin; + child_allocation.width = allocation->width - 2 * xmargin; + child_allocation.height = allocation->height - (2 * ymargin + title_height); + + if (GTK_WIDGET_MAPPED (widget) && + (child_allocation.x != mux_win->child_allocation.x || + child_allocation.y != mux_win->child_allocation.y || + child_allocation.width != mux_win->child_allocation.width || + child_allocation.height != mux_win->child_allocation.height)) { + gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE); + } + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) { + gtk_widget_size_allocate (bin->child, &child_allocation); + } + + mux_win->child_allocation = child_allocation; +} + + +static void +mux_window_class_init (MuxWindowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (klass, sizeof (MuxWindowPrivate)); + + object_class->get_property = mux_window_get_property; + object_class->set_property = mux_window_set_property; + object_class->dispose = mux_window_dispose; + object_class->finalize = mux_window_finalize; + + widget_class->expose_event = mux_window_expose; + widget_class->size_request = mux_window_size_request; + widget_class->size_allocate = mux_window_size_allocate; + widget_class->style_set = mux_window_style_set; + + container_class->forall = mux_window_forall; + container_class->remove = mux_window_remove; + + pspec = g_param_spec_uint ("title-bar-height", + "Title bar height", + "Total height of the title bar", + 0, G_MAXUINT, MUX_WINDOW_DEFAULT_TITLE_BAR_HEIGHT, + G_PARAM_READWRITE); + gtk_widget_class_install_style_property(widget_class, pspec); + pspec = g_param_spec_boxed ("title-bar-bg", + "Title bar bg color", + "Color of the title bar background", + GDK_TYPE_COLOR, + G_PARAM_READWRITE); + gtk_widget_class_install_style_property(widget_class, pspec); + pspec = g_param_spec_boxed ("title-bar-fg", + "Title bar fg color", + "Color of the title bar foreground (text)", + GDK_TYPE_COLOR, + G_PARAM_READWRITE); + gtk_widget_class_install_style_property(widget_class, pspec); + pspec = g_param_spec_string ("title-bar-font", + "Title bar font", + "Pango font description string for title bar text", + "Bold 25", + G_PARAM_READWRITE); + gtk_widget_class_install_style_property(widget_class, pspec); + + pspec = g_param_spec_flags ("decorations", + NULL, + "Bitfield of MuxDecorations defining used window decorations", + MUX_TYPE_DECORATIONS, + MUX_DECOR_CLOSE, + G_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_DECORATIONS, + pspec); + + mux_window_signals[SETTINGS_CLICKED] = + g_signal_new ("settings-clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (MuxWindowClass, settings_clicked), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0, NULL); + +} + +static void +mux_window_settings_clicked (MuxWindow *window) +{ + g_signal_emit (window, mux_window_signals[SETTINGS_CLICKED], 0, NULL); +} + +static void +mux_window_close_clicked (MuxWindow *window) +{ + /* this is how GtkDialog does it... */ + GdkEvent *event; + + event = gdk_event_new (GDK_DELETE); + event->any.window = g_object_ref (gtk_widget_get_window (GTK_WIDGET (window))); + event->any.send_event = TRUE; + + gtk_main_do_event (event); + gdk_event_free (event); +} + +static void +mux_window_build_title_bar (MuxWindow *window) +{ + GtkWidget *box, *btn, *sep; + + if (window->title_bar) { + gtk_widget_unparent (window->title_bar); + } + + window->title_bar = gtk_event_box_new (); + gtk_widget_set_name (window->title_bar, "mux_window_title_bar"); + gtk_widget_set_parent (window->title_bar, GTK_WIDGET (window)); + gtk_widget_show (window->title_bar); + + box = gtk_hbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window->title_bar), box); + gtk_widget_show (box); + + window->title_label = gtk_label_new (gtk_window_get_title (GTK_WINDOW (window))); + gtk_box_pack_start (GTK_BOX (box), window->title_label, + FALSE, FALSE, 0); + gtk_widget_show (window->title_label); + + if (window->decorations & MUX_DECOR_CLOSE) { + /* TODO load icons from theme when they are added to it */ + btn = mux_icon_button_new (THEMEDIR "close.png", THEMEDIR "close_hover.png"); + g_signal_connect_swapped (btn, "clicked", + G_CALLBACK (mux_window_close_clicked), window); + gtk_box_pack_end (GTK_BOX (box), btn, FALSE, FALSE, 0); + gtk_widget_show (btn); + } + + if (window->decorations & MUX_DECOR_SETTINGS) { + sep = gtk_vseparator_new (); + gtk_box_pack_end (GTK_BOX (box), sep, FALSE, FALSE, 0); + gtk_widget_show (sep); + } + + if (window->decorations & MUX_DECOR_SETTINGS) { + /* TODO load icons from theme when they are added to it */ + btn = mux_icon_button_new (THEMEDIR "settings.png", THEMEDIR "settings_hover.png"); + g_signal_connect_swapped (btn, "clicked", + G_CALLBACK (mux_window_settings_clicked), window); + gtk_box_pack_end (GTK_BOX (box), btn, FALSE, FALSE, 0); + gtk_widget_show (btn); + } + + mux_window_update_style (window); + + gtk_widget_map (window->title_bar); /*TODO: is there a better way to do this ? */ + if (GTK_WIDGET_VISIBLE (window)) + gtk_widget_queue_resize (GTK_WIDGET (window)); + +} + +static void +mux_window_title_changed (MuxWindow *window, + GParamSpec *pspec, + gpointer user_data) +{ + if (window->title_label) { + gtk_label_set_text (GTK_LABEL (window->title_label), + gtk_window_get_title (GTK_WINDOW (window))); + } +} + +static void +mux_window_init (MuxWindow *self) +{ + self->decorations = MUX_DECOR_CLOSE; + + gtk_window_maximize (GTK_WINDOW (self)); + gtk_window_set_decorated (GTK_WINDOW (self), FALSE); + + g_signal_connect (self, "notify::title", + G_CALLBACK (mux_window_title_changed), NULL); + + mux_window_build_title_bar (self); +} + +GtkWidget* +mux_window_new (void) +{ + return g_object_new (MUX_TYPE_WINDOW, NULL); +} + +void +mux_window_set_decorations (MuxWindow *window, + MuxDecorations decorations) +{ + g_return_if_fail (MUX_IS_WINDOW (window)); + + if (decorations != window->decorations) { + window->decorations = decorations; + mux_window_build_title_bar (window); + } +} + +MuxDecorations +mux_window_get_decorations (MuxWindow *window) +{ + g_return_val_if_fail (MUX_IS_WINDOW (window), MUX_DECOR_NONE); + + return window->decorations; +} diff --git a/src/gtk-ui/mux-window.h b/src/gtk-ui/mux-window.h new file mode 100644 index 00000000..85f5ddf1 --- /dev/null +++ b/src/gtk-ui/mux-window.h @@ -0,0 +1,58 @@ +#ifndef _MUX_WINDOW +#define _MUX_WINDOW + +#include + +G_BEGIN_DECLS + +typedef enum { + MUX_DECOR_NONE = 0, + MUX_DECOR_CLOSE = 1 << 0, + MUX_DECOR_SETTINGS = 1 << 1, +} MuxDecorations; + +GType mux_decorations_get_type (void) G_GNUC_CONST; +#define MUX_TYPE_DECORATIONS (mux_decorations_get_type()) + + +#define MUX_TYPE_WINDOW mux_window_get_type() +#define MUX_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUX_TYPE_WINDOW, MuxWindow)) +#define MUX_WINDOW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MUX_TYPE_WINDOW, MuxWindowClass)) +#define MUX_IS_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUX_TYPE_WINDOW)) +#define MUX_IS_WINDOW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MUX_TYPE_WINDOW)) +#define MUX_WINDOW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MUX_TYPE_WINDOW, MuxWindowClass)) + +typedef struct { + GtkWindow parent; + + GtkWidget *title_bar; + GtkWidget *title_label; + GtkWidget *title_alignment; + + GtkAllocation child_allocation; + + MuxDecorations decorations; + GdkColor title_bar_color; + guint title_bar_height; +} MuxWindow; + +typedef struct { + GtkWindowClass parent_class; + + void (*settings_clicked) (MuxWindow *window); +} MuxWindowClass; + +GType mux_window_get_type (void); + +GtkWidget* mux_window_new (void); + +void mux_window_set_decorations (MuxWindow *window, MuxDecorations decorations); +MuxDecorations mux_window_get_decorations (MuxWindow *window); +G_END_DECLS + +#endif diff --git a/src/gtk-ui/sync-ui.c b/src/gtk-ui/sync-ui.c index 55787777..f6aa68bb 100644 --- a/src/gtk-ui/sync-ui.c +++ b/src/gtk-ui/sync-ui.c @@ -37,6 +37,7 @@ #include "sync-ui-config.h" #include "mux-bin.h" +#include "mux-window.h" #define SYNC_UI_GCONF_DIR "/apps/sync-ui" #define SYNC_UI_SERVER_KEY SYNC_UI_GCONF_DIR"/server" @@ -524,6 +525,8 @@ sync_type_toggled_cb (GObject *radio, app_data *data) } +/* truly stupid, but glade doesn't allow GtkBin or custom containers. + Now glade has dummy containers that will be replaced here */ static GtkWidget* switch_dummy_to_mux_bin (GtkWidget *dummy) { @@ -537,8 +540,8 @@ switch_dummy_to_mux_bin (GtkWidget *dummy) gtk_container_remove (GTK_CONTAINER (dummy), child); gtk_container_remove (GTK_CONTAINER (parent), dummy); - /* truly stupid, but glade doesn't allow GtkBins -- - just making sure there are no other children in box */ + + /* make sure there are no other children in box */ g_assert (gtk_container_get_children (GTK_CONTAINER (parent)) == NULL); bin = mux_bin_new (); @@ -548,6 +551,22 @@ switch_dummy_to_mux_bin (GtkWidget *dummy) return bin; } +static GtkWidget* +switch_dummy_to_mux_window (GtkWidget *dummy) +{ + GtkWidget *window; + + g_assert (GTK_IS_BIN (dummy)); + + window = mux_window_new (); + gtk_window_set_title (GTK_WINDOW (window), "Sync"); + mux_window_set_decorations (MUX_WINDOW (window), + MUX_DECOR_CLOSE|MUX_DECOR_SETTINGS); + gtk_widget_reparent (gtk_bin_get_child (GTK_BIN (dummy)), window); + + return window; +} + static void show_link_button_url (GtkLinkButton *link) { @@ -571,6 +590,12 @@ key_press_cb (GtkWidget *widget, } } +static void settings_clicked (MuxWindow *win, app_data *data) +{ + g_debug ("TODO: settings clicked"); +} + + static gboolean init_ui (app_data *data) { @@ -590,10 +615,6 @@ init_ui (app_data *data) return FALSE; } - data->sync_win = GTK_WIDGET (gtk_builder_get_object (builder, "sync_win")); - data->services_win = GTK_WIDGET (gtk_builder_get_object (builder, "services_win")); - data->service_settings_win = GTK_WIDGET (gtk_builder_get_object (builder, "service_settings_win")); - data->server_box = GTK_WIDGET (gtk_builder_get_object (builder, "server_box")); data->no_server_box = GTK_WIDGET (gtk_builder_get_object (builder, "no_server_box")); data->server_failure_box = GTK_WIDGET (gtk_builder_get_object (builder, "server_failure_box")); @@ -641,6 +662,30 @@ init_ui (app_data *data) g_signal_connect (radio, "toggled", G_CALLBACK (sync_type_toggled_cb), data); + /* No (documented) way to add own widgets to gtkbuilder it seems... + swap the all dummy frames with MuxBins */ + data->sync_win = switch_dummy_to_mux_window (GTK_WIDGET (gtk_builder_get_object (builder, "sync_win"))); + data->services_win = switch_dummy_to_mux_window (GTK_WIDGET (gtk_builder_get_object (builder, "services_win"))); + gtk_widget_set_name (data->services_win, "services_win"); + data->service_settings_win = switch_dummy_to_mux_window (GTK_WIDGET (gtk_builder_get_object (builder, "service_settings_win"))); + gtk_widget_set_name (data->services_win, "service_settings_win"); + + data->main_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "main_frame"))); + gtk_widget_set_name (data->main_bin, "main_bin"); + data->log_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "log_frame"))); + mux_bin_set_title (MUX_BIN (data->log_bin), "Log"); + data->services_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "services_frame"))); + mux_bin_set_title (MUX_BIN (data->services_bin), "Service"); + data->backup_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "backup_frame"))); + mux_bin_set_title (MUX_BIN (data->backup_bin), "Backup"); + bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "services_list_frame"))); + mux_bin_set_title (MUX_BIN (bin), "Sync services"); + gtk_widget_set_name (bin, "services_list_bin"); + data->service_settings_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "service_settings_frame"))); + mux_bin_set_title (MUX_BIN (bin), "Sync service settings"); + + g_signal_connect (data->sync_win, "settings-clicked", + G_CALLBACK (settings_clicked), data); g_signal_connect (data->sync_win, "destroy", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect (data->services_win, "delete-event", @@ -668,23 +713,6 @@ init_ui (app_data *data) g_signal_connect (data->sync_btn, "clicked", G_CALLBACK (sync_clicked_cb), data); - /* No (documented) way to add own widgets to gtkbuilder it seems... - swap the all dummy frames with MuxBins */ - - data->main_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "main_frame"))); - gtk_widget_set_name (data->main_bin, "main_bin"); - data->log_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "log_frame"))); - mux_bin_set_title (MUX_BIN (data->log_bin), "Log"); - data->services_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "services_frame"))); - mux_bin_set_title (MUX_BIN (data->services_bin), "Service"); - data->backup_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "backup_frame"))); - mux_bin_set_title (MUX_BIN (data->backup_bin), "Backup"); - bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "services_list_frame"))); - mux_bin_set_title (MUX_BIN (bin), "Sync services"); - gtk_widget_set_name (bin, "services_list_bin"); - data->service_settings_bin = switch_dummy_to_mux_bin (GTK_WIDGET (gtk_builder_get_object (builder, "service_settings_frame"))); - mux_bin_set_title (MUX_BIN (bin), "Sync service settings"); - g_object_unref (builder); return TRUE; } diff --git a/src/gtk-ui/sync-ui.rc b/src/gtk-ui/sync-ui.rc index e3fe9625..abee7daa 100644 --- a/src/gtk-ui/sync-ui.rc +++ b/src/gtk-ui/sync-ui.rc @@ -1,28 +1,22 @@ -style "sync-bg" { - bg[NORMAL] = "#4a535a" -} -class "GtkWindow" style "sync-bg" +# generic rules for MuxWidgets -style "sync-bin" { +style "mux-win" { + bg[NORMAL] = "#4a535a" + MuxWindow::title-bar-bg = "#333333" + MuxWindow::title-bar-fg = "#c2c2c2" +} +class "MuxWindow" style "mux-win" + +style "mux-bin" { bg[NORMAL] = "#ffffff" MuxBin::border-color = "#dee2e5" MuxBin::bullet-color = "#aaaaaa" + MuxBin::title-font = "12" } -class "MuxBin" style "sync-bin" - -style "normal-mux-label" { - font_name = "12" -} -widget "sync_win.*.mux_bin_title" style "normal-mux-label" - -style "big-mux-label" { - font_name = "14" -} -widget "services_win.*.mux_bin_title" style "big-mux-label" -widget "service_settings_win.*.mux_bin_title" style "big-mux-label" +class "MuxBin" style "mux-bin" # tooltips seem to take their color from the window bg? working around that -style "gtk-tooltips-style" { +style "mux-tooltip-fix" { bg[NORMAL] = "#ffffff" } -widget "gtk-tooltip*" style "gtk-tooltips-style" +widget "gtk-tooltip*" style "mux-tooltip-fix"