/* * Copyright 2015 Javier S. Pedro * * This file is part of MDock. * * MDock is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MDock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MDock. If not, see . */ #include "mdock-item-window-selector.h" #include "mdock-window.h" #define MDOCK_ITEM_WINDOW_SELECTOR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), MDOCK_TYPE_ITEM_WINDOW_SELECTOR, MDockItemWindowSelectorPrivate)) #define GLOBAL_PADDING 8 #define WINDOW_PADDING 4 #define APP_NAME_PADDING 8 struct _MDockItemWindowSelectorPrivate { GSequence *windows; GSequenceIter *active_window; GtkLabel *app_label; GtkBox *window_box; }; static void mdock_item_window_selector_orientable_init(GtkOrientableIface *iface); G_DEFINE_TYPE_WITH_CODE(MDockItemWindowSelector, mdock_item_window_selector, GTK_TYPE_WINDOW, G_IMPLEMENT_INTERFACE(GTK_TYPE_ORIENTABLE, mdock_item_window_selector_orientable_init)) enum MDockItemWindowSelectorProperties { PROP_0, PROP_ITEM, N_PROPERTIES, PROP_ORIENTATION }; static GParamSpec *obj_properties[N_PROPERTIES] = { NULL }; G_DEFINE_QUARK(mdock-item-window-selector-menu, mdock_item_window_selector_menu) static GSequenceIter * find_window(MDockItemWindowSelector *self, WnckWindow *window) { GSequenceIter *iter = g_sequence_get_begin_iter(self->priv->windows); while (!g_sequence_iter_is_end(iter)) { MDockWindow *dwin = MDOCK_WINDOW(g_sequence_get(iter)); if (dwin->window == window) { return iter; } iter = g_sequence_iter_next(iter); } return NULL; } static gboolean handle_window_button_press(MDockItemWindowSelector *self, GdkEventButton *event, MDockWindow *window) { switch (event->button) { case 3: gtk_menu_popup(GTK_MENU(g_object_get_qdata(G_OBJECT(window), mdock_item_window_selector_menu_quark())), NULL, NULL, NULL, NULL, event->button, event->time); break; } return TRUE; } static gboolean handle_window_button_release(MDockItemWindowSelector *self, GdkEventButton *event, MDockWindow *window) { switch (event->button) { case 1: if (!wnck_window_is_minimized(window->window) && (wnck_window_is_most_recently_activated(window->window) || wnck_window_transient_is_most_recently_activated(window->window))) { wnck_window_minimize(window->window); } else { wnck_window_activate_transient(window->window, event->time); } break; } return TRUE; } static void mdock_item_window_selector_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { MDockItemWindowSelector *self = MDOCK_ITEM_WINDOW_SELECTOR(object); switch (property_id) { case PROP_ITEM: g_clear_object(&self->item); self->item = g_value_dup_object(value); break; case PROP_ORIENTATION: gtk_orientable_set_orientation(GTK_ORIENTABLE(self->priv->window_box), g_value_get_enum(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; } } static void mdock_item_window_selector_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { MDockItemWindowSelector *self = MDOCK_ITEM_WINDOW_SELECTOR(object); switch (property_id) { case PROP_ITEM: g_value_set_object(value, self->item); break; case PROP_ORIENTATION: g_value_set_enum(value, gtk_orientable_get_orientation(GTK_ORIENTABLE(self->priv->window_box))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; } } static void mdock_item_window_selector_constructed(GObject *object) { GtkWindow *window = GTK_WINDOW(object); window->type = GTK_WINDOW_POPUP; gtk_window_set_type_hint(window, GDK_WINDOW_TYPE_HINT_TOOLTIP); G_OBJECT_CLASS(mdock_item_window_selector_parent_class)->constructed(object); MDockItemWindowSelector *self = MDOCK_ITEM_WINDOW_SELECTOR(object); gtk_label_set_text(self->priv->app_label, mdock_item_get_display_name(self->item)); } static void mdock_item_window_selector_dispose(GObject *object) { G_OBJECT_CLASS(mdock_item_window_selector_parent_class)->dispose(object); } static void mdock_item_window_selector_finalize(GObject *object) { MDockItemWindowSelector *self = MDOCK_ITEM_WINDOW_SELECTOR(object); g_sequence_free(self->priv->windows); G_OBJECT_CLASS(mdock_item_window_selector_parent_class)->finalize(object); } static void mdock_item_window_selector_orientable_init(GtkOrientableIface *iface) { } static void mdock_item_window_selector_class_init(MDockItemWindowSelectorClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS (klass); obj_class->set_property = mdock_item_window_selector_set_property; obj_class->get_property = mdock_item_window_selector_get_property; obj_class->constructed = mdock_item_window_selector_constructed; obj_class->dispose = mdock_item_window_selector_dispose; obj_class->finalize = mdock_item_window_selector_finalize; g_type_class_add_private(obj_class, sizeof(MDockItemWindowSelectorPrivate)); obj_properties[PROP_ITEM] = g_param_spec_object("item", "The MDockItem the options in this menu apply to", "Set the MDockItem the options in this menu apply to", MDOCK_TYPE_ITEM, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, N_PROPERTIES, obj_properties); g_object_class_override_property(obj_class, PROP_ORIENTATION, "orientation"); } static void mdock_item_window_selector_init(MDockItemWindowSelector *self) { self->priv = MDOCK_ITEM_WINDOW_SELECTOR_GET_PRIVATE (self); self->priv->windows = g_sequence_new(NULL); self->priv->app_label = GTK_LABEL(gtk_label_new(NULL)); self->priv->window_box = GTK_BOX(gtk_hbox_new(TRUE, 1)); gtk_container_set_border_width(GTK_CONTAINER(self), GLOBAL_PADDING); gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(self->priv->window_box)); gtk_box_pack_start(self->priv->window_box, GTK_WIDGET(self->priv->app_label), TRUE, TRUE, APP_NAME_PADDING); gtk_widget_show_all(GTK_WIDGET(self->priv->window_box)); } void mdock_item_window_selector_add_window(MDockItemWindowSelector *self, WnckWindow *window) { MDockWindow *win = mdock_window_new(window); g_sequence_append(self->priv->windows, win); gtk_box_pack_start(self->priv->window_box, GTK_WIDGET(win), FALSE, FALSE, WINDOW_PADDING); gtk_widget_hide(GTK_WIDGET(self->priv->app_label)); gtk_widget_show(GTK_WIDGET(win)); g_signal_connect_object(win, "button-press-event", G_CALLBACK(handle_window_button_press), self, G_CONNECT_SWAPPED); g_signal_connect_object(win, "button-release-event", G_CALLBACK(handle_window_button_release), self, G_CONNECT_SWAPPED); g_object_set_qdata_full(G_OBJECT(win), mdock_item_window_selector_menu_quark(), wnck_action_menu_new(window), (GDestroyNotify)gtk_widget_destroy); } void mdock_item_window_selector_remove_window(MDockItemWindowSelector *self, WnckWindow *window) { GSequenceIter *iter = find_window(self, window); g_return_if_fail(iter); MDockWindow *dwin = g_sequence_get(iter); g_sequence_remove(iter); gtk_widget_destroy(GTK_WIDGET(dwin)); if (g_sequence_get_length(self->priv->windows) == 0) { gtk_widget_show(GTK_WIDGET(self->priv->app_label)); } GtkRequisition requisition; gtk_widget_size_request(GTK_WIDGET(self), &requisition); gtk_window_resize(GTK_WINDOW(self), requisition.width, requisition.height); } void mdock_item_window_selector_set_active_window(MDockItemWindowSelector *self, WnckWindow *window) { GSequenceIter *iter = find_window(self, window); g_return_if_fail(iter); MDockWindow *dwin = g_sequence_get(iter); mdock_window_schedule_screenshot(dwin); } MDockItemWindowSelector * mdock_item_window_selector_new(MDockItem *item) { return g_object_new(MDOCK_TYPE_ITEM_WINDOW_SELECTOR, "item", item, NULL); }