From c2e94e1925f3c7acfa3fd3352dc8fdafe6375adc Mon Sep 17 00:00:00 2001 From: zhuyaliang <15132211195@163.com> Date: Wed, 25 Oct 2023 21:43:03 +0800 Subject: Remove libslab library libslab is only used in mate-c-c and there is no need to provide a library --- Makefile.am | 8 +- configure.ac | 19 +- libslab/Makefile.am | 71 -- libslab/app-resizer.c | 321 --------- libslab/app-resizer.h | 74 -- libslab/app-shell.c | 1448 --------------------------------------- libslab/app-shell.h | 142 ---- libslab/application-tile.c | 764 --------------------- libslab/application-tile.h | 67 -- libslab/bookmark-agent.c | 1244 --------------------------------- libslab/bookmark-agent.h | 98 --- libslab/double-click-detector.c | 87 --- libslab/double-click-detector.h | 58 -- libslab/libslab-utils.c | 70 -- libslab/libslab-utils.h | 14 - libslab/mate-slab.pc.in | 12 - libslab/mate-utils.c | 82 --- libslab/mate-utils.h | 34 - libslab/nameplate-tile.c | 274 -------- libslab/nameplate-tile.h | 57 -- libslab/nld-marshal.list | 1 - libslab/search-bar.c | 238 ------- libslab/search-bar.h | 66 -- libslab/shell-window.c | 83 --- libslab/shell-window.h | 65 -- libslab/slab-mate-util.c | 160 ----- libslab/slab-mate-util.h | 39 -- libslab/slab-section.c | 233 ------- libslab/slab-section.h | 72 -- libslab/slab.h | 40 -- libslab/themed-icon.c | 159 ----- libslab/themed-icon.h | 54 -- libslab/tile-action.c | 109 --- libslab/tile.c | 529 -------------- libslab/tile.h | 127 ---- po/POTFILES.in | 8 +- shell/Makefile.am | 55 +- shell/app-resizer.c | 321 +++++++++ shell/app-resizer.h | 74 ++ shell/app-shell.c | 1448 +++++++++++++++++++++++++++++++++++++++ shell/app-shell.h | 142 ++++ shell/application-tile.c | 764 +++++++++++++++++++++ shell/application-tile.h | 67 ++ shell/bookmark-agent.c | 1244 +++++++++++++++++++++++++++++++++ shell/bookmark-agent.h | 98 +++ shell/control-center.c | 2 +- shell/double-click-detector.c | 87 +++ shell/double-click-detector.h | 58 ++ shell/libslab-utils.c | 70 ++ shell/libslab-utils.h | 14 + shell/mate-utils.c | 82 +++ shell/mate-utils.h | 34 + shell/nameplate-tile.c | 274 ++++++++ shell/nameplate-tile.h | 57 ++ shell/nld-marshal.list | 1 + shell/search-bar.c | 238 +++++++ shell/search-bar.h | 66 ++ shell/shell-window.c | 83 +++ shell/shell-window.h | 65 ++ shell/slab-mate-util.c | 160 +++++ shell/slab-mate-util.h | 39 ++ shell/slab-section.c | 233 +++++++ shell/slab-section.h | 72 ++ shell/slab.h | 40 ++ shell/themed-icon.c | 159 +++++ shell/themed-icon.h | 54 ++ shell/tile-action.c | 109 +++ shell/tile.c | 529 ++++++++++++++ shell/tile.h | 127 ++++ 69 files changed, 6864 insertions(+), 6929 deletions(-) delete mode 100644 libslab/Makefile.am delete mode 100644 libslab/app-resizer.c delete mode 100644 libslab/app-resizer.h delete mode 100644 libslab/app-shell.c delete mode 100644 libslab/app-shell.h delete mode 100644 libslab/application-tile.c delete mode 100644 libslab/application-tile.h delete mode 100644 libslab/bookmark-agent.c delete mode 100644 libslab/bookmark-agent.h delete mode 100644 libslab/double-click-detector.c delete mode 100644 libslab/double-click-detector.h delete mode 100644 libslab/libslab-utils.c delete mode 100644 libslab/libslab-utils.h delete mode 100644 libslab/mate-slab.pc.in delete mode 100644 libslab/mate-utils.c delete mode 100644 libslab/mate-utils.h delete mode 100644 libslab/nameplate-tile.c delete mode 100644 libslab/nameplate-tile.h delete mode 100644 libslab/nld-marshal.list delete mode 100644 libslab/search-bar.c delete mode 100644 libslab/search-bar.h delete mode 100644 libslab/shell-window.c delete mode 100644 libslab/shell-window.h delete mode 100644 libslab/slab-mate-util.c delete mode 100644 libslab/slab-mate-util.h delete mode 100644 libslab/slab-section.c delete mode 100644 libslab/slab-section.h delete mode 100644 libslab/slab.h delete mode 100644 libslab/themed-icon.c delete mode 100644 libslab/themed-icon.h delete mode 100644 libslab/tile-action.c delete mode 100644 libslab/tile.c delete mode 100644 libslab/tile.h create mode 100644 shell/app-resizer.c create mode 100644 shell/app-resizer.h create mode 100644 shell/app-shell.c create mode 100644 shell/app-shell.h create mode 100644 shell/application-tile.c create mode 100644 shell/application-tile.h create mode 100644 shell/bookmark-agent.c create mode 100644 shell/bookmark-agent.h create mode 100644 shell/double-click-detector.c create mode 100644 shell/double-click-detector.h create mode 100644 shell/libslab-utils.c create mode 100644 shell/libslab-utils.h create mode 100644 shell/mate-utils.c create mode 100644 shell/mate-utils.h create mode 100644 shell/nameplate-tile.c create mode 100644 shell/nameplate-tile.h create mode 100644 shell/nld-marshal.list create mode 100644 shell/search-bar.c create mode 100644 shell/search-bar.h create mode 100644 shell/shell-window.c create mode 100644 shell/shell-window.h create mode 100644 shell/slab-mate-util.c create mode 100644 shell/slab-mate-util.h create mode 100644 shell/slab-section.c create mode 100644 shell/slab-section.h create mode 100644 shell/slab.h create mode 100644 shell/themed-icon.c create mode 100644 shell/themed-icon.h create mode 100644 shell/tile-action.c create mode 100644 shell/tile.c create mode 100644 shell/tile.h diff --git a/Makefile.am b/Makefile.am index 134c64ad..39d34639 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,15 +3,9 @@ PO_SUBDIR = po endif SUBDIRS = $(PO_SUBDIR) capplets font-viewer help man -DIST_SUBDIRS = po capplets font-viewer help libslab shell typing-break man +DIST_SUBDIRS = po capplets font-viewer help shell typing-break man -if HAVE_LIBMATESLAB -SUBDIRS += libslab -endif - -if HAVE_LIBMATESLAB SUBDIRS += shell -endif if HAVE_TYPING_BREAK SUBDIRS += typing-break diff --git a/configure.ac b/configure.ac index 30ff9ca3..a4272e1d 100644 --- a/configure.ac +++ b/configure.ac @@ -111,7 +111,7 @@ COMMON_MODULES="gtk+-3.0 >= $GTK_REQUIRED dnl mate-desktop-2.0 >= $MATE_DESKTOP_REQUIRED" PKG_CHECK_MODULES(CAPPLET, $COMMON_MODULES) PKG_CHECK_MODULES(MATECC, $COMMON_MODULES libmate-menu >= 1.21.0) -PKG_CHECK_MODULES(MATECC_SHELL, $COMMON_MODULES libmate-menu) +PKG_CHECK_MODULES(MATECC_SHELL, $COMMON_MODULES libmate-menu librsvg-2.0 pango) PKG_CHECK_MODULES(POLKIT, polkit-gobject-1) PKG_CHECK_MODULES(MATE_DESKTOP, mate-desktop-2.0 >= $MATE_DESKTOP_REQUIRED) @@ -136,20 +136,8 @@ AC_SUBST(GTK_ENGINE_DIR) PKG_CHECK_MODULES(GLIB, glib-2.0 >= $GLIB_REQUIRED $GMODULE_ADD) -dnl -dnl Check dependencies of libmate-slab -dnl -PKG_CHECK_MODULES(LIBSLAB, [ - gio-2.0 mate-desktop-2.0 librsvg-2.0 libmate-menu pango - ], - have_libmateslab=yes, - have_libmateslab=no) - -AC_SUBST(LIBMATESLAB_CFLAGS) -AC_SUBST(LIBMATESLAB_LIBS) -AC_SUBST(WARN_CFLAGS) -AM_CONDITIONAL(HAVE_LIBMATESLAB, [test $have_libmateslab = yes]) +AC_SUBST(LIBMATECC_SHELL_CFLAGS) dnl dnl Check dependencies of accountsservice @@ -301,8 +289,6 @@ font-viewer/Makefile help/Makefile man/Makefile po/Makefile.in -libslab/mate-slab.pc -libslab/Makefile shell/Makefile typing-break/Makefile ]) @@ -328,7 +314,6 @@ Configure summary: Ayatana AppIndicator (preferred) $(test "x$enable_appindicator" = xyes && echo no || echo yes) Ubuntu AppIndicator (legacy) $(test "x$enable_appindicator" = xyes && echo yes || echo no) - Libmate-slab: ${have_libmateslab} Accountsservice: ${have_accountsservice} Native Language support: ${USE_NLS} " diff --git a/libslab/Makefile.am b/libslab/Makefile.am deleted file mode 100644 index df720566..00000000 --- a/libslab/Makefile.am +++ /dev/null @@ -1,71 +0,0 @@ -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = mate-slab.pc - -AM_CPPFLAGS = \ - -DG_LOG_DOMAIN=\"libslab\" \ - -I$(top_srcdir) \ - $(LIBSLAB_CFLAGS) \ - $(WARN_CFLAGS) - -HEADER_FILES= \ - $(BUILT_SOURCES) \ - app-resizer.h \ - app-shell.h \ - application-tile.h \ - bookmark-agent.h \ - double-click-detector.h \ - mate-utils.h \ - libslab-utils.h \ - nameplate-tile.h \ - search-bar.h \ - shell-window.h \ - slab-mate-util.h \ - slab-section.h \ - slab.h \ - tile.h - -lib_LTLIBRARIES = libmate-slab.la - -libmate_slab_la_SOURCES = \ - $(MARSHAL_GENERATED) \ - app-resizer.c \ - app-shell.c \ - application-tile.c \ - bookmark-agent.c \ - double-click-detector.c \ - mate-utils.c \ - libslab-utils.c \ - nameplate-tile.c \ - search-bar.c \ - shell-window.c \ - slab-mate-util.c \ - slab-section.c \ - themed-icon.c \ - themed-icon.h \ - tile-action.c \ - tile.c - -libmate_slab_includedir = $(includedir)/libmate-slab -libmate_slab_include_HEADERS = $(HEADER_FILES) -libmate_slab_la_LIBADD = $(LIBSLAB_LIBS) - -MARSHAL_GENERATED = nld-marshal.c nld-marshal.h - -nld-marshal.h: nld-marshal.list - ( @GLIB_GENMARSHAL@ --prefix=nld_marshal $(srcdir)/nld-marshal.list --header > nld-marshal.tmp \ - && mv nld-marshal.tmp nld-marshal.h ) \ - || ( rm -f nld-marshal.tmp && exit 1 ) - -nld-marshal.c: nld-marshal.h - ( (echo '#include "nld-marshal.h"'; @GLIB_GENMARSHAL@ --prefix=nld_marshal $(srcdir)/nld-marshal.list --body) > nld-marshal.tmp \ - && mv nld-marshal.tmp nld-marshal.c ) \ - || ( rm -f nld-marshal.tmp && exit 1 ) - - -BUILT_SOURCES = $(MARSHAL_GENERATED) - -CLEANFILES = $(MARSHAL_GENERATED) - -EXTRA_DIST = nld-marshal.list - --include $(top_srcdir)/git.mk diff --git a/libslab/app-resizer.c b/libslab/app-resizer.c deleted file mode 100644 index 0e1a15b8..00000000 --- a/libslab/app-resizer.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include "app-shell.h" -#include "app-resizer.h" - -static void app_resizer_size_allocate (GtkWidget * resizer, GtkAllocation * allocation); -static gboolean app_resizer_paint_window (GtkWidget * widget, cairo_t * cr, AppShellData * app_data); - -G_DEFINE_TYPE (AppResizer, app_resizer, GTK_TYPE_LAYOUT); - -static void -app_resizer_class_init (AppResizerClass * klass) -{ - GtkWidgetClass *widget_class; - - widget_class = GTK_WIDGET_CLASS (klass); - widget_class->size_allocate = app_resizer_size_allocate; -} - -static void -app_resizer_init (AppResizer * window) -{ - gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), - GTK_STYLE_CLASS_VIEW); -} - -void -remove_container_entries (GtkContainer * widget) -{ - GList *children, *l; - - children = gtk_container_get_children (widget); - for (l = children; l; l = l->next) - { - GtkWidget *child = GTK_WIDGET (l->data); - gtk_container_remove (GTK_CONTAINER (widget), GTK_WIDGET (child)); - } - - if (children) - g_list_free (children); -} - -static void -resize_table (AppResizer *widget, GtkGrid * table, gint columns) -{ - remove_container_entries (GTK_CONTAINER (table)); - widget->column = columns; -} - -static void -relayout_table (AppResizer *widget, GtkGrid * table, GList * element_list) -{ - gint row = 0, col = 0; - do - { - GtkWidget *element = GTK_WIDGET (element_list->data); - gtk_grid_attach (table, element, col, row, 1, 1); - col++; - if (col == widget->column) - { - col = 0; - row++; - } - } - while (NULL != (element_list = g_list_next (element_list))); -} - -void -app_resizer_layout_table_default (AppResizer * widget, GtkGrid * table, GList * element_list) -{ - resize_table (widget, table, widget->cur_num_cols); - relayout_table (widget, table, element_list); -} - -static void -relayout_tables (AppResizer * widget, gint num_cols) -{ - GtkGrid *table; - GList *table_list, *launcher_list; - - for (table_list = widget->cached_tables_list; table_list != NULL; - table_list = g_list_next (table_list)) - { - table = GTK_GRID (table_list->data); - launcher_list = gtk_container_get_children (GTK_CONTAINER (table)); - launcher_list = g_list_reverse (launcher_list); /* Fixme - ugly hack because table stores prepend */ - resize_table (widget, table, num_cols); - relayout_table (widget, table, launcher_list); - g_list_free (launcher_list); - } -} - -static gint -calculate_num_cols (AppResizer * resizer, gint avail_width) -{ - if (resizer->table_elements_homogeneous) - { - gint num_cols; - - if (resizer->cached_element_width == -1) - { - GtkGrid *table = GTK_GRID (resizer->cached_tables_list->data); - GList *children = gtk_container_get_children (GTK_CONTAINER (table)); - GtkWidget *table_element = GTK_WIDGET (children->data); - gint natural_width; - g_list_free (children); - - gtk_widget_get_preferred_width (table_element, NULL, &natural_width); - resizer->cached_element_width = natural_width; - resizer->cached_table_spacing = gtk_grid_get_column_spacing (table); - } - - num_cols = - (avail_width + - resizer->cached_table_spacing) / (resizer->cached_element_width + - resizer->cached_table_spacing); - return num_cols; - } - else - g_assert_not_reached (); /* Fixme - implement... */ -} - -static gint -relayout_tables_if_needed (AppResizer * widget, gint avail_width, gint current_num_cols) -{ - gint num_cols = calculate_num_cols (widget, avail_width); - if (num_cols < 1) - { - num_cols = 1; /* just horiz scroll if avail_width is less than one column */ - } - - if (current_num_cols != num_cols) - { - relayout_tables (widget, num_cols); - current_num_cols = num_cols; - } - return current_num_cols; -} - -void -app_resizer_set_table_cache (AppResizer * widget, GList * cache_list) -{ - widget->cached_tables_list = cache_list; -} - -static void -app_resizer_size_allocate (GtkWidget * widget, GtkAllocation * allocation) -{ - AppResizer *resizer = APP_RESIZER (widget); - GtkWidget *child = GTK_WIDGET (APP_RESIZER (resizer)->child); - GtkAllocation widget_allocation; - GtkRequisition child_requisition; - - static gboolean first_time = TRUE; - gint new_num_cols; - - if (first_time) - { - /* we are letting the first show be the "natural" size of the child widget so do nothing. */ - if (GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) - (*GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) (widget, allocation); - - first_time = FALSE; - gtk_widget_get_allocation (child, &widget_allocation); - gtk_layout_set_size (GTK_LAYOUT (resizer), widget_allocation.width, - widget_allocation.height); - return; - } - - gtk_widget_get_preferred_size (child, &child_requisition, NULL); - - if (!resizer->cached_tables_list) /* if everthing is currently filtered out - just return */ - { - GtkAllocation child_allocation; - - if (GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) - (*GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) (widget, allocation); - - /* We want the message to center itself and only scroll if it's bigger than the available real size. */ - child_allocation.x = 0; - child_allocation.y = 0; - child_allocation.width = MAX (allocation->width, child_requisition.width); - child_allocation.height = MAX (allocation->height, child_requisition.height); - - gtk_widget_size_allocate (child, &child_allocation); - gtk_layout_set_size (GTK_LAYOUT (resizer), child_allocation.width, - child_allocation.height); - return; - } - GtkRequisition other_requisiton; - gtk_widget_get_preferred_size (GTK_WIDGET (resizer->cached_tables_list->data), &other_requisiton, NULL); - - new_num_cols = - relayout_tables_if_needed (APP_RESIZER (resizer), allocation->width, - resizer->cur_num_cols); - if (resizer->cur_num_cols != new_num_cols) - { - GtkRequisition req; - - /* Have to do this so that it requests, and thus gets allocated, new amount */ - gtk_widget_get_preferred_size (child, &req, NULL); - - resizer->cur_num_cols = new_num_cols; - } - - if (GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) - (*GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) (widget, allocation); - gtk_widget_get_allocation (child, &widget_allocation); - gtk_layout_set_size (GTK_LAYOUT (resizer), widget_allocation.width, - widget_allocation.height); -} - -GtkWidget * -app_resizer_new (GtkBox * child, gint initial_num_columns, gboolean homogeneous, - AppShellData * app_data) -{ - AppResizer *widget; - - g_assert (child != NULL); - - widget = g_object_new (APP_RESIZER_TYPE, NULL); - widget->cached_element_width = -1; - widget->cur_num_cols = initial_num_columns; - widget->table_elements_homogeneous = homogeneous; - widget->setting_style = FALSE; - widget->app_data = app_data; - - g_signal_connect (widget, "draw", - G_CALLBACK (app_resizer_paint_window), - app_data); - - gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (child)); - widget->child = child; - - return GTK_WIDGET (widget); -} - -void -app_resizer_set_vadjustment_value (GtkWidget * widget, gdouble value) -{ - GtkAdjustment *adjust; - - adjust = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (widget)); - - gdouble upper = gtk_adjustment_get_upper (adjust); - gdouble page_size = gtk_adjustment_get_page_size (adjust); - if (value > upper - page_size) - { - value = upper - page_size; - } - gtk_adjustment_set_value (adjust, value); -} - -static gboolean -app_resizer_paint_window (GtkWidget * widget, cairo_t * cr, AppShellData * app_data) -{ - cairo_save(cr); - GtkStyleContext *context; - GdkRGBA *bg_rgba = NULL; - - GtkAllocation widget_allocation; - gtk_widget_get_allocation (widget, &widget_allocation); - - context = gtk_widget_get_style_context (widget); - gtk_style_context_get (context, - GTK_STATE_FLAG_NORMAL, - "background-color", &bg_rgba, - NULL); - - gdk_cairo_set_source_rgba (cr, bg_rgba); - cairo_set_line_width(cr, 1); - - cairo_rectangle(cr, widget_allocation.x, widget_allocation.y, widget_allocation.width, widget_allocation.height); - cairo_stroke_preserve(cr); - cairo_fill(cr); - - if (app_data->selected_group) - { - GtkWidget *selected_widget = GTK_WIDGET (app_data->selected_group); - GdkRGBA *rgba; - GtkAllocation selected_widget_allocation; - gtk_widget_get_allocation (selected_widget, &selected_widget_allocation); - - gtk_style_context_get (context, - GTK_STATE_FLAG_PRELIGHT, - "background-color", &rgba, - NULL); - - gdk_cairo_set_source_rgba (cr, rgba); - cairo_set_line_width(cr, 1); - cairo_rectangle(cr, selected_widget_allocation.x, selected_widget_allocation.y, selected_widget_allocation.width, selected_widget_allocation.height); - cairo_stroke_preserve(cr); - cairo_fill(cr); - gdk_rgba_free (rgba); - } - - cairo_restore(cr); - gdk_rgba_free (bg_rgba); - - return FALSE; -} diff --git a/libslab/app-resizer.h b/libslab/app-resizer.h deleted file mode 100644 index 1c65f533..00000000 --- a/libslab/app-resizer.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __APP_RESIZER_H__ -#define __APP_RESIZER_H__ - -#include -#include - -#include "app-shell.h" - -G_BEGIN_DECLS - -#define INITIAL_NUM_COLS 3 -#define APP_RESIZER_TYPE (app_resizer_get_type ()) -#define APP_RESIZER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), APP_RESIZER_TYPE, AppResizer)) -#define APP_RESIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), APP_RESIZER_TYPE, AppResizerClass)) -#define IS_APP_RESIZER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), APP_RESIZER_TYPE)) -#define IS_APP_RESIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_RESIZER_TYPE)) -#define APP_RESIZER_GET_CLASS(obj) (G_TYPE_CHECK_GET_CLASS ((obj), APP_RESIZER_TYPE, AppResizerClass)) - -typedef struct _AppResizer AppResizer; -typedef struct _AppResizerClass AppResizerClass; - -struct _AppResizer -{ - GtkLayout parent; - - GtkBox *child; - GList *cached_tables_list; - gint cached_element_width; - gint cached_table_spacing; - gboolean table_elements_homogeneous; - gint cur_num_cols; - gboolean setting_style; - - guint column; - AppShellData *app_data; -}; - -struct _AppResizerClass -{ - GtkLayoutClass parent_class; -}; - -void remove_container_entries (GtkContainer * widget); - -GType app_resizer_get_type (void); -GtkWidget *app_resizer_new (GtkBox * child, gint initial_num_columns, gboolean homogeneous, - AppShellData * app_data); -void app_resizer_set_table_cache (AppResizer * widget, GList * cache_list); -void app_resizer_layout_table_default (AppResizer * widget, GtkGrid * table, GList * element_list); -void app_resizer_set_vadjustment_value (GtkWidget * widget, gdouble value); - -G_END_DECLS - -#endif /* __APP_RESIZER_H__ */ diff --git a/libslab/app-shell.c b/libslab/app-shell.c deleted file mode 100644 index 0e681c2e..00000000 --- a/libslab/app-shell.c +++ /dev/null @@ -1,1448 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "app-shell.h" -#include "shell-window.h" -#include "app-resizer.h" -#include "slab-section.h" -#include "slab-mate-util.h" -#include "search-bar.h" - -#include "application-tile.h" -#include "themed-icon.h" - -#define TILE_EXEC_NAME "Tile_desktop_exec_name" -#define CC_SCHEMA "org.mate.control-center" -#define EXIT_SHELL_ON_ACTION_START "cc-exit-shell-on-action-start" -#define EXIT_SHELL_ON_ACTION_HELP "cc-exit-shell-on-action-help" -#define EXIT_SHELL_ON_ACTION_ADD_REMOVE "cc-exit-shell-on-action-add-remove" -#define EXIT_SHELL_ON_ACTION_UPGRADE_UNINSTALL "cc-exit-shell-on-action-upgrade-uninstall" - -static void create_application_category_sections (AppShellData * app_data); -static GtkWidget *create_filter_section (AppShellData * app_data, const gchar * title); -static GtkWidget *create_groups_section (AppShellData * app_data, const gchar * title); -static GtkWidget *create_actions_section (AppShellData * app_data, const gchar * title, - void (*actions_handler) (Tile *, TileEvent *, gpointer)); - -static void generate_category (const char * category, MateMenuTreeDirectory * root_dir, AppShellData * app_data, gboolean recursive); -static void generate_launchers (MateMenuTreeDirectory * root_dir, AppShellData * app_data, - CategoryData * cat_data, gboolean recursive); -static void generate_new_apps (AppShellData * app_data); -static void insert_launcher_into_category (CategoryData * cat_data, MateDesktopItem * desktop_item, - AppShellData * app_data); - -static gboolean main_keypress_callback (GtkWidget * widget, GdkEventKey * event, - AppShellData * app_data); -static gboolean main_delete_callback (GtkWidget * widget, GdkEvent * event, - AppShellData * app_data); -static void application_launcher_clear_search_bar (AppShellData * app_data); -static void launch_selected_app (AppShellData * app_data); -static void generate_potential_apps (gpointer catdata, gpointer user_data); - -static void relayout_shell (AppShellData * app_data); -static gboolean handle_filter_changed (NldSearchBar * search_bar, const char *text, - gpointer user_data); -static void handle_group_clicked (Tile * tile, TileEvent * event, gpointer user_data); -static void set_state (AppShellData * app_data, GtkWidget * widget); -static void populate_groups_section (AppShellData * app_data); -static void generate_filtered_lists (gpointer catdata, gpointer user_data); -static void show_no_results_message (AppShellData * app_data, GtkWidget * containing_vbox); -static void populate_application_category_sections (AppShellData * app_data, - GtkWidget * containing_vbox); -static void populate_application_category_section (AppShellData * app_data, SlabSection * section, - GList * launcher_list); -static void tile_activated_cb (Tile * tile, TileEvent * event, gpointer user_data); -static void handle_launcher_single_clicked (Tile * launcher, gpointer data); -static void handle_menu_action_performed (Tile * launcher, TileEvent * event, TileAction * action, - gpointer data); -static gint application_launcher_compare (gconstpointer a, gconstpointer b); -static void matemenu_tree_changed_callback (MateMenuTree * tree, gpointer user_data); -gboolean regenerate_categories (AppShellData * app_data); - -void -hide_shell (AppShellData * app_data) -{ - gtk_window_get_position (GTK_WINDOW (app_data->main_app), - &app_data->main_app_window_x, &app_data->main_app_window_y); - /* clear the search bar now so reshowing is fast and flicker free - BNC#283186 */ - application_launcher_clear_search_bar (app_data); - gtk_widget_hide (app_data->main_app); -} - -void -show_shell (AppShellData * app_data) -{ - gtk_widget_show_all (app_data->main_app); - if (!app_data->static_actions) - gtk_widget_hide (app_data->actions_section); /* don't show unless a launcher is selected */ - - if (app_data->main_app_window_shown_once) - gtk_window_move (GTK_WINDOW (app_data->main_app), - app_data->main_app_window_x, app_data->main_app_window_y); - - /* if this is the first time shown, need to clear this handler */ - else - shell_window_clear_resize_handler (SHELL_WINDOW (app_data->shell)); - app_data->main_app_window_shown_once = TRUE; -} - -gboolean -create_main_window (AppShellData * app_data, const gchar * app_name, const gchar * title, - const gchar * window_icon, gint width, gint height, gboolean hidden) -{ - GtkWidget *main_app = gtk_window_new (GTK_WINDOW_TOPLEVEL); - app_data->main_app = main_app; - gtk_widget_set_name (main_app, app_name); - gtk_window_set_title (GTK_WINDOW (main_app), title); - gtk_window_set_default_size(GTK_WINDOW(main_app), width, height); - gtk_window_set_icon_name (GTK_WINDOW (main_app), window_icon); - gtk_container_add (GTK_CONTAINER (main_app), app_data->shell); - - g_signal_connect (main_app, "delete-event", G_CALLBACK (main_delete_callback), app_data); - g_signal_connect (main_app, "key-press-event", G_CALLBACK (main_keypress_callback), - app_data); - - gtk_window_set_position (GTK_WINDOW (app_data->main_app), GTK_WIN_POS_CENTER); - if (!hidden) - show_shell (app_data); - - return TRUE; -} - -static void -generate_potential_apps (gpointer catdata, gpointer user_data) -{ - GHashTable *app_hash = (GHashTable *) user_data; - CategoryData *data = (CategoryData *) catdata; - gchar *uri; - - GList *launcher_list = data->filtered_launcher_list; - - while (launcher_list) - { - g_object_get (launcher_list->data, "tile-uri", &uri, NULL); - /* eliminate dups of same app in multiple categories */ - if (!g_hash_table_lookup (app_hash, uri)) - g_hash_table_insert (app_hash, uri, launcher_list->data); - else - g_free (uri); - launcher_list = g_list_next (launcher_list); - } -} - -static gboolean -return_first_entry (gpointer key, gpointer value, gpointer unused) -{ - return TRUE; /*better way to pull an entry out ? */ -} - -static void -launch_selected_app (AppShellData * app_data) -{ - GHashTable *app_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - guint num_apps; - - g_list_foreach (app_data->categories_list, generate_potential_apps, app_hash); - num_apps = g_hash_table_size (app_hash); - if (num_apps == 1) - { - ApplicationTile *launcher = - APPLICATION_TILE (g_hash_table_find (app_hash, return_first_entry, NULL)); - g_hash_table_destroy (app_hash); - handle_launcher_single_clicked (TILE (launcher), app_data); - return; - } - - g_hash_table_destroy (app_hash); -} - -static gboolean -main_keypress_callback (GtkWidget * widget, GdkEventKey * event, AppShellData * app_data) -{ - GApplication *app; - - if (event->keyval == GDK_KEY_Return) - { - SlabSection *section = SLAB_SECTION (app_data->filter_section); - NldSearchBar *search_bar; - - /* Make sure our implementation has not changed */ - g_assert (NLD_IS_SEARCH_BAR (section->contents)); - search_bar = NLD_SEARCH_BAR (section->contents); - if (nld_search_bar_has_focus (search_bar)) - { - launch_selected_app (app_data); - return TRUE; - } - } - - /* quit on ESC or Ctl-W or Ctl-Q */ - if (event->keyval == GDK_KEY_Escape || - ((event->keyval == GDK_KEY_w || event->keyval == GDK_KEY_W) && (event->state & GDK_CONTROL_MASK)) || - ((event->keyval == GDK_KEY_q || event->keyval == GDK_KEY_Q) && (event->state & GDK_CONTROL_MASK))) - { - if (app_data->exit_on_close) - { - app=g_application_get_default(); - g_application_quit(app); - } - else - hide_shell (app_data); - - return TRUE; - } - return FALSE; -} - -static gboolean -main_delete_callback (GtkWidget * widget, GdkEvent * event, AppShellData * app_data) -{ - GApplication *app; - - if (app_data->exit_on_close) - { - app=g_application_get_default(); - g_application_quit(app); - return FALSE; - } - - hide_shell (app_data); - return TRUE; /* stop the processing of this event */ -} - -void -layout_shell (AppShellData * app_data, const gchar * filter_title, const gchar * groups_title, - const gchar * actions_title, GSList * actions, - void (*actions_handler) (Tile *, TileEvent *, gpointer)) -{ - GtkWidget *filter_section; - GtkWidget *groups_section; - GtkWidget *actions_section; - - GtkWidget *left_vbox; - GtkWidget *right_vbox; - gint num_cols; - - GtkWidget *sw; - GtkAdjustment *adjustment; - - app_data->shell = shell_window_new (app_data); - app_data->static_actions = actions; - - right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - - num_cols = SIZING_SCREEN_WIDTH_LARGE_NUMCOLS; - - GdkRectangle geometry = {0}; - - GdkDisplay *display; - GdkMonitor *monitor; - - display= gdk_screen_get_display (gdk_screen_get_default ()); - monitor = gdk_display_get_monitor (display, 0); - gdk_monitor_get_geometry (monitor, &geometry); - - if (geometry.width <= SIZING_SCREEN_WIDTH_LARGE) - { - if (geometry.width <= SIZING_SCREEN_WIDTH_MEDIUM) - num_cols = SIZING_SCREEN_WIDTH_SMALL_NUMCOLS; - else - num_cols = SIZING_SCREEN_WIDTH_MEDIUM_NUMCOLS; - } - app_data->category_layout = - app_resizer_new (GTK_BOX (right_vbox), num_cols, TRUE, app_data); - - sw = gtk_scrolled_window_new (NULL, NULL); - gtk_widget_set_vexpand (GTK_WIDGET (sw), TRUE); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); - gtk_container_add (GTK_CONTAINER (sw), app_data->category_layout); - adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw)); - g_object_set (adjustment, "step-increment", (double) 20, NULL); - - create_application_category_sections (app_data); - populate_application_category_sections (app_data, right_vbox); - app_resizer_set_table_cache (APP_RESIZER (app_data->category_layout), - app_data->cached_tables_list); - - gtk_container_set_focus_vadjustment (GTK_CONTAINER (right_vbox), - gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw))); - - left_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 15); - - filter_section = create_filter_section (app_data, filter_title); - app_data->filter_section = filter_section; - gtk_box_pack_start (GTK_BOX (left_vbox), filter_section, FALSE, FALSE, 0); - - groups_section = create_groups_section (app_data, groups_title); - app_data->groups_section = groups_section; - populate_groups_section (app_data); - gtk_box_pack_start (GTK_BOX (left_vbox), groups_section, FALSE, FALSE, 0); - - actions_section = create_actions_section (app_data, actions_title, actions_handler); - app_data->actions_section = actions_section; - gtk_box_pack_start (GTK_BOX (left_vbox), actions_section, FALSE, FALSE, 0); - - shell_window_set_contents (SHELL_WINDOW (app_data->shell), left_vbox, sw); -} - -static gboolean -relayout_shell_partial (gpointer user_data) -{ - AppShellData *app_data = (AppShellData *) user_data; - GtkBox *vbox = APP_RESIZER (app_data->category_layout)->child; - CategoryData *data; - - if (app_data->stop_incremental_relayout) - return FALSE; - - if (app_data->incremental_relayout_cat_list != NULL) - { - /* There are still categories to layout */ - data = (CategoryData *) app_data->incremental_relayout_cat_list->data; - if (data->filtered_launcher_list != NULL) - { - populate_application_category_section (app_data, data->section, - data->filtered_launcher_list); - gtk_box_pack_start (vbox, GTK_WIDGET (data->section), TRUE, TRUE, - 0); - app_data->filtered_out_everything = FALSE; - } - - app_data->incremental_relayout_cat_list = - g_list_next (app_data->incremental_relayout_cat_list); - return TRUE; - } - - /* We're done laying out the categories; finish up */ - if (app_data->filtered_out_everything) - show_no_results_message (app_data, GTK_WIDGET (vbox)); - - app_resizer_set_table_cache (APP_RESIZER (app_data->category_layout), - app_data->cached_tables_list); - populate_groups_section (app_data); - - gtk_widget_show_all (app_data->category_layout); - gdk_window_set_cursor (gtk_widget_get_window (app_data->shell), NULL); - - app_data->stop_incremental_relayout = TRUE; - return FALSE; -} - -static void -relayout_shell_incremental (AppShellData * app_data) -{ - GtkBox *vbox = APP_RESIZER (app_data->category_layout)->child; - - app_data->stop_incremental_relayout = FALSE; - app_data->filtered_out_everything = TRUE; - app_data->incremental_relayout_cat_list = app_data->categories_list; - - if (app_data->cached_tables_list) - g_list_free (app_data->cached_tables_list); - app_data->cached_tables_list = NULL; - - remove_container_entries (GTK_CONTAINER (vbox)); - - g_idle_add ((GSourceFunc) relayout_shell_partial, app_data); -} - -static void -relayout_shell (AppShellData * app_data) -{ - GtkWidget *shell = app_data->shell; - GtkBox *vbox = APP_RESIZER (app_data->category_layout)->child; - - populate_application_category_sections (app_data, GTK_WIDGET (vbox)); - app_resizer_set_table_cache (APP_RESIZER (app_data->category_layout), - app_data->cached_tables_list); - populate_groups_section (app_data); - - gtk_widget_show_all (shell); - if (!app_data->static_actions && !app_data->last_clicked_launcher) - gtk_widget_hide (app_data->actions_section); /* don't show unless a launcher is selected */ -} - -static GtkWidget * -create_actions_section (AppShellData * app_data, const gchar * title, - void (*actions_handler) (Tile *, TileEvent *, gpointer)) -{ - GtkWidget *section, *launcher; - GtkWidget *vbox; - GSList *actions; - AppAction *action; - AtkObject *a11y_cat; - - g_assert (app_data != NULL); - - section = slab_section_new (title, Style1); - g_object_ref (section); - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - slab_section_set_contents (SLAB_SECTION (section), vbox); - - if (app_data->static_actions) - { - for (actions = app_data->static_actions; actions; actions = actions->next) - { - GtkWidget *header; - - action = (AppAction *) actions->data; - header = gtk_label_new (action->name); - gtk_label_set_line_wrap (GTK_LABEL (header), TRUE); - gtk_label_set_max_width_chars (GTK_LABEL (header), 0); - gtk_label_set_xalign (GTK_LABEL (header), 0.0); - launcher = nameplate_tile_new (NULL, NULL, header, NULL); - - g_object_set_data (G_OBJECT (launcher), APP_ACTION_KEY, action->item); - g_signal_connect (launcher, "tile-activated", G_CALLBACK (actions_handler), - app_data); - gtk_box_pack_start (GTK_BOX (vbox), launcher, FALSE, FALSE, 0); - - a11y_cat = gtk_widget_get_accessible (GTK_WIDGET (launcher)); - atk_object_set_name (a11y_cat, action->name); - } - } - - return section; -} - -static GtkWidget * -create_groups_section (AppShellData * app_data, const gchar * title) -{ - GtkWidget *section; - GtkWidget *vbox; - - g_assert (app_data != NULL); - - section = slab_section_new (title, Style1); - g_object_ref (section); - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - slab_section_set_contents (SLAB_SECTION (section), vbox); - - return section; -} - -static void -populate_groups_section (AppShellData * app_data) -{ - SlabSection *section = SLAB_SECTION (app_data->groups_section); - GtkBox *vbox; - GList *cat_list; - - vbox = GTK_BOX (section->contents); - remove_container_entries (GTK_CONTAINER (vbox)); - - cat_list = app_data->categories_list; - do - { - CategoryData *data = (CategoryData *) cat_list->data; - if (NULL != data->filtered_launcher_list) - { - gtk_widget_set_state_flags (GTK_WIDGET (data->group_launcher), GTK_STATE_FLAG_NORMAL, FALSE); - gtk_box_pack_start (vbox, GTK_WIDGET (data->group_launcher), - FALSE, FALSE, 0); - } - } - while (NULL != (cat_list = g_list_next (cat_list))); -} - -static void -handle_group_clicked (Tile * tile, TileEvent * event, gpointer user_data) -{ - AppShellData *app_data = (AppShellData *) user_data; - GtkWidget *section = NULL; - GtkAllocation allocation; - - gint clicked_pos = - GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tile), GROUP_POSITION_NUMBER_KEY)); - - GList *cat_list = app_data->categories_list; - - gint total = 0; - do - { - CategoryData *cat_data = (CategoryData *) cat_list->data; - gint pos = - GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cat_data->group_launcher), - GROUP_POSITION_NUMBER_KEY)); - if (pos == clicked_pos) - { - section = GTK_WIDGET (cat_data->section); - break; - } - - if (NULL != cat_data->filtered_launcher_list) - { - gtk_widget_get_allocation (GTK_WIDGET (cat_data->section), &allocation); - total += allocation.height; - } - } - while (NULL != (cat_list = g_list_next (cat_list))); - - g_assert (section != NULL); - set_state (app_data, section); - - app_resizer_set_vadjustment_value (app_data->category_layout, total); -} - -static void -set_state (AppShellData * app_data, GtkWidget * widget) -{ - if (app_data->selected_group) - { - slab_section_set_selected (app_data->selected_group, FALSE); - app_data->selected_group = NULL; - } - - if (widget) - { - app_data->selected_group = SLAB_SECTION (widget); - slab_section_set_selected (SLAB_SECTION (widget), TRUE); - } - gtk_widget_queue_draw (app_data->shell); -} - -static GtkWidget * -create_filter_section (AppShellData * app_data, const gchar * title) -{ - GtkWidget *section; - - GtkWidget *search_bar; - - section = slab_section_new (title, Style1); - g_object_ref (section); - - search_bar = nld_search_bar_new (); - nld_search_bar_set_search_timeout (NLD_SEARCH_BAR (search_bar), 0); - slab_section_set_contents (SLAB_SECTION (section), search_bar); - - g_signal_connect (search_bar, "search", - G_CALLBACK (handle_filter_changed), - app_data); - - return section; -} - -static gboolean -handle_filter_changed_delayed (gpointer user_data) -{ - AppShellData *app_data = (AppShellData *) user_data; - - g_list_foreach (app_data->categories_list, generate_filtered_lists, - (gpointer) app_data->filter_string); - app_data->last_clicked_launcher = NULL; - - /* showing the updates incremtally is very visually distracting. Much worse than just blanking until - the incremental work is done and then doing one show. It would be nice to optimize this though - somehow and not even show any change but the cursor change until all the work is done. But since - we do the work incrementally in an idle loop I don't know how else besides hiding to not show - incremental updates - */ - /* gdk_window_freeze_updates(app_data->category_layout->window); */ - gtk_widget_hide (app_data->category_layout); - app_data->busy_cursor = - gdk_cursor_new_for_display (gtk_widget_get_display (app_data->shell), GDK_WATCH); - gdk_window_set_cursor (gtk_widget_get_window (app_data->shell), app_data->busy_cursor); - g_object_unref (app_data->busy_cursor); - - set_state (app_data, NULL); - app_resizer_set_vadjustment_value (app_data->category_layout, 0); - - relayout_shell_incremental (app_data); - - app_data->filter_changed_timeout = 0; - return FALSE; -} - -static gboolean -handle_filter_changed (NldSearchBar * search_bar, const char *text, gpointer data) -{ - AppShellData *app_data; - - app_data = (AppShellData *) data; - - if (app_data->filter_string) - g_free (app_data->filter_string); - app_data->filter_string = g_strdup (text); - - if (app_data->filter_changed_timeout) - g_source_remove (app_data->filter_changed_timeout); - - app_data->filter_changed_timeout = - g_timeout_add (75, handle_filter_changed_delayed, app_data); - app_data->stop_incremental_relayout = TRUE; - - return FALSE; -} - -static void -generate_filtered_lists (gpointer catdata, gpointer user_data) -{ - CategoryData *data = (CategoryData *) catdata; - - /* Fixme - everywhere you use ascii you need to fix up for multibyte */ - gchar *filter_string = g_ascii_strdown (user_data, -1); - gchar *temp1, *temp2; - GList *launcher_list = data->launcher_list; - - g_list_free (data->filtered_launcher_list); - data->filtered_launcher_list = NULL; - - do - { - ApplicationTile *launcher = APPLICATION_TILE (launcher_list->data); - const gchar *filename; - - temp1 = NULL; - temp2 = NULL; - - /* Since the filter may remove this entry from the - container it will not get a mouse out event */ - gtk_widget_set_state_flags (GTK_WIDGET (launcher), GTK_STATE_FLAG_NORMAL, FALSE); - filename = g_object_get_data (G_OBJECT (launcher), TILE_EXEC_NAME); /* do I need to free this */ - - temp1 = g_ascii_strdown (launcher->name, -1); - if (launcher->description) - temp2 = g_ascii_strdown (launcher->description, -1); - if (g_strrstr (temp1, filter_string) || (launcher->description - && g_strrstr (temp2, filter_string)) - || g_strrstr (filename, filter_string)) - { - data->filtered_launcher_list = - g_list_append (data->filtered_launcher_list, launcher); - } - if (temp1) - g_free (temp1); - if (temp2) - g_free (temp2); - } - while (NULL != (launcher_list = g_list_next (launcher_list))); - g_free (filter_string); -} - -static void -delete_old_data (AppShellData * app_data) -{ - GList *temp; - GList *cat_list; - - g_assert (app_data != NULL); - g_assert (app_data->categories_list != NULL); - - cat_list = app_data->categories_list; - - do - { - CategoryData *data = (CategoryData *) cat_list->data; - gtk_widget_destroy (GTK_WIDGET (data->section)); - gtk_widget_destroy (GTK_WIDGET (data->group_launcher)); - g_object_unref (data->section); - g_object_unref (data->group_launcher); - g_free (data->category); - - for (temp = data->launcher_list; temp; temp = g_list_next (temp)) - { - g_free (g_object_get_data (G_OBJECT (temp->data), TILE_EXEC_NAME)); - g_object_unref (temp->data); - } - - g_list_free (data->launcher_list); - g_list_free (data->filtered_launcher_list); - g_free (data); - } - while (NULL != (cat_list = g_list_next (cat_list))); - - g_list_free (app_data->categories_list); - app_data->categories_list = NULL; - app_data->selected_group = NULL; -} - -static void -create_application_category_sections (AppShellData * app_data) -{ - GList *cat_list; - AtkObject *a11y_cat; - gint pos = 0; - - g_assert (app_data != NULL); - g_assert (app_data->categories_list != NULL); /* Fixme - pop up a dialog box and then close */ - - cat_list = app_data->categories_list; - - do - { - CategoryData *data = (CategoryData *) cat_list->data; - GtkWidget *header = gtk_label_new (data->category); - gchar *markup; - GtkWidget *hbox; - GtkWidget *table; - - gtk_label_set_xalign (GTK_LABEL (header), 0.0); - data->group_launcher = TILE (nameplate_tile_new (NULL, NULL, header, NULL)); - g_object_ref (data->group_launcher); - - g_object_set_data (G_OBJECT (data->group_launcher), GROUP_POSITION_NUMBER_KEY, - GINT_TO_POINTER (pos)); - pos++; - g_signal_connect (data->group_launcher, "tile-activated", - G_CALLBACK (handle_group_clicked), app_data); - a11y_cat = gtk_widget_get_accessible (GTK_WIDGET (data->group_launcher)); - atk_object_set_name (a11y_cat, data->category); - - markup = g_markup_printf_escaped ("%s", - data->category); - data->section = SLAB_SECTION (slab_section_new_with_markup (markup, Style2)); - - /* as we filter these will be added/removed from parent container and we dont want them destroyed */ - g_object_ref (data->section); - g_free (markup); - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - table = gtk_grid_new (); - gtk_grid_set_column_spacing (GTK_GRID (table), 5); - gtk_grid_set_row_spacing (GTK_GRID (table), 5); - gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 15); - slab_section_set_contents (SLAB_SECTION (data->section), hbox); - } - while (NULL != (cat_list = g_list_next (cat_list))); -} - -static void -show_no_results_message (AppShellData * app_data, GtkWidget * containing_vbox) -{ - gchar *markup; - gchar *str1; - gchar *str2; - - if (!app_data->filtered_out_everything_widget) - { - GtkWidget *image; - GtkWidget *label; - - app_data->filtered_out_everything_widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_set_halign (app_data->filtered_out_everything_widget, GTK_ALIGN_CENTER); - gtk_widget_set_valign (app_data->filtered_out_everything_widget, GTK_ALIGN_CENTER); - g_object_ref (app_data->filtered_out_everything_widget); - - image = themed_icon_new ("face-surprise", GTK_ICON_SIZE_DIALOG); - gtk_box_pack_start (GTK_BOX (app_data->filtered_out_everything_widget), image, FALSE, FALSE, 0); - - label = gtk_label_new (NULL); - gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); - gtk_box_pack_start (GTK_BOX (app_data->filtered_out_everything_widget), label, TRUE, TRUE, 15); - app_data->filtered_out_everything_widget_label = GTK_LABEL (label); - } - - str1 = g_markup_printf_escaped ("%s", app_data->filter_string); - str2 = g_strdup_printf (_("Your filter \"%s\" does not match any items."), str1); - markup = g_strdup_printf ("%s\n\n%s", - _("No matches found."), str2); - gtk_label_set_text (app_data->filtered_out_everything_widget_label, markup); - gtk_label_set_use_markup (app_data->filtered_out_everything_widget_label, TRUE); - gtk_box_pack_start (GTK_BOX (containing_vbox), app_data->filtered_out_everything_widget, - TRUE, TRUE, 0); - g_free (str1); - g_free (str2); - g_free (markup); -} - -static void -populate_application_category_sections (AppShellData * app_data, GtkWidget * containing_vbox) -{ - GList *cat_list = app_data->categories_list; - gboolean filtered_out_everything = TRUE; - if (app_data->cached_tables_list) - g_list_free (app_data->cached_tables_list); - app_data->cached_tables_list = NULL; - - remove_container_entries (GTK_CONTAINER (containing_vbox)); - do - { - CategoryData *data = (CategoryData *) cat_list->data; - if (NULL != data->filtered_launcher_list) - { - populate_application_category_section (app_data, data->section, - data->filtered_launcher_list); - gtk_box_pack_start (GTK_BOX (containing_vbox), GTK_WIDGET (data->section), - TRUE, TRUE, 0); - filtered_out_everything = FALSE; - } - } - while (NULL != (cat_list = g_list_next (cat_list))); - - if (TRUE == filtered_out_everything) - show_no_results_message (app_data, containing_vbox); -} - -static void -populate_application_category_section (AppShellData * app_data, SlabSection * section, - GList * launcher_list) -{ - GtkWidget *hbox; - GtkGrid *table; - GList *children; - - hbox = GTK_WIDGET (section->contents); - - children = gtk_container_get_children (GTK_CONTAINER (hbox)); - table = children->data; - g_list_free (children); - - /* Make sure our implementation has not changed and it's still a GtkGrid */ - g_assert (GTK_IS_GRID (table)); - - app_data->cached_tables_list = g_list_append (app_data->cached_tables_list, table); - - app_resizer_layout_table_default (APP_RESIZER (app_data->category_layout), table, - launcher_list); - -} - -gboolean -regenerate_categories (AppShellData * app_data) -{ - delete_old_data (app_data); - generate_categories (app_data); - create_application_category_sections (app_data); - relayout_shell (app_data); - - return FALSE; /* remove this function from the list */ -} - -static void -matemenu_tree_changed_callback (MateMenuTree * old_tree, gpointer user_data) -{ - /* - This method only gets called on the first change (matemenu appears to ignore subsequent) until - we reget the root dir which we can't do in this method because if we do for some reason this - method then gets called multiple times for one actual change. This actually is okay because - it's probably a good idea to wait a couple seconds to regenerate the categories in case there - are multiple quick changes being made, no sense regenerating multiple times. - */ - GError *error = NULL; - AppShellData * app_data = user_data; - if (!matemenu_tree_load_sync (app_data->tree, &error)) { - g_warning ("Menu tree loading got error:%s\n", error->message); - g_object_unref (app_data->tree); - app_data->tree = NULL; - g_error_free (error); - } else { - g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 3000, (GSourceFunc) regenerate_categories, - user_data, NULL); - } -} - -AppShellData * -appshelldata_new (const gchar * menu_name, GtkIconSize icon_size, gboolean show_tile_generic_name, gboolean exit_on_close, gint new_apps_max_items) -{ - AppShellData *app_data = g_new0 (AppShellData, 1); - app_data->settings = g_settings_new (CC_SCHEMA); - app_data->menu_name = menu_name; - app_data->icon_size = icon_size; - app_data->stop_incremental_relayout = TRUE; - app_data->show_tile_generic_name = show_tile_generic_name; - app_data->exit_on_close = exit_on_close; - if (new_apps_max_items > 0) { - app_data->new_apps = g_new0 (NewAppConfig, 1); - app_data->new_apps->max_items = new_apps_max_items; - app_data->new_apps->name = _("New Applications"); - } - return app_data; -} - -void -generate_categories (AppShellData * app_data) -{ - MateMenuTreeDirectory *root_dir; - gboolean need_misc = FALSE; - MateMenuTreeIter *iter; - MateMenuTreeItemType type; - - if (!app_data->tree) - { - GError *error = NULL; - - app_data->tree = matemenu_tree_new (app_data->menu_name, MATEMENU_TREE_FLAGS_NONE); - g_signal_connect (app_data->tree, "changed", G_CALLBACK (matemenu_tree_changed_callback), app_data); - if (! matemenu_tree_load_sync (app_data->tree, &error)) { - g_warning("Menu tree loading got error:%s\n", error->message); - g_error_free(error); - g_object_unref(app_data->tree); - app_data->tree = NULL; - } - } - - if (app_data->tree != NULL) - root_dir = matemenu_tree_get_root_directory (app_data->tree); - else - root_dir = NULL; - - if ( app_data->tree == NULL || root_dir == NULL) { - GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Failure loading - %s", - app_data->menu_name); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - exit (1); /* Fixme - is there a MATE/GTK way to do this. */ - } - - iter = matemenu_tree_directory_iter (root_dir); - while ((type = matemenu_tree_iter_next (iter)) != MATEMENU_TREE_ITEM_INVALID) { - gpointer item; - const char *category; - switch (type) { - case MATEMENU_TREE_ITEM_DIRECTORY: - item = matemenu_tree_iter_get_directory (iter); - category = matemenu_tree_directory_get_name (item); - generate_category(category, item, app_data, TRUE); - matemenu_tree_item_unref (item); - break; - case MATEMENU_TREE_ITEM_ENTRY: - need_misc = TRUE; - break; - default: - break; - } - } - matemenu_tree_iter_unref(iter); - - if (need_misc) - generate_category (_("Other"), root_dir, app_data, FALSE); - - if (app_data->hash) - { - g_hash_table_destroy (app_data->hash); - app_data->hash = NULL; - } - - matemenu_tree_item_unref (root_dir); - - if (app_data->new_apps && (app_data->new_apps->max_items > 0)) - generate_new_apps (app_data); -} - -static void -generate_category (const char * category, MateMenuTreeDirectory * root_dir, AppShellData * app_data, gboolean recursive) -{ - CategoryData *data; - /* This is not needed. MateMenu already returns an ordered, non duplicate list - GList *list_entry; - list_entry = - g_list_find_custom (app_data->categories_list, category, - category_name_compare); - if (!list_entry) - { - */ - data = g_new0 (CategoryData, 1); - data->category = g_strdup (category); - app_data->categories_list = - /* use the matemenu order instead of alphabetical */ - g_list_append (app_data->categories_list, data); - /* g_list_insert_sorted (app_data->categories_list, data, category_data_compare); */ - /* - } - else - { - data = list_entry->data; - } - */ - - if (app_data->hash) /* used to eliminate dups on a per category basis. */ - g_hash_table_destroy (app_data->hash); - app_data->hash = g_hash_table_new (g_str_hash, g_str_equal); - generate_launchers (root_dir, app_data, data, recursive); -} - -static gboolean -check_specific_apps_hack (MateDesktopItem * item) -{ - static const gchar *COMMAND_LINE_LOCKDOWN_SCHEMA = "org.mate.lockdown"; - static const gchar *COMMAND_LINE_LOCKDOWN_KEY = "disable-command-line"; - static const gchar *COMMAND_LINE_LOCKDOWN_DESKTOP_CATEGORY = "TerminalEmulator"; - static gboolean got_lockdown_value = FALSE; - static gboolean command_line_lockdown; - - gchar *path; - const char *exec; - - if (!got_lockdown_value) - { - got_lockdown_value = TRUE; - GSettings *lockdown_settings; - lockdown_settings = g_settings_new (COMMAND_LINE_LOCKDOWN_SCHEMA); - command_line_lockdown = g_settings_get_boolean (lockdown_settings, COMMAND_LINE_LOCKDOWN_KEY); - g_object_unref (lockdown_settings); - } - - /* This seems like an ugly hack but it's the way it's currently done in the old control center */ - exec = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_EXEC); - - /* discard xscreensaver if mate-screensaver is installed */ - if ((exec && !strcmp (exec, "xscreensaver-demo")) - && (path = g_find_program_in_path ("mate-screensaver-preferences"))) - { - g_free (path); - return TRUE; - } - - /* discard gnome-keyring-manager if CASA is installed */ - if ((exec && !strcmp (exec, "gnome-keyring-manager")) - && (path = g_find_program_in_path ("CASAManager.sh"))) - { - g_free (path); - return TRUE; - } - - /* discard terminals if lockdown key is set */ - if (command_line_lockdown) - { - const gchar *categories = - mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_CATEGORIES); - if (g_strrstr (categories, COMMAND_LINE_LOCKDOWN_DESKTOP_CATEGORY)) - { - return TRUE; - } - } - - return FALSE; -} - -static void -generate_launchers (MateMenuTreeDirectory * root_dir, AppShellData * app_data, CategoryData * cat_data, gboolean recursive) -{ - MateDesktopItem *desktop_item; - const gchar *desktop_file; - MateMenuTreeIter *iter; - MateMenuTreeItemType type; - - iter = matemenu_tree_directory_iter (root_dir); - while ((type = matemenu_tree_iter_next (iter)) != MATEMENU_TREE_ITEM_INVALID) { - gpointer item; - switch (type) { - case MATEMENU_TREE_ITEM_DIRECTORY: - item = matemenu_tree_iter_get_directory(iter); - /* g_message ("Found sub-category %s", matemenu_tree_directory_get_name (item)); */ - if (recursive) - generate_launchers (item, app_data, cat_data, TRUE); - matemenu_tree_item_unref (item); - break; - case MATEMENU_TREE_ITEM_ENTRY: - item = matemenu_tree_iter_get_entry(iter); - /* g_message ("Found item name is:%s", matemenu_tree_entry_get_desktop_file_id(item)); */ - desktop_file = matemenu_tree_entry_get_desktop_file_path (item); - if (desktop_file) - { - if (g_hash_table_lookup (app_data->hash, desktop_file)) - { - break; /* duplicate */ - } - /* Fixme - make sure it's safe to store this without duping it. As far as I can tell it is - safe as long as I don't hang on to this anylonger than I hang on to the MateMenuTreeEntry* - which brings up another point - am I supposed to free these or does freeing the top level recurse - */ - g_hash_table_insert (app_data->hash, (gpointer) desktop_file, - (gpointer) desktop_file); - } - desktop_item = mate_desktop_item_new_from_file (desktop_file, 0, NULL); - if (!desktop_item) - { - g_critical ("Failure - mate_desktop_item_new_from_file(%s)", - desktop_file); - break; - } - if (!check_specific_apps_hack (desktop_item)) - insert_launcher_into_category (cat_data, desktop_item, app_data); - mate_desktop_item_unref (desktop_item); - matemenu_tree_item_unref (item); - break; - default: - break; - } - } - matemenu_tree_iter_unref(iter); -} - -static void -generate_new_apps (AppShellData * app_data) -{ - GHashTable *all_apps_cache = NULL; - gchar *all_apps; - GError *error = NULL; - gchar *separator = "\n"; - - gchar *all_apps_file_name; - gchar **all_apps_split; - gint x; - gboolean got_new_apps; - CategoryData *new_apps_category = NULL; - GList *categories, *launchers; - GHashTable *new_apps_dups; - - all_apps_file_name = g_build_filename (g_get_user_config_dir (), "mate", "ab-newapps.txt", NULL); - - if (!g_file_get_contents (all_apps_file_name, &all_apps, NULL, &error)) - { - /* If file does not exist, this is the first time this user has run this, create the baseline file */ - GList *categories, *launchers; - GString *gstr; - gchar *dirname; - - g_error_free (error); - error = NULL; - - /* best initial size determined by running on a couple different platforms */ - gstr = g_string_sized_new (10000); - - for (categories = app_data->categories_list; categories; categories = categories->next) - { - CategoryData *data = categories->data; - for (launchers = data->launcher_list; launchers; launchers = launchers->next) - { - Tile *tile = TILE (launchers->data); - MateDesktopItem *item = - application_tile_get_desktop_item (APPLICATION_TILE (tile)); - const gchar *uri = mate_desktop_item_get_location (item); - g_string_append (gstr, uri); - g_string_append (gstr, separator); - } - } - - dirname = g_path_get_dirname (all_apps_file_name); - g_mkdir_with_parents (dirname, 0700); /* creates if does not exist */ - g_free (dirname); - - if (!g_file_set_contents (all_apps_file_name, gstr->str, -1, &error)) - g_warning ("Error setting all apps file:%s\n", error->message); - - g_string_free (gstr, TRUE); - g_free (all_apps_file_name); - return; - } - - all_apps_cache = g_hash_table_new (g_str_hash, g_str_equal); - all_apps_split = g_strsplit (all_apps, separator, -1); - for (x = 0; all_apps_split[x]; x++) - { - g_hash_table_insert (all_apps_cache, all_apps_split[x], all_apps_split[x]); - } - - got_new_apps = FALSE; - new_apps_dups = g_hash_table_new (g_str_hash, g_str_equal); - for (categories = app_data->categories_list; categories; categories = categories->next) - { - CategoryData *cat_data = categories->data; - for (launchers = cat_data->launcher_list; launchers; launchers = launchers->next) - { - Tile *tile = TILE (launchers->data); - MateDesktopItem *item = - application_tile_get_desktop_item (APPLICATION_TILE (tile)); - const gchar *uri = mate_desktop_item_get_location (item); - if (!g_hash_table_lookup (all_apps_cache, uri)) - { - GFile *file; - GFileInfo *info; - long filetime; - - if (g_hash_table_lookup (new_apps_dups, uri)) - { - /* if a desktop file is in 2 or more top level categories, only show it once */ - break; - } - g_hash_table_insert (new_apps_dups, (gpointer) uri, (gpointer) uri); - - if (!got_new_apps) - { - new_apps_category = g_new0 (CategoryData, 1); - new_apps_category->category = - g_strdup (app_data->new_apps->name); - app_data->new_apps->garray = - g_array_sized_new (FALSE, TRUE, - sizeof (NewAppData *), - app_data->new_apps->max_items); - - /* should not need this, but a bug in glib does not actually clear the elements until you call this method */ - g_array_set_size (app_data->new_apps->garray, app_data->new_apps->max_items); - got_new_apps = TRUE; - } - - file = g_file_new_for_uri (uri); - info = g_file_query_info (file, - G_FILE_ATTRIBUTE_TIME_MODIFIED, - 0, NULL, NULL); - - if (!info) - { - g_object_unref (file); - g_warning ("Cant get vfs info for %s\n", uri); - if (new_apps_category) { - g_free (new_apps_category->category); - g_free (new_apps_category); - } - g_free (all_apps_file_name); - g_strfreev (all_apps_split); - return; - } - filetime = (long) g_file_info_get_attribute_uint64 (info, - G_FILE_ATTRIBUTE_TIME_MODIFIED); - g_object_unref (info); - g_object_unref (file); - - for (x = 0; x < app_data->new_apps->max_items; x++) - { - NewAppData *temp_data = (NewAppData *) - g_array_index (app_data->new_apps->garray, NewAppData *, x); - if (!temp_data || filetime > temp_data->time) /* if this slot is empty or we are newer than this slot */ - { - NewAppData *temp = g_new0 (NewAppData, 1); - temp->time = filetime; - temp->item = item; - g_array_insert_val (app_data->new_apps->garray, x, - temp); - break; - } - } - } - } - } - g_hash_table_destroy (new_apps_dups); - g_hash_table_destroy (all_apps_cache); - - if (got_new_apps) - { - for (x = 0; x < app_data->new_apps->max_items; x++) - { - NewAppData *data = - (NewAppData *) g_array_index (app_data->new_apps->garray, - NewAppData *, x); - if (data) - { - insert_launcher_into_category (new_apps_category, data->item, - app_data); - g_free (data); - } - else - break; - } - app_data->categories_list = - g_list_prepend (app_data->categories_list, new_apps_category); - - g_array_free (app_data->new_apps->garray, TRUE); - } - g_free (all_apps); - g_free (all_apps_file_name); - g_strfreev (all_apps_split); -} - -static void -insert_launcher_into_category (CategoryData * cat_data, MateDesktopItem * desktop_item, - AppShellData * app_data) -{ - GtkWidget *launcher; - static GtkSizeGroup *icon_group = NULL; - - gchar *filepath; - gchar *filename; - GtkWidget *tile_icon; - - if (!icon_group) - icon_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - - launcher = - application_tile_new_full (mate_desktop_item_get_location (desktop_item), - app_data->icon_size, app_data->show_tile_generic_name); - gtk_widget_set_size_request (launcher, SIZING_TILE_WIDTH, -1); - - filepath = - g_strdup (mate_desktop_item_get_string (desktop_item, MATE_DESKTOP_ITEM_EXEC)); - g_strdelimit (filepath, " ", '\0'); /* just want the file name - no args or replacements */ - filename = g_strrstr (filepath, "/"); - if (filename) - g_stpcpy (filepath, filename + 1); - filename = g_ascii_strdown (filepath, -1); - g_free (filepath); - g_object_set_data (G_OBJECT (launcher), TILE_EXEC_NAME, filename); - - tile_icon = NAMEPLATE_TILE (launcher)->image; - gtk_size_group_add_widget (icon_group, tile_icon); - - g_signal_connect (launcher, "tile-activated", G_CALLBACK (tile_activated_cb), app_data); - - /* Note that this will handle the case of the action being launched via the side panel as - well as directly from the context menu of an individual launcher, because they both - funnel through tile_button_action_activate. - */ - g_signal_connect (launcher, "tile-action-triggered", - G_CALLBACK (handle_menu_action_performed), app_data); - - /* These will be inserted/removed from tables as the filter changes and we dont want them */ - /* destroyed when they are removed */ - g_object_ref (launcher); - - /* use alphabetical order instead of the matemenu order. We group all sub items in each top level - category together, ignoring sub menus, so we also ignore sub menu layout hints */ - cat_data->launcher_list = - /* g_list_insert (cat_data->launcher_list, launcher, -1); */ - g_list_insert_sorted (cat_data->launcher_list, launcher, application_launcher_compare); - cat_data->filtered_launcher_list = - /* g_list_insert (cat_data->filtered_launcher_list, launcher, -1); */ - g_list_insert_sorted (cat_data->filtered_launcher_list, launcher, application_launcher_compare); -} - -static gint -application_launcher_compare (gconstpointer a, gconstpointer b) -{ - ApplicationTile *launcher1 = APPLICATION_TILE (a); - ApplicationTile *launcher2 = APPLICATION_TILE (b); - - gchar *val1 = launcher1->name; - gchar *val2 = launcher2->name; - - if (val1 == NULL || val2 == NULL) - { - g_assert_not_reached (); - } - return g_ascii_strcasecmp (val1, val2); -} - -static void -application_launcher_clear_search_bar (AppShellData * app_data) -{ - SlabSection *section = SLAB_SECTION (app_data->filter_section); - NldSearchBar *search_bar; - g_assert (NLD_IS_SEARCH_BAR (section->contents)); - search_bar = NLD_SEARCH_BAR (section->contents); - nld_search_bar_set_text (search_bar, "", TRUE); -} - -/* -static gint -category_name_compare (gconstpointer a, gconstpointer b) -{ - CategoryData *data = (CategoryData *) a; - const gchar *category = b; - - if (category == NULL || data->category == NULL) - { - g_assert_not_reached (); - } - return g_ascii_strcasecmp (category, data->category); -} -*/ - -static void -tile_activated_cb (Tile * tile, TileEvent * event, gpointer user_data) -{ - switch (event->type) - { - case TILE_EVENT_ACTIVATED_SINGLE_CLICK: - case TILE_EVENT_ACTIVATED_KEYBOARD: - handle_launcher_single_clicked (tile, user_data); - break; - default: - break; - } - -} - -static void -handle_launcher_single_clicked (Tile * launcher, gpointer data) -{ - GApplication *app; - AppShellData *app_data = (AppShellData *) data; - - tile_trigger_action (launcher, launcher->actions[APPLICATION_TILE_ACTION_START]); - - if (g_settings_get_boolean (app_data->settings, EXIT_SHELL_ON_ACTION_START)) - { - if (app_data->exit_on_close) - { - app=g_application_get_default(); - g_application_quit(app); - } - else - hide_shell (app_data); - } -} - -static void -handle_menu_action_performed (Tile * launcher, TileEvent * event, TileAction * action, - gpointer data) -{ - GApplication *app; - AppShellData *app_data = (AppShellData *) data; - gchar *temp; - - temp = NULL; - if (action == launcher->actions[APPLICATION_TILE_ACTION_START]) - { - temp = EXIT_SHELL_ON_ACTION_START; - } - - else if (action == launcher->actions[APPLICATION_TILE_ACTION_HELP]) - { - temp = EXIT_SHELL_ON_ACTION_HELP; - } - - else if (action == launcher->actions[APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU] - || action == launcher->actions[APPLICATION_TILE_ACTION_UPDATE_STARTUP]) - { - temp = EXIT_SHELL_ON_ACTION_ADD_REMOVE; - } - - else if (action == launcher->actions[APPLICATION_TILE_ACTION_UPGRADE_PACKAGE] - || action == launcher->actions[APPLICATION_TILE_ACTION_UNINSTALL_PACKAGE]) - { - temp = EXIT_SHELL_ON_ACTION_UPGRADE_UNINSTALL; - } - - if (temp) - { - if (g_settings_get_boolean (app_data->settings, temp)) - { - if (app_data->exit_on_close) - { - app=g_application_get_default(); - g_application_quit(app); - } - else - hide_shell (app_data); - } - } - else - g_warning ("Unknown Action"); -} diff --git a/libslab/app-shell.h b/libslab/app-shell.h deleted file mode 100644 index 97e22b60..00000000 --- a/libslab/app-shell.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __APP_SHELL_H__ -#define __APP_SHELL_H__ - -#include -#include -#include -#define MATEMENU_I_KNOW_THIS_IS_UNSTABLE -#include -#include - -#include "slab-section.h" -#include "tile.h" - -G_BEGIN_DECLS - -#define GROUP_POSITION_NUMBER_KEY "Unique Group Position Number" -#define APP_ACTION_KEY "Unique Application Action Key" - -/* constants for initial sizing */ -#define SIZING_SCREEN_WIDTH_LARGE 1024 -#define SIZING_SCREEN_WIDTH_MEDIUM 800 -#define SIZING_SCREEN_WIDTH_SMALL 640 -#define SIZING_SCREEN_WIDTH_LARGE_NUMCOLS 3 -#define SIZING_SCREEN_WIDTH_MEDIUM_NUMCOLS 2 -#define SIZING_SCREEN_WIDTH_SMALL_NUMCOLS 1 -#define SIZING_TILE_WIDTH 230 -#define SIZING_HEIGHT_PERCENT 0.8 - -typedef struct -{ - const gchar *name; - gint max_items; - GArray *garray; -} NewAppConfig; - -typedef struct _AppShellData -{ - GtkWidget *main_app; - gint main_app_window_x; - gint main_app_window_y; - gboolean main_app_window_shown_once; - - GtkWidget *shell; - GtkWidget *groups_section; - - GtkWidget *actions_section; - /* - NULL - if the available actions depend on the current tile selected - NON-NULL - a list of AppAction that are always shown - */ - GSList *static_actions; - - GtkWidget *filter_section; - gchar *filter_string; - GdkCursor *busy_cursor; - - GtkWidget *category_layout; - GList *categories_list; - GList *cached_tables_list; /* list of currently showing (not filtered out) tables */ - Tile *last_clicked_launcher; - SlabSection *selected_group; - GtkIconSize icon_size; - const gchar *menu_name; - NewAppConfig *new_apps; - MateMenuTree *tree; - GHashTable *hash; - - guint filter_changed_timeout; - gboolean stop_incremental_relayout; - GList *incremental_relayout_cat_list; - gboolean filtered_out_everything; - GtkWidget *filtered_out_everything_widget; - GtkLabel *filtered_out_everything_widget_label; - - gboolean show_tile_generic_name; - gboolean exit_on_close; - - GSettings *settings; -} AppShellData; - -typedef struct -{ - gchar *category; - Tile *group_launcher; - - SlabSection *section; - GList *launcher_list; - GList *filtered_launcher_list; -} CategoryData; - -typedef struct -{ - gchar *name; - MateDesktopItem *item; -} AppAction; - -typedef struct -{ - long time; - MateDesktopItem *item; -} NewAppData; - -void generate_categories (AppShellData * app_data); - -/* If new_apps_max_items is 0 then the new applications category is not created */ -AppShellData *appshelldata_new (const gchar * menu_name, - GtkIconSize icon_size, gboolean show_tile_generic_name, gboolean exit_on_close, gint new_apps_max_items); - -void layout_shell (AppShellData * app_data, const gchar * filter_title, const gchar * groups_title, - const gchar * actions_title, GSList * actions, - void (*actions_handler) (Tile *, TileEvent *, gpointer)); - -gboolean create_main_window (AppShellData * app_data, const gchar * app_name, const gchar * title, - const gchar * window_icon, gint width, gint height, gboolean hidden); - -void hide_shell (AppShellData * app_data); - -void show_shell (AppShellData * app_data); - -G_END_DECLS - -#endif /* __APP_SHELL_H__ */ diff --git a/libslab/application-tile.c b/libslab/application-tile.c deleted file mode 100644 index ab1b4cf5..00000000 --- a/libslab/application-tile.c +++ /dev/null @@ -1,764 +0,0 @@ -/* - * This file is part of libtile. - * - * Copyright (c) 2006, 2007 Novell, Inc. - * - * Libtile is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libtile 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "application-tile.h" -#include "config.h" - -#include -#include -#include -#include -#include - -#include "slab-mate-util.h" -#include "libslab-utils.h" -#include "bookmark-agent.h" -#include "themed-icon.h" - -typedef enum { - APP_IN_USER_STARTUP_DIR, - APP_NOT_IN_STARTUP_DIR, - APP_NOT_ELIGIBLE -} StartupStatus; - -static void application_tile_get_property (GObject *, guint, GValue *, GParamSpec *); -static void application_tile_set_property (GObject *, guint, const GValue *, GParamSpec *); -static void application_tile_finalize (GObject *); - -static void application_tile_setup (ApplicationTile *); - -static GtkWidget *create_header (const gchar *); -static GtkWidget *create_subheader (const gchar *); - -static void header_size_allocate_cb (GtkWidget *, GtkAllocation *, gpointer); - -static void start_trigger (Tile *, TileEvent *, TileAction *); -static void help_trigger (Tile *, TileEvent *, TileAction *); -static void user_apps_trigger (Tile *, TileEvent *, TileAction *); -static void startup_trigger (Tile *, TileEvent *, TileAction *); - -static void add_to_user_list (ApplicationTile *); -static void remove_from_user_list (ApplicationTile *); -static void add_to_startup_list (ApplicationTile *); -static void remove_from_startup_list (ApplicationTile *); - -static void update_user_list_menu_item (ApplicationTile *); -static void agent_notify_cb (GObject *, GParamSpec *, gpointer); - -static StartupStatus get_desktop_item_startup_status (MateDesktopItem *); -static void update_startup_menu_item (ApplicationTile *); - -typedef struct { - MateDesktopItem *desktop_item; - - gchar *image_id; - gboolean image_is_broken; - GtkIconSize image_size; - - gboolean show_generic_name; - StartupStatus startup_status; - - BookmarkAgent *agent; - BookmarkStoreStatus agent_status; - gboolean is_bookmarked; - gulong notify_signal_id; -} ApplicationTilePrivate; - -enum { - PROP_0, - PROP_APPLICATION_NAME, - PROP_APPLICATION_DESCRIPTION -}; - -G_DEFINE_TYPE_WITH_PRIVATE (ApplicationTile, application_tile, NAMEPLATE_TILE_TYPE) - -static void -application_tile_class_init (ApplicationTileClass *app_tile_class) -{ - GObjectClass *g_obj_class = G_OBJECT_CLASS (app_tile_class); - - g_obj_class->get_property = application_tile_get_property; - g_obj_class->set_property = application_tile_set_property; - g_obj_class->finalize = application_tile_finalize; - - g_object_class_install_property ( - g_obj_class, PROP_APPLICATION_NAME, - g_param_spec_string ( - "application-name", "application-name", - "the name of the application", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - g_obj_class, PROP_APPLICATION_DESCRIPTION, - g_param_spec_string ( - "application-description", "application-description", - "the name of the application", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -} - -GtkWidget * -application_tile_new (const gchar *desktop_item_id) -{ - return application_tile_new_full (desktop_item_id, GTK_ICON_SIZE_DND, TRUE); -} - -GtkWidget * -application_tile_new_full (const gchar *desktop_item_id, - GtkIconSize image_size, gboolean show_generic_name) -{ - ApplicationTile *this; - ApplicationTilePrivate *priv; - - const gchar *uri = NULL; - - MateDesktopItem *desktop_item; - - desktop_item = load_desktop_item_from_unknown (desktop_item_id); - - if ( - desktop_item && - mate_desktop_item_get_entry_type (desktop_item) == MATE_DESKTOP_ITEM_TYPE_APPLICATION - ) - uri = mate_desktop_item_get_location (desktop_item); - - if (! uri) { - if (desktop_item) - mate_desktop_item_unref (desktop_item); - - return NULL; - } - - this = g_object_new (APPLICATION_TILE_TYPE, "tile-uri", uri, NULL); - priv = application_tile_get_instance_private (this); - - priv->image_size = image_size; - priv->desktop_item = desktop_item; - priv->show_generic_name = show_generic_name; - - application_tile_setup (this); - - return GTK_WIDGET (this); -} - -static void -application_tile_init (ApplicationTile *tile) -{ - ApplicationTilePrivate *priv = application_tile_get_instance_private (tile); - - priv->desktop_item = NULL; - priv->image_id = NULL; - priv->image_is_broken = TRUE; - - priv->agent = NULL; - priv->agent_status = BOOKMARK_STORE_ABSENT; - priv->is_bookmarked = FALSE; - priv->notify_signal_id = 0; - - tile->name = tile->description = NULL; -} - -static void -application_tile_finalize (GObject *g_object) -{ - ApplicationTile *tile = APPLICATION_TILE (g_object); - ApplicationTilePrivate *priv = application_tile_get_instance_private (tile); - - if (tile->name) { - g_free (tile->name); - tile->name = NULL; - } - if (tile->description) { - g_free (tile->description); - tile->description = NULL; - } - - if (priv->desktop_item) { - mate_desktop_item_unref (priv->desktop_item); - priv->desktop_item = NULL; - } - if (priv->image_id) { - g_free (priv->image_id); - priv->image_id = NULL; - } - - if (priv->notify_signal_id) - g_signal_handler_disconnect (priv->agent, priv->notify_signal_id); - - g_object_unref (G_OBJECT (priv->agent)); - - G_OBJECT_CLASS (application_tile_parent_class)->finalize (g_object); -} - -static void -application_tile_get_property (GObject *g_obj, guint prop_id, GValue *value, GParamSpec *param_spec) -{ - ApplicationTile *tile = APPLICATION_TILE (g_obj); - - switch (prop_id) { - case PROP_APPLICATION_NAME: - g_value_set_string (value, tile->name); - break; - - case PROP_APPLICATION_DESCRIPTION: - g_value_set_string (value, tile->description); - break; - - default: - break; - } -} - -static void -application_tile_set_property (GObject *g_obj, guint prop_id, const GValue *value, GParamSpec *param_spec) -{ - ApplicationTile *tile = APPLICATION_TILE (g_obj); - - switch (prop_id) { - case PROP_APPLICATION_NAME: - if (tile->name) - g_free (tile->name); - tile->name = g_strdup (g_value_get_string (value)); - break; - - case PROP_APPLICATION_DESCRIPTION: - if (tile->description) - g_free (tile->description); - tile->description = g_strdup (g_value_get_string (value)); - break; - - default: - break; - } -} - -static void -application_tile_setup (ApplicationTile *this) -{ - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - - GtkWidget *image; - GtkWidget *header; - GtkWidget *subheader; - GtkMenu *context_menu; - AtkObject *accessible; - - TileAction **actions; - TileAction *action; - GtkWidget *menu_item; - GtkContainer *menu_ctnr; - - gchar *name; - gchar *desc; - - gchar *comment; - - gchar *markup; - gchar *str; - - if (! priv->desktop_item) { - priv->desktop_item = load_desktop_item_from_unknown (TILE (this)->uri); - - if (! priv->desktop_item) - return; - } - - priv->image_id = g_strdup (mate_desktop_item_get_localestring (priv->desktop_item, "Icon")); - image = themed_icon_new (priv->image_id, priv->image_size); - - gchar *filename = g_filename_from_uri (mate_desktop_item_get_location (priv->desktop_item), NULL, NULL); - GKeyFile *keyfile = g_key_file_new (); - g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, NULL); - - name = g_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, "Name", NULL, NULL); - desc = g_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, "GenericName", NULL, NULL); - comment = g_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, "Comment", NULL, NULL); - - accessible = gtk_widget_get_accessible (GTK_WIDGET (this)); - if (name) - atk_object_set_name (accessible, name); - if (desc) - atk_object_set_description (accessible, desc); - - header = create_header (name); - - /*if no GenericName then just show and center the Name */ - if (desc && priv->show_generic_name - && (!name || strcmp(name, desc) != 0)) - subheader = create_subheader (desc); - else - subheader = NULL; - - context_menu = GTK_MENU (gtk_menu_new ()); - - g_object_set ( - G_OBJECT (this), - "nameplate-image", image, - "nameplate-header", header, - "nameplate-subheader", subheader, - "context-menu", context_menu, - "application-name", name, - "application-description", desc, - NULL); - gtk_widget_set_tooltip_text (GTK_WIDGET (this), comment); - - priv->agent = bookmark_agent_get_instance (BOOKMARK_STORE_USER_APPS); - g_object_get (G_OBJECT (priv->agent), BOOKMARK_AGENT_STORE_STATUS_PROP, & priv->agent_status, NULL); - - priv->notify_signal_id = g_signal_connect ( - G_OBJECT (priv->agent), "notify", G_CALLBACK (agent_notify_cb), this); - - priv->startup_status = get_desktop_item_startup_status (priv->desktop_item); - - actions = g_new0 (TileAction *, 6); - - TILE (this)->actions = actions; - TILE (this)->n_actions = 6; - - menu_ctnr = GTK_CONTAINER (TILE (this)->context_menu); - -/* make start action */ - - str = g_strdup_printf (_("Start %s"), this->name); - markup = g_markup_printf_escaped ("%s", str); - action = tile_action_new (TILE (this), start_trigger, markup, TILE_ACTION_OPENS_NEW_WINDOW); - actions [APPLICATION_TILE_ACTION_START] = action; - g_free (markup); - g_free (str); - - menu_item = GTK_WIDGET (tile_action_get_menu_item (action)); - - gtk_container_add (menu_ctnr, menu_item); - - TILE (this)->default_action = action; - -/* insert separator */ - - gtk_container_add (menu_ctnr, gtk_separator_menu_item_new ()); - -/* make help action */ - - if (mate_desktop_item_get_string (priv->desktop_item, "DocPath")) { - action = tile_action_new ( - TILE (this), help_trigger, _("Help"), - TILE_ACTION_OPENS_NEW_WINDOW | TILE_ACTION_OPENS_HELP); - - menu_item = GTK_WIDGET (tile_action_get_menu_item (action)); - gtk_container_add (menu_ctnr, menu_item); - } - else { - action = NULL; - } - - actions [APPLICATION_TILE_ACTION_HELP] = action; - -/* insert separator */ - - if (action != NULL) - gtk_container_add (menu_ctnr, gtk_separator_menu_item_new ()); - -/* make "add/remove to favorites" action */ - - update_user_list_menu_item (this); - -/* make "add/remove to startup" action */ - - if (priv->startup_status != APP_NOT_ELIGIBLE) { - action = tile_action_new (TILE (this), startup_trigger, NULL, 0); - actions [APPLICATION_TILE_ACTION_UPDATE_STARTUP] = action; - - update_startup_menu_item (this); - - menu_item = GTK_WIDGET (tile_action_get_menu_item (action)); - - gtk_container_add (menu_ctnr, menu_item); - } - - gtk_widget_show_all (GTK_WIDGET (TILE (this)->context_menu)); - - g_free (name); - g_free (desc); - g_free (comment); - g_free (filename); - g_key_file_unref (keyfile); -} - -static GtkWidget * -create_header (const gchar *name) -{ - GtkWidget *header; - - header = gtk_label_new (name); - gtk_label_set_line_wrap (GTK_LABEL (header), TRUE); - gtk_label_set_xalign (GTK_LABEL (header), 0.0); - - g_signal_connect ( - G_OBJECT (header), - "size-allocate", - G_CALLBACK (header_size_allocate_cb), - NULL); - - return header; -} - -static void -set_background_color (GtkWidget *widget, - GdkRGBA *rgba) -{ - gchar *css; - GtkCssProvider *provider; - - provider = gtk_css_provider_new (); - - css = g_strdup_printf ("* { background-color: %s;}", - gdk_rgba_to_string (rgba)); - gtk_css_provider_load_from_data (provider, css, -1, NULL); - g_free (css); - - gtk_style_context_add_provider (gtk_widget_get_style_context (widget), - GTK_STYLE_PROVIDER (provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - g_object_unref (provider); -} - -static GtkWidget * -create_subheader (const gchar *desc) -{ - GtkWidget *subheader; - GtkStyleContext *context; - GdkRGBA *rgba = NULL; - - subheader = gtk_label_new (desc); - gtk_label_set_ellipsize (GTK_LABEL (subheader), PANGO_ELLIPSIZE_END); - gtk_label_set_xalign (GTK_LABEL (subheader), 0.0); - context = gtk_widget_get_style_context (subheader); - gtk_style_context_get (context, - GTK_STATE_FLAG_INSENSITIVE, - "background-color", &rgba, - NULL); - - set_background_color (subheader, rgba); - - return subheader; -} - -static void -start_trigger (Tile *tile, TileEvent *event, TileAction *action) -{ - ApplicationTile *this = APPLICATION_TILE (tile); - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - open_desktop_item_exec (priv->desktop_item); -} - -static void -help_trigger (Tile *tile, TileEvent *event, TileAction *action) -{ - ApplicationTile *this = APPLICATION_TILE (tile); - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - open_desktop_item_help (priv->desktop_item); -} - -static void -user_apps_trigger (Tile *tile, TileEvent *event, TileAction *action) -{ - ApplicationTile *this = APPLICATION_TILE (tile); - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - - if (priv->is_bookmarked) - remove_from_user_list (this); - else - add_to_user_list (this); - - update_user_list_menu_item (this); -} - -static void -add_to_user_list (ApplicationTile *this) -{ - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - - BookmarkItem *item; - - item = g_new0 (BookmarkItem, 1); - item->uri = TILE (this)->uri; - item->mime_type = "application/x-desktop"; - - bookmark_agent_add_item (priv->agent, item); - g_free (item); - - priv->is_bookmarked = TRUE; -} - -static void -remove_from_user_list (ApplicationTile *this) -{ - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - - bookmark_agent_remove_item (priv->agent, TILE (this)->uri); - - priv->is_bookmarked = FALSE; -} - -static void -startup_trigger (Tile *tile, TileEvent *event, TileAction *action) -{ - ApplicationTile *this = APPLICATION_TILE (tile); - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - - switch (priv->startup_status) { - case APP_IN_USER_STARTUP_DIR: - remove_from_startup_list (this); - break; - - case APP_NOT_IN_STARTUP_DIR: - add_to_startup_list (this); - break; - - default: - break; - } - - update_startup_menu_item (this); -} - -static void -add_to_startup_list (ApplicationTile *this) -{ - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - - gchar *desktop_item_filename; - gchar *desktop_item_basename; - - gchar *startup_dir; - gchar *dst_filename; - - const gchar *src_uri; - gchar *dst_uri; - - desktop_item_filename = - g_filename_from_uri (mate_desktop_item_get_location (priv->desktop_item), NULL, - NULL); - - g_return_if_fail (desktop_item_filename != NULL); - - desktop_item_basename = g_path_get_basename (desktop_item_filename); - - startup_dir = g_build_filename (g_get_user_config_dir (), "autostart", NULL); - - if (! g_file_test (startup_dir, G_FILE_TEST_EXISTS)) - g_mkdir_with_parents (startup_dir, 0700); - - dst_filename = g_build_filename (startup_dir, desktop_item_basename, NULL); - - src_uri = mate_desktop_item_get_location (priv->desktop_item); - dst_uri = g_filename_to_uri (dst_filename, NULL, NULL); - - copy_file (src_uri, dst_uri); - priv->startup_status = APP_IN_USER_STARTUP_DIR; - - g_free (desktop_item_filename); - g_free (desktop_item_basename); - g_free (startup_dir); - g_free (dst_filename); - g_free (dst_uri); -} - -static void -remove_from_startup_list (ApplicationTile *this) -{ - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - - gchar *ditem_filename; - gchar *ditem_basename; - gchar *src_filename; - - ditem_filename = - g_filename_from_uri (mate_desktop_item_get_location (priv->desktop_item), NULL, - NULL); - - g_return_if_fail (ditem_filename != NULL); - - ditem_basename = g_path_get_basename (ditem_filename); - - src_filename = g_build_filename (g_get_user_config_dir (), "autostart", ditem_basename, NULL); - - priv->startup_status = APP_NOT_IN_STARTUP_DIR; - if (g_file_test (src_filename, G_FILE_TEST_EXISTS)) - { - if(g_file_test (src_filename, G_FILE_TEST_IS_DIR)) - g_assert_not_reached (); - g_unlink (src_filename); - } - - g_free (ditem_filename); - g_free (ditem_basename); - g_free (src_filename); -} - -MateDesktopItem * -application_tile_get_desktop_item (ApplicationTile *tile) -{ - ApplicationTilePrivate *priv; - - priv = application_tile_get_instance_private (tile); - return priv->desktop_item; -} - -static void -update_user_list_menu_item (ApplicationTile *this) -{ - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - - TileAction *action; - GtkWidget *item; - - if (priv->agent_status == BOOKMARK_STORE_ABSENT) { - if (TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU]) - g_object_unref (TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU]); - - TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU] = NULL; - } - else if (! TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU]) { - TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU] = - tile_action_new (TILE (this), user_apps_trigger, NULL, 0); - - tile_action_set_menu_item_label ( - TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU], "blah"); - - item = GTK_WIDGET (tile_action_get_menu_item ( - TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU])); - gtk_menu_shell_insert (GTK_MENU_SHELL (TILE (this)->context_menu), item, 4); - - gtk_widget_show_all (item); - } - else { - /* do nothing */ ; - } - - action = TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU]; - - if (! action) - return; - - priv->is_bookmarked = bookmark_agent_has_item (priv->agent, TILE (this)->uri); - - if (priv->is_bookmarked) - tile_action_set_menu_item_label (action, _("Remove from Favorites")); - else - tile_action_set_menu_item_label (action, _("Add to Favorites")); - - item = GTK_WIDGET (tile_action_get_menu_item (action)); - - if (! GTK_IS_MENU_ITEM (item)) - return; - - g_object_get (G_OBJECT (priv->agent), BOOKMARK_AGENT_STORE_STATUS_PROP, & priv->agent_status, NULL); - - gtk_widget_set_sensitive (item, (priv->agent_status != BOOKMARK_STORE_DEFAULT_ONLY)); -} - -static StartupStatus -get_desktop_item_startup_status (MateDesktopItem *desktop_item) -{ - gchar *filename; - gchar *basename; - - const gchar * const * global_dirs; - gchar *global_target; - gchar *user_target; - - StartupStatus retval; - gint x; - - filename = g_filename_from_uri (mate_desktop_item_get_location (desktop_item), NULL, NULL); - if (!filename) - return APP_NOT_ELIGIBLE; - basename = g_path_get_basename (filename); - - retval = APP_NOT_IN_STARTUP_DIR; - global_dirs = g_get_system_config_dirs(); - for(x=0; global_dirs[x]; x++) - { - global_target = g_build_filename (global_dirs[x], "autostart", basename, NULL); - if (g_file_test (global_target, G_FILE_TEST_EXISTS)) - { - retval = APP_NOT_ELIGIBLE; - g_free (global_target); - break; - } - g_free (global_target); - } - - /* mate-session currently checks these dirs also. see startup-programs.c */ - if (retval != APP_NOT_ELIGIBLE) - { - global_dirs = g_get_system_data_dirs(); - for(x=0; global_dirs[x]; x++) - { - global_target = g_build_filename (global_dirs[x], "mate", "autostart", basename, NULL); - if (g_file_test (global_target, G_FILE_TEST_EXISTS)) - { - retval = APP_NOT_ELIGIBLE; - g_free (global_target); - break; - } - g_free (global_target); - } - } - - if (retval != APP_NOT_ELIGIBLE) - { - user_target = g_build_filename (g_get_user_config_dir (), "autostart", basename, NULL); - if (g_file_test (user_target, G_FILE_TEST_EXISTS)) - retval = APP_IN_USER_STARTUP_DIR; - g_free (user_target); - } - - g_free (basename); - g_free (filename); - - return retval; -} - -static void -update_startup_menu_item (ApplicationTile *this) -{ - TileAction *action = TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_STARTUP]; - ApplicationTilePrivate *priv = application_tile_get_instance_private (this); - - if (!action) - return; - - if (priv->startup_status == APP_IN_USER_STARTUP_DIR) - tile_action_set_menu_item_label (action, _("Remove from Startup Programs")); - else - tile_action_set_menu_item_label (action, _("Add to Startup Programs")); -} - -static void -header_size_allocate_cb (GtkWidget *widget, GtkAllocation *alloc, gpointer user_data) -{ - gtk_widget_set_size_request (widget, alloc->width, -1); -} - -static void -agent_notify_cb (GObject *g_obj, GParamSpec *pspec, gpointer user_data) -{ - update_user_list_menu_item (APPLICATION_TILE (user_data)); -} diff --git a/libslab/application-tile.h b/libslab/application-tile.h deleted file mode 100644 index dea0bde9..00000000 --- a/libslab/application-tile.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of libtile. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libtile is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libtile 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __APPLICATION_TILE_H__ -#define __APPLICATION_TILE_H__ - -#include "nameplate-tile.h" - -#include -#include - -G_BEGIN_DECLS - -#define APPLICATION_TILE_TYPE (application_tile_get_type ()) -#define APPLICATION_TILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), APPLICATION_TILE_TYPE, ApplicationTile)) -#define APPLICATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), APPLICATION_TILE_TYPE, ApplicationTileClass)) -#define IS_APPLICATION_TILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), APPLICATION_TILE_TYPE)) -#define IS_APPLICATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), APPLICATION_TILE_TYPE)) -#define APPLICATION_TILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), APPLICATION_TILE_TYPE, ApplicationTileClass)) -#define APPLICATION_TILE_ACTION_START 0 -#define APPLICATION_TILE_ACTION_HELP 1 -#define APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU 2 -#define APPLICATION_TILE_ACTION_UPDATE_STARTUP 3 -#define APPLICATION_TILE_ACTION_UPGRADE_PACKAGE 4 -#define APPLICATION_TILE_ACTION_UNINSTALL_PACKAGE 5 - -typedef struct -{ - NameplateTile nameplate_tile; - - gchar *name; - gchar *description; -} ApplicationTile; - -typedef struct -{ - NameplateTileClass nameplate_tile_class; -} ApplicationTileClass; - -GType application_tile_get_type (void); - -GtkWidget *application_tile_new (const gchar * desktop_item_id); -GtkWidget *application_tile_new_full (const gchar * desktop_item_id, - GtkIconSize icon_size, gboolean show_generic_name); - -MateDesktopItem *application_tile_get_desktop_item (ApplicationTile * tile); - -G_END_DECLS - -#endif /* __APPLICATION_TILE_H__ */ diff --git a/libslab/bookmark-agent.c b/libslab/bookmark-agent.c deleted file mode 100644 index 0f5f1bee..00000000 --- a/libslab/bookmark-agent.c +++ /dev/null @@ -1,1244 +0,0 @@ -/* - * This file is part of the Main Menu. - * - * Copyright (c) 2007 Novell, Inc. - * - * The Main Menu 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 2 of the License, or (at your option) - * any later version. - * - * The Main Menu 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 General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * the Main Menu; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "bookmark-agent.h" - -#ifdef HAVE_CONFIG_H -# include -#else -# define PACKAGE "mate-main-menu" -#endif - -#include - -#include -#include -#include -#include -#include - -#include "libslab-utils.h" - -#define USER_APPS_STORE_FILE_NAME "applications.xbel" -#define USER_DOCS_STORE_FILE_NAME "documents.xbel" -#define USER_DIRS_STORE_FILE_NAME "places.xbel" -#define SYSTEM_STORE_FILE_NAME "system-items.xbel" -#define CALC_TEMPLATE_FILE_NAME "empty.ots" -#define WRITER_TEMPLATE_FILE_NAME "empty.ott" - -#define GTK_BOOKMARKS_FILE "bookmarks" - -#define TYPE_IS_RECENT(type) ((type) == BOOKMARK_STORE_RECENT_APPS || (type) == BOOKMARK_STORE_RECENT_DOCS) - -typedef struct { - BookmarkStoreType type; - - BookmarkItem **items; - gint n_items; - BookmarkStoreStatus status; - - GBookmarkFile *store; - gboolean needs_sync; - - gchar *store_path; - gchar *user_store_path; - gboolean user_modifiable; - gboolean reorderable; - const gchar *store_filename; - - GFileMonitor *store_monitor; - GFileMonitor *user_store_monitor; - - void (* update_path) (BookmarkAgent *); - void (* load_store) (BookmarkAgent *); - void (* save_store) (BookmarkAgent *); - void (* create_item) (BookmarkAgent *, const gchar *); - - gchar *gtk_store_path; - GFileMonitor *gtk_store_monitor; -} BookmarkAgentPrivate; - -enum { - PROP_0, - PROP_ITEMS, - PROP_STATUS -}; - -static BookmarkAgent *instances [BOOKMARK_STORE_N_TYPES]; - -static BookmarkAgentClass *bookmark_agent_parent_class = NULL; - -static void bookmark_agent_base_init (BookmarkAgentClass *); -static void bookmark_agent_class_init (BookmarkAgentClass *); -static void bookmark_agent_init (BookmarkAgent *); -static BookmarkAgent *bookmark_agent_new (BookmarkStoreType ); - -static void get_property (GObject *, guint, GValue *, GParamSpec *); -static void set_property (GObject *, guint, const GValue *, GParamSpec *); -static void finalize (GObject *); - -static void update_agent (BookmarkAgent *); -static void update_items (BookmarkAgent *); -static void save_store (BookmarkAgent *); -static gint get_rank (BookmarkAgent *, const gchar *); -static void set_rank (BookmarkAgent *, const gchar *, gint); - -static void load_xbel_store (BookmarkAgent *); -static void load_places_store (BookmarkAgent *); -static void update_user_spec_path (BookmarkAgent *); -static void save_xbel_store (BookmarkAgent *); -static void create_app_item (BookmarkAgent *, const gchar *); -static void create_doc_item (BookmarkAgent *, const gchar *); -static void create_dir_item (BookmarkAgent *, const gchar *); - -static void store_monitor_cb (GFileMonitor *, GFile *, GFile *, - GFileMonitorEvent, gpointer); -static void weak_destroy_cb (gpointer, GObject *); - -static gchar *find_package_data_file (const gchar *filename); - -static gint BookmarkAgent_private_offset; - -static inline gpointer bookmark_agent_get_instance_private (BookmarkAgent *this) -{ - return (G_STRUCT_MEMBER_P (this, BookmarkAgent_private_offset)); -} - -GType -bookmark_agent_get_type () -{ - static GType g_define_type_id = 0; - - if (G_UNLIKELY (g_define_type_id == 0)) { - static const GTypeInfo info = { - sizeof (BookmarkAgentClass), - (GBaseInitFunc) bookmark_agent_base_init, - NULL, - (GClassInitFunc) bookmark_agent_class_init, - NULL, NULL, - sizeof (BookmarkAgent), 0, - (GInstanceInitFunc) bookmark_agent_init, - NULL - }; - - g_define_type_id = g_type_register_static ( - G_TYPE_OBJECT, "BookmarkAgent", & info, 0); - G_ADD_PRIVATE (BookmarkAgent); - } - - return g_define_type_id; -} - -gboolean -bookmark_agent_has_item (BookmarkAgent *this, const gchar *uri) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - return g_bookmark_file_has_item (priv->store, uri); -} - -void -bookmark_agent_add_item (BookmarkAgent *this, const BookmarkItem *item) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - if (! item) - return; - - g_return_if_fail (priv->user_modifiable); - g_return_if_fail (item->uri); - g_return_if_fail (item->mime_type); - - g_bookmark_file_set_mime_type (priv->store, item->uri, item->mime_type); - - if (item->mtime) -#if GLIB_CHECK_VERSION(2,66,0) - g_bookmark_file_set_modified_date_time (priv->store, item->uri, item->mtime); -#else - g_bookmark_file_set_modified (priv->store, item->uri, item->mtime); -#endif - - if (item->title) - g_bookmark_file_set_title (priv->store, item->uri, item->title); - - g_bookmark_file_add_application (priv->store, item->uri, item->app_name, item->app_exec); - - set_rank (this, item->uri, g_bookmark_file_get_size (priv->store) - 1); - - save_store (this); -} - -void -bookmark_agent_move_item (BookmarkAgent *this, const gchar *uri, const gchar *uri_new) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - GError *error = NULL; - - if (! TYPE_IS_RECENT (priv->type)) - return; - - gtk_recent_manager_move_item (gtk_recent_manager_get_default (), uri, uri_new, &error); - if (error) { - g_warning ("Unable to update %s with renamed file, [%s] -> [%s]: %s", - priv->store_path, uri, uri_new, error->message); - g_error_free (error); - } -} - -void -bookmark_agent_purge_items (BookmarkAgent *this) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - GError *error = NULL; - - gchar **uris = NULL; - gsize uris_len; - gint i; - g_return_if_fail (priv->user_modifiable); - - uris = g_bookmark_file_get_uris (priv->store, &uris_len); - if (TYPE_IS_RECENT (priv->type)) { - for (i = 0; i < uris_len; i++) { - gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uris [i], &error); - if (error) { - g_warning ("Unable to remove [%s] from %s: %s", - priv->store_path, uris [i], error->message); - g_error_free (error); - } - } - } else { - for (i = 0; i < uris_len; i++) { - g_bookmark_file_remove_item (priv->store, uris [i], NULL); - } - save_store (this); - } - g_strfreev (uris); -} - -void -bookmark_agent_remove_item (BookmarkAgent *this, const gchar *uri) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - gint rank; - - GError *error = NULL; - - gchar **uris = NULL; - gint rank_i; - gint i; - - g_return_if_fail (priv->user_modifiable); - - if (! bookmark_agent_has_item (this, uri)) - return; - - if (TYPE_IS_RECENT (priv->type)) { - gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uri, &error); - if (error) { - g_warning ("Unable to remove [%s] from %s: %s", priv->store_path, uri, error->message); - g_error_free (error); - } - } - else { - rank = get_rank (this, uri); - - g_bookmark_file_remove_item (priv->store, uri, NULL); - - if (rank >= 0) { - uris = g_bookmark_file_get_uris (priv->store, NULL); - - for (i = 0; uris && uris [i]; ++i) { - rank_i = get_rank (this, uris [i]); - - if (rank_i > rank) - set_rank (this, uris [i], rank_i - 1); - } - - g_strfreev (uris); - } - - save_store (this); - } -} - -void -bookmark_agent_reorder_items (BookmarkAgent *this, const gchar **uris) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gint i; - - g_return_if_fail (priv->reorderable); - - for (i = 0; uris && uris [i]; ++i) - set_rank (this, uris [i], i); - - save_store (this); -} - -#if !GLIB_CHECK_VERSION(2,66,0) -static gint -recent_item_mru_comp_func (gconstpointer a, gconstpointer b) -{ - return ((BookmarkItem *) b)->mtime - ((BookmarkItem *) a)->mtime; -} -#endif - -static GList * -make_items_from_bookmark_file (BookmarkAgent *this, GBookmarkFile *store) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - gchar **uris; - gint i; - GList *items_ordered; - - if (!store) - return NULL; - - uris = g_bookmark_file_get_uris (store, NULL); - items_ordered = NULL; - - for (i = 0; uris && uris [i]; ++i) { - gboolean include; - - if (priv->type == BOOKMARK_STORE_RECENT_APPS) - include = g_bookmark_file_has_group (store, uris [i], "recently-used-apps", NULL); - else - include = ! g_bookmark_file_get_is_private (store, uris [i], NULL); - - if (include) { - BookmarkItem *item; - - item = g_new0 (BookmarkItem, 1); - - item->uri = g_strdup (uris [i]); - item->mime_type = g_bookmark_file_get_mime_type (store, uris [i], NULL); -#if GLIB_CHECK_VERSION(2,66,0) - item->mtime = g_bookmark_file_get_modified_date_time (store, uris [i], NULL); -#else - item->mtime = g_bookmark_file_get_modified (store, uris [i], NULL); -#endif - - items_ordered = g_list_prepend (items_ordered, item); - } - } - -#if GLIB_CHECK_VERSION(2,66,0) - items_ordered = g_list_sort (items_ordered, g_date_time_compare); -#else - items_ordered = g_list_sort (items_ordered, recent_item_mru_comp_func); -#endif - g_strfreev (uris); - - return items_ordered; -} - -void -bookmark_agent_update_from_bookmark_file (BookmarkAgent *this, GBookmarkFile *store) -{ - BookmarkAgentPrivate *priv; - GList *items_ordered; - GList *node; - - g_return_if_fail (IS_BOOKMARK_AGENT (this)); - - priv = bookmark_agent_get_instance_private (this); - - items_ordered = make_items_from_bookmark_file (this, store); - - g_bookmark_file_free (priv->store); - priv->store = g_bookmark_file_new (); - - for (node = items_ordered; node; node = node->next) { - BookmarkItem *item; - - item = (BookmarkItem *) node->data; - - g_bookmark_file_set_mime_type (priv->store, item->uri, item->mime_type); - #if GLIB_CHECK_VERSION(2,66,0) - g_bookmark_file_set_modified_date_time (priv->store, item->uri, item->mtime); - #else - g_bookmark_file_set_modified (priv->store, item->uri, item->mtime); - #endif - - bookmark_item_free (item); - } - - g_list_free (items_ordered); - - update_items (this); -} - -void -bookmark_item_free (BookmarkItem *item) -{ - if (! item) - return; - - g_free (item->uri); - g_free (item->title); - g_free (item->mime_type); - g_free (item->icon); - g_free (item->app_name); - g_free (item->app_exec); - g_free (item); -} - -static void -bookmark_agent_base_init (BookmarkAgentClass *this_class) -{ - gint i; - - for (i = 0; i < BOOKMARK_STORE_N_TYPES; ++i) - instances [i] = NULL; -} - -static void -bookmark_agent_class_init (BookmarkAgentClass *this_class) -{ - GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); - - GParamSpec *items_pspec; - GParamSpec *status_pspec; - - if (BookmarkAgent_private_offset != 0) - g_type_class_adjust_private_offset (this_class, &BookmarkAgent_private_offset); - - g_obj_class->get_property = get_property; - g_obj_class->set_property = set_property; - g_obj_class->finalize = finalize; - - items_pspec = g_param_spec_pointer ( - BOOKMARK_AGENT_ITEMS_PROP, BOOKMARK_AGENT_ITEMS_PROP, - "the null-terminated list which contains the bookmark items in this store", - G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); - - status_pspec = g_param_spec_int ( - BOOKMARK_AGENT_STORE_STATUS_PROP, BOOKMARK_AGENT_STORE_STATUS_PROP, "the status of the store", - BOOKMARK_STORE_DEFAULT_ONLY, BOOKMARK_STORE_USER, BOOKMARK_STORE_DEFAULT, - G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); - - g_object_class_install_property (g_obj_class, PROP_ITEMS, items_pspec); - g_object_class_install_property (g_obj_class, PROP_STATUS, status_pspec); - - bookmark_agent_parent_class = g_type_class_peek_parent (this_class); -} - -static void -bookmark_agent_init (BookmarkAgent *this) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - priv->type = -1; - - priv->items = NULL; - priv->n_items = 0; - priv->status = BOOKMARK_STORE_ABSENT; - - priv->store = NULL; - priv->needs_sync = FALSE; - - priv->store_path = NULL; - priv->user_store_path = NULL; - priv->user_modifiable = FALSE; - priv->reorderable = FALSE; - priv->store_filename = NULL; - - priv->store_monitor = NULL; - priv->user_store_monitor = NULL; - - priv->update_path = NULL; - priv->load_store = NULL; - priv->save_store = NULL; - priv->create_item = NULL; - - priv->gtk_store_path = NULL; - priv->gtk_store_monitor = NULL; -} - -static BookmarkAgent * -bookmark_agent_new (BookmarkStoreType type) -{ - BookmarkAgent *this; - BookmarkAgentPrivate *priv; - GFile *gtk_store_file; - - this = g_object_new (BOOKMARK_AGENT_TYPE, NULL); - priv = bookmark_agent_get_instance_private (this); - - priv->type = type; - priv->store = g_bookmark_file_new (); - - switch (type) { - case BOOKMARK_STORE_USER_APPS: - priv->store_filename = USER_APPS_STORE_FILE_NAME; - priv->create_item = create_app_item; - - break; - - case BOOKMARK_STORE_USER_DOCS: - priv->store_filename = USER_DOCS_STORE_FILE_NAME; - priv->create_item = create_doc_item; - - break; - - case BOOKMARK_STORE_USER_DIRS: - priv->store_filename = USER_DIRS_STORE_FILE_NAME; - priv->create_item = create_dir_item; - - priv->user_modifiable = TRUE; - priv->reorderable = FALSE; - - priv->load_store = load_places_store; - - priv->gtk_store_path = g_build_filename (g_get_user_config_dir (), - "gtk-3.0", GTK_BOOKMARKS_FILE, NULL); - gtk_store_file = g_file_new_for_path (priv->gtk_store_path); - priv->gtk_store_monitor = g_file_monitor_file (gtk_store_file, - 0, NULL, NULL); - if (priv->gtk_store_monitor) { - g_signal_connect (priv->gtk_store_monitor, "changed", - G_CALLBACK (store_monitor_cb), this); - } - - g_object_unref (gtk_store_file); - - break; - - case BOOKMARK_STORE_RECENT_APPS: - case BOOKMARK_STORE_RECENT_DOCS: - priv->user_modifiable = TRUE; - priv->reorderable = FALSE; - - priv->store_path = g_build_filename (g_get_user_data_dir (), "recently-used.xbel", NULL); - - break; - - case BOOKMARK_STORE_SYSTEM: - priv->store_filename = SYSTEM_STORE_FILE_NAME; - priv->create_item = create_app_item; - - break; - - default: - break; - } - - if ( - type == BOOKMARK_STORE_USER_APPS || type == BOOKMARK_STORE_USER_DOCS || - type == BOOKMARK_STORE_USER_DIRS || type == BOOKMARK_STORE_SYSTEM) - { - priv->user_modifiable = TRUE; - - priv->user_store_path = g_build_filename ( - g_get_user_data_dir (), PACKAGE, priv->store_filename, NULL); - - priv->update_path = update_user_spec_path; - } - - if (type == BOOKMARK_STORE_USER_APPS || type == BOOKMARK_STORE_USER_DOCS || type == BOOKMARK_STORE_SYSTEM) { - priv->reorderable = TRUE; - priv->load_store = load_xbel_store; - priv->save_store = save_xbel_store; - } - - update_agent (this); - - return this; -} - -BookmarkAgent * -bookmark_agent_get_instance (BookmarkStoreType type) -{ - g_return_val_if_fail (0 <= type, NULL); - g_return_val_if_fail (type < BOOKMARK_STORE_N_TYPES, NULL); - - if (! instances [type]) { - instances [type] = bookmark_agent_new (type); - g_object_weak_ref (G_OBJECT (instances [type]), weak_destroy_cb, GINT_TO_POINTER (type)); - } - else - g_object_ref (G_OBJECT (instances [type])); - - return instances [type]; -} - -static void -get_property (GObject *g_obj, guint prop_id, GValue *value, GParamSpec *pspec) -{ - BookmarkAgent *this = BOOKMARK_AGENT (g_obj); - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - switch (prop_id) { - case PROP_ITEMS: - g_value_set_pointer (value, priv->items); - break; - - case PROP_STATUS: - g_value_set_int (value, priv->status); - break; - } -} - -static void -set_property (GObject *g_obj, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - /* no writeable properties */ -} - -static void -finalize (GObject *g_obj) -{ - BookmarkAgent *this = BOOKMARK_AGENT (g_obj); - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gint i; - - for (i = 0; priv->items && priv->items [i]; ++i) - bookmark_item_free (priv->items [i]); - - g_free (priv->items); - g_free (priv->store_path); - g_free (priv->user_store_path); - g_free (priv->gtk_store_path); - - if (priv->store_monitor) { - g_signal_handlers_disconnect_by_func (priv->store_monitor, store_monitor_cb, this); - g_file_monitor_cancel (priv->store_monitor); - g_object_unref (priv->store_monitor); - } - - if (priv->user_store_monitor) { - g_signal_handlers_disconnect_by_func (priv->user_store_monitor, store_monitor_cb, this); - g_file_monitor_cancel (priv->user_store_monitor); - g_object_unref (priv->user_store_monitor); - } - - if (priv->gtk_store_monitor) { - g_signal_handlers_disconnect_by_func (priv->gtk_store_monitor, store_monitor_cb, this); - g_file_monitor_cancel (priv->gtk_store_monitor); - g_object_unref (priv->gtk_store_monitor); - } - - g_bookmark_file_free (priv->store); - - G_OBJECT_CLASS (bookmark_agent_parent_class)->finalize (g_obj); -} - -static void -update_agent (BookmarkAgent *this) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - if (priv->update_path) - priv->update_path (this); - - if (priv->load_store) - priv->load_store (this); - - update_items (this); -} - -static void -update_items (BookmarkAgent *this) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gchar **uris = NULL; - gchar **uris_ordered = NULL; - gsize n_uris = 0; - gint rank = -1; - gint rank_corr = -1; - gboolean needs_update = FALSE; - gboolean store_corrupted = FALSE; - gchar *new_title, *old_title; - - gint i; - - uris = g_bookmark_file_get_uris (priv->store, & n_uris); - uris_ordered = g_new0 (gchar *, n_uris + 1); - uris_ordered [n_uris] = NULL; - - for (i = 0; uris && uris [i]; ++i) { - rank = get_rank (this, uris [i]); - - if (rank < 0 || rank >= n_uris) - rank = i; - - if (uris_ordered [rank]) { - store_corrupted = TRUE; - rank_corr = rank; - - for (rank = 0; rank < n_uris; ++rank) - if (! uris_ordered [rank]) - break; - - g_warning ( - "store corruption [%s] - multiple uris with same rank (%d): [%s] [%s], moving latter to %d", - priv->store_path, rank_corr, uris_ordered [rank_corr], uris [i], rank); - } - - set_rank (this, uris [i], rank); - - uris_ordered [rank] = uris [i]; - } - - if (priv->n_items != n_uris) - needs_update = TRUE; - - for (i = 0; ! needs_update && uris_ordered && uris_ordered [i]; ++i) { - if (priv->type == BOOKMARK_STORE_USER_DIRS) { - new_title = g_bookmark_file_get_title (priv->store, uris_ordered [i], NULL); - old_title = priv->items [i]->title; - if (!new_title && !old_title) { - if (strcmp (priv->items [i]->uri, uris_ordered [i])) - needs_update = TRUE; - } - else if ((new_title && !old_title) || (!new_title && old_title)) - needs_update = TRUE; - else if (strcmp (old_title, new_title)) - needs_update = TRUE; - g_free (new_title); - } - else if (strcmp (priv->items [i]->uri, uris_ordered [i])) - needs_update = TRUE; - } - - if (needs_update) { - for (i = 0; priv->items && priv->items [i]; ++i) - bookmark_item_free (priv->items [i]); - - g_free (priv->items); - - priv->n_items = n_uris; - priv->items = g_new0 (BookmarkItem *, priv->n_items + 1); - - for (i = 0; uris_ordered && uris_ordered [i]; ++i) { - priv->items [i] = g_new0 (BookmarkItem, 1); - priv->items [i]->uri = g_strdup (uris_ordered [i]); - priv->items [i]->title = g_bookmark_file_get_title (priv->store, uris_ordered [i], NULL); - priv->items [i]->mime_type = g_bookmark_file_get_mime_type (priv->store, uris_ordered [i], NULL); - #if GLIB_CHECK_VERSION(2,66,0) - priv->items [i]->mtime = g_bookmark_file_get_modified_date_time (priv->store, uris_ordered [i], NULL); - #else - priv->items [i]->mtime = g_bookmark_file_get_modified (priv->store, uris_ordered [i], NULL); - #endif - priv->items [i]->app_name = NULL; - priv->items [i]->app_exec = NULL; - - g_bookmark_file_get_icon (priv->store, uris_ordered [i], & priv->items [i]->icon, NULL, NULL); - } - - /* Since the bookmark store for recently-used items is updated by the caller of BookmarkAgent, - * we don't emit notifications in that case. The caller will know when to update itself. - */ - if (!TYPE_IS_RECENT (priv->type)) - g_object_notify (G_OBJECT (this), BOOKMARK_AGENT_ITEMS_PROP); - } - - if (store_corrupted) - save_store (this); - - g_strfreev (uris); - g_free (uris_ordered); -} - -static void -save_store (BookmarkAgent *this) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gchar *dir; - - g_return_if_fail (priv->user_modifiable); - - priv->needs_sync = TRUE; - priv->update_path (this); - - dir = g_path_get_dirname (priv->store_path); - g_mkdir_with_parents (dir, 0700); - g_free (dir); - - priv->save_store (this); - update_items (this); -} - -static gint -get_rank (BookmarkAgent *this, const gchar *uri) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gchar **groups; - gint rank; - - gint i; - - if (! priv->reorderable) - return -1; - - groups = g_bookmark_file_get_groups (priv->store, uri, NULL, NULL); - rank = -1; - - for (i = 0; groups && groups [i]; ++i) { - if (g_str_has_prefix (groups [i], "rank-")) { - if (rank >= 0) - g_warning ( - "store corruption - multiple ranks for same uri: [%s] [%s]", - priv->store_path, uri); - - rank = atoi (& groups [i] [5]); - } - } - - g_strfreev (groups); - - return rank; -} - -static void -set_rank (BookmarkAgent *this, const gchar *uri, gint rank) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gchar **groups; - gchar *group; - - gint i; - - if (! (priv->reorderable && bookmark_agent_has_item (this, uri))) - return; - - groups = g_bookmark_file_get_groups (priv->store, uri, NULL, NULL); - - for (i = 0; groups && groups [i]; ++i) - if (g_str_has_prefix (groups [i], "rank-")) - g_bookmark_file_remove_group (priv->store, uri, groups [i], NULL); - - g_strfreev (groups); - - group = g_strdup_printf ("rank-%d", rank); - g_bookmark_file_add_group (priv->store, uri, group); - g_free (group); -} - -static void -load_xbel_store (BookmarkAgent *this) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gchar **uris = NULL; - - GError *error = NULL; - - gint i; - gboolean success; - - if (!priv->store_path) - success = FALSE; - else { - success = g_bookmark_file_load_from_file (priv->store, priv->store_path, & error); - } - - if (!success) { - g_bookmark_file_free (priv->store); - priv->store = g_bookmark_file_new (); - - if (error) { - g_debug ("Couldn't load bookmark file [%s]: %s", priv->store_path, error->message); - g_error_free (error); - } else { - g_debug ("Couldn't load bookmark file [NULL]"); - } - return; - } - - uris = g_bookmark_file_get_uris (priv->store, NULL); - - for (i = 0; uris && uris [i]; ++i) - priv->create_item (this, uris [i]); - - g_strfreev (uris); -} - -static void -load_places_store (BookmarkAgent *this) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gchar **uris; - gchar **groups; - gchar **bookmarks = NULL; - - gchar *buf, *label, *uri; - - gint i, j, bookmark_len; - - load_xbel_store (this); - - uris = g_bookmark_file_get_uris (priv->store, NULL); - - for (i = 0; uris && uris [i]; ++i) { - groups = g_bookmark_file_get_groups (priv->store, uris [i], NULL, NULL); - - for (j = 0; groups && groups [j]; ++j) { - if (! strcmp (groups [j], "gtk-bookmarks")) { - g_bookmark_file_remove_item (priv->store, uris [i], NULL); - - break; - } - } - - g_strfreev (groups); - } - - g_strfreev (uris); - - g_file_get_contents (priv->gtk_store_path, & buf, NULL, NULL); - - if (buf) { - bookmarks = g_strsplit (buf, "\n", -1); - g_free (buf); - } - - for (i = 0; bookmarks && bookmarks [i]; ++i) { - bookmark_len = strlen (bookmarks [i]); - if (bookmark_len > 0) { - label = strstr (bookmarks[i], " "); - if (label != NULL) - uri = g_strndup (bookmarks [i], bookmark_len - strlen (label)); - else - uri = bookmarks [i]; - g_bookmark_file_add_group (priv->store, uri, "gtk-bookmarks"); - priv->create_item (this, uri); - if (label != NULL) { - label++; - if (strlen (label) > 0) - g_bookmark_file_set_title (priv->store, uri, label); - g_free (uri); - } - } - } - - g_strfreev (bookmarks); -} - -static gchar * -find_package_data_file (const gchar *filename) -{ - const gchar * const *dirs = NULL; - gchar *path = NULL; - gint i; - - dirs = g_get_system_data_dirs (); - - for (i = 0; ! path && dirs && dirs [i]; ++i) { - path = g_build_filename (dirs [i], PACKAGE, filename, NULL); - - if (! g_file_test (path, G_FILE_TEST_EXISTS)) { - g_free (path); - path = NULL; - } - } - - return path; -} - -static void -update_user_spec_path (BookmarkAgent *this) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gboolean use_user_path; - gchar *path = NULL; - - BookmarkStoreStatus status; - - use_user_path = priv->user_modifiable && - (priv->needs_sync || g_file_test (priv->user_store_path, G_FILE_TEST_EXISTS)); - - if (use_user_path) - path = g_strdup (priv->user_store_path); - else - path = find_package_data_file (priv->store_filename); - - if (use_user_path) - status = BOOKMARK_STORE_USER; - else if (path && priv->user_modifiable) - status = BOOKMARK_STORE_DEFAULT; - else if (path) - status = BOOKMARK_STORE_DEFAULT_ONLY; - else - status = BOOKMARK_STORE_ABSENT; - - if (priv->status != status) { - priv->status = status; - g_object_notify (G_OBJECT (this), BOOKMARK_AGENT_STORE_STATUS_PROP); - - if (priv->user_store_monitor) { - g_file_monitor_cancel (priv->user_store_monitor); - g_object_unref (priv->user_store_monitor); - priv->user_store_monitor = NULL; - } - - if (priv->status == BOOKMARK_STORE_DEFAULT) { - GFile *user_store_file; - - user_store_file = g_file_new_for_path (priv->user_store_path); - priv->user_store_monitor = g_file_monitor_file (user_store_file, - 0, NULL, NULL); - if (priv->user_store_monitor) { - g_signal_connect (priv->user_store_monitor, "changed", - G_CALLBACK (store_monitor_cb), this); - } - - g_object_unref (user_store_file); - } - } - - if (g_strcmp0 (priv->store_path, path)) { - g_free (priv->store_path); - priv->store_path = path; - - if (priv->store_monitor) { - g_file_monitor_cancel (priv->store_monitor); - g_object_unref (priv->store_monitor); - } - - if (priv->store_path) { - GFile *store_file; - - store_file = g_file_new_for_path (priv->store_path); - priv->store_monitor = g_file_monitor_file (store_file, - 0, NULL, NULL); - if (priv->store_monitor) { - g_signal_connect (priv->store_monitor, "changed", - G_CALLBACK (store_monitor_cb), this); - } - - g_object_unref (store_file); - } - } - else - g_free (path); -} - -static void -save_xbel_store (BookmarkAgent *this) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - GError *error = NULL; - - if (g_bookmark_file_to_file (priv->store, priv->store_path, &error)) - return; - - if (error) { - g_warning ("Couldn't save bookmark file [%s]: %s", priv->store_path, error->message); - g_error_free (error); - } else { - g_warning ("Couldn't save bookmark file [%s]", priv->store_path); - } -} - -static void -create_app_item (BookmarkAgent *this, const gchar *uri) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - MateDesktopItem *ditem; - gchar *uri_new = NULL; - - ditem = libslab_mate_desktop_item_new_from_unknown_id (uri); - - if (ditem) { - uri_new = g_strdup (mate_desktop_item_get_location (ditem)); - mate_desktop_item_unref (ditem); - } - - if (! uri_new) - return; - - if (g_strcmp0 (uri, uri_new)) - g_bookmark_file_move_item (priv->store, uri, uri_new, NULL); - - g_free (uri_new); -} - -static void -create_doc_item (BookmarkAgent *this, const gchar *uri) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gchar *uri_new = NULL; - - if ((strcmp (uri, "BLANK_SPREADSHEET") == 0) || (strcmp (uri, "BLANK_DOCUMENT") == 0)) { - gchar *template = NULL; - gchar *file; - - gchar *dir = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); - if (!dir) - dir = g_build_filename (g_get_home_dir (), "Documents", NULL); - - if (strcmp (uri, "BLANK_SPREADSHEET") == 0) { - g_bookmark_file_set_title (priv->store, uri, "BLANK_SPREADSHEET"); - file = g_strconcat (_("New Spreadsheet"), ".ots", NULL); - template = find_package_data_file (CALC_TEMPLATE_FILE_NAME); - } else { - g_bookmark_file_set_title (priv->store, uri, "BLANK_DOCUMENT"); - file = g_strconcat (_("New Document"), ".ott", NULL); - template = find_package_data_file (WRITER_TEMPLATE_FILE_NAME); - } - - gchar *path = g_build_filename (dir, file, NULL); - if (!g_file_test (path, G_FILE_TEST_EXISTS)) { - g_mkdir_with_parents (dir, 0700); - - if (template != NULL) { - gchar *contents; - gsize length; - - if (g_file_get_contents (template, &contents, &length, NULL)) - g_file_set_contents (path, contents, length, NULL); - - g_free (contents); - } else { - fclose (g_fopen (path, "w")); - } - } - - uri_new = g_filename_to_uri (path, NULL, NULL); - - g_free (dir); - g_free (file); - g_free (path); - g_free (template); - } - - if (!uri_new) - return; - - if (g_strcmp0 (uri, uri_new)) - g_bookmark_file_move_item (priv->store, uri, uri_new, NULL); - - g_free (uri_new); -} - -static void -create_dir_item (BookmarkAgent *this, const gchar *uri) -{ - BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); - - gchar *uri_new = NULL; - gchar *path = NULL; - gchar *name = NULL; - gchar *icon = NULL; - - gchar *search_string = NULL; - - gboolean gotta_free_name = FALSE; - - if (strcmp (uri, "HOME") == 0) { - uri_new = g_filename_to_uri (g_get_home_dir (), NULL, NULL); - name = g_strdup (C_("Home folder", "Home")); - gotta_free_name = TRUE; - icon = "user-home"; - } else if (strcmp (uri, "DOCUMENTS") == 0) { - path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); - if (!path) - path = g_build_filename (g_get_home_dir (), "Documents", NULL); - name = _("Documents"); - uri_new = g_filename_to_uri (path, NULL, NULL); - } else if (strcmp (uri, "DESKTOP") == 0) { - path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)); - if (!path) - path = g_build_filename (g_get_home_dir (), "Desktop", NULL); - name = _("Desktop"); - uri_new = g_filename_to_uri (path, NULL, NULL); - icon = "user-desktop"; - } else if (strcmp (uri, "file:///") == 0) { - icon = "drive-harddisk"; - name = _("File System"); - } else if (strcmp (uri, "network:") == 0) { - icon = "network-workgroup"; - name = _("Network Servers"); - } else if (g_str_has_prefix (uri, "x-caja-search")) { - icon = "system-search"; - - path = g_build_filename (g_get_user_data_dir (), "caja", "searches", & uri [21], NULL); - - if (g_file_test (path, G_FILE_TEST_EXISTS)) { - gchar *buf = NULL; - g_file_get_contents (path, &buf, NULL, NULL); - - gchar *tag_open_ptr = NULL; - gchar *tag_close_ptr = NULL; - - if (buf) { - tag_open_ptr = strstr (buf, ""); - tag_close_ptr = strstr (buf, ""); - } - - if (tag_open_ptr && tag_close_ptr) { - tag_close_ptr [0] = '\0'; - tag_close_ptr [0] = 'a'; - search_string = g_strdup_printf ("\"%s\"", &tag_open_ptr[6]); - } - - g_free (buf); - } - - if (search_string) { - name = search_string; - gotta_free_name = TRUE; - } else { - name = _("Search"); - } - } - - if (icon) - g_bookmark_file_set_icon (priv->store, uri, icon, "image/png"); - - if (name) - g_bookmark_file_set_title (priv->store, uri, name); - - if (uri_new && g_strcmp0 (uri, uri_new)) - g_bookmark_file_move_item (priv->store, uri, uri_new, NULL); - - if (gotta_free_name) { - g_free (name); - } - - g_free (path); - g_free (uri_new); -} - -static void -store_monitor_cb (GFileMonitor *mon, GFile *f1, GFile *f2, - GFileMonitorEvent event_type, gpointer user_data) -{ - update_agent (BOOKMARK_AGENT (user_data)); -} - -static void -weak_destroy_cb (gpointer data, GObject *g_obj) -{ - instances [GPOINTER_TO_INT (data)] = NULL; -} diff --git a/libslab/bookmark-agent.h b/libslab/bookmark-agent.h deleted file mode 100644 index f54415bf..00000000 --- a/libslab/bookmark-agent.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file is part of the Main Menu. - * - * Copyright (c) 2007 Novell, Inc. - * - * The Main Menu 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 2 of the License, or (at your option) - * any later version. - * - * The Main Menu 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 General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * the Main Menu; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __BOOKMARK_AGENT_H__ -#define __BOOKMARK_AGENT_H__ - -#include -#include - -#if !GLIB_CHECK_VERSION(2,66,0) -#include -#endif - -G_BEGIN_DECLS - -#define BOOKMARK_AGENT_TYPE (bookmark_agent_get_type ()) -#define BOOKMARK_AGENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BOOKMARK_AGENT_TYPE, BookmarkAgent)) -#define BOOKMARK_AGENT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), BOOKMARK_AGENT_TYPE, BookmarkAgentClass)) -#define IS_BOOKMARK_AGENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BOOKMARK_AGENT_TYPE)) -#define IS_BOOKMARK_AGENT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), BOOKMARK_AGENT_TYPE)) -#define BOOKMARK_AGENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BOOKMARK_AGENT_TYPE, BookmarkAgentClass)) - -#define BOOKMARK_AGENT_STORE_STATUS_PROP "store-status" -#define BOOKMARK_AGENT_ITEMS_PROP "items" - -typedef struct { - gchar *uri; - gchar *title; - gchar *mime_type; -#if GLIB_CHECK_VERSION(2,66,0) - GDateTime *mtime; -#else - time_t mtime; -#endif - gchar *icon; - gchar *app_name; - gchar *app_exec; -} BookmarkItem; - -typedef enum { - BOOKMARK_STORE_DEFAULT_ONLY, - BOOKMARK_STORE_DEFAULT, - BOOKMARK_STORE_USER, - BOOKMARK_STORE_ABSENT -} BookmarkStoreStatus; - -typedef enum { - BOOKMARK_STORE_USER_APPS = 0, - BOOKMARK_STORE_USER_DOCS = 1, - BOOKMARK_STORE_USER_DIRS = 2, - BOOKMARK_STORE_RECENT_APPS = 3, - BOOKMARK_STORE_RECENT_DOCS = 4, - BOOKMARK_STORE_SYSTEM = 5, - BOOKMARK_STORE_N_TYPES = 6 -} BookmarkStoreType; - -typedef struct { - GObject g_object; -} BookmarkAgent; - -typedef struct { - GObjectClass g_object_class; -} BookmarkAgentClass; - -GType bookmark_agent_get_type (void); - -BookmarkAgent *bookmark_agent_get_instance (BookmarkStoreType type); -gboolean bookmark_agent_has_item (BookmarkAgent *this, const gchar *uri); -void bookmark_agent_add_item (BookmarkAgent *this, const BookmarkItem *item); -void bookmark_agent_move_item (BookmarkAgent *this, const gchar *uri, const gchar *uri_new); -void bookmark_agent_remove_item (BookmarkAgent *this, const gchar *uri); -void bookmark_agent_reorder_items (BookmarkAgent *this, const gchar **uris); - -void bookmark_agent_update_from_bookmark_file (BookmarkAgent *this, GBookmarkFile *store); -void bookmark_agent_purge_items (BookmarkAgent *this); - -void bookmark_item_free (BookmarkItem *item); - -G_END_DECLS - -#endif /* __BOOKMARK_AGENT_H__ */ diff --git a/libslab/double-click-detector.c b/libslab/double-click-detector.c deleted file mode 100644 index e6874d11..00000000 --- a/libslab/double-click-detector.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006, 2007 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "double-click-detector.h" - -#include - -#include "libslab-utils.h" - -G_DEFINE_TYPE (DoubleClickDetector, double_click_detector, G_TYPE_OBJECT); - -void double_click_detector_update_click_time (DoubleClickDetector * detector, guint32 event_time); - -static void -double_click_detector_class_init (DoubleClickDetectorClass * detector_class) -{ -} - -static void -double_click_detector_init (DoubleClickDetector * detector) -{ - GtkSettings *settings; - gint click_interval; - - settings = gtk_settings_get_default (); - - g_object_get (G_OBJECT (settings), "gtk-double-click-time", &click_interval, NULL); - - detector->double_click_time = (gint32) click_interval; - detector->last_click_time = 0; -} - -DoubleClickDetector * -double_click_detector_new () -{ - return g_object_new (DOUBLE_CLICK_DETECTOR_TYPE, NULL); -} - -gboolean -double_click_detector_is_double_click (DoubleClickDetector *this, guint32 event_time, - gboolean auto_update) -{ - gint32 delta; - - if (event_time == 0) - event_time = (guint32) (g_get_monotonic_time () / 1000); /* milliseconds */ - - if (this->last_click_time == 0) { - if (auto_update) - double_click_detector_update_click_time (this, event_time); - - return FALSE; - } - - delta = (gint32) event_time - (gint32) this->last_click_time; - - if (auto_update) - double_click_detector_update_click_time (this, event_time); - - return delta < this->double_click_time; -} - -void -double_click_detector_update_click_time (DoubleClickDetector *this, guint32 event_time) -{ - if (event_time == 0) - event_time = (guint32) (g_get_monotonic_time () / 1000); /* milliseconds */ - - this->last_click_time = event_time; -} diff --git a/libslab/double-click-detector.h b/libslab/double-click-detector.h deleted file mode 100644 index 4a745d8e..00000000 --- a/libslab/double-click-detector.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __DOUBLE_CLICK_DETECTOR_H__ -#define __DOUBLE_CLICK_DETECTOR_H__ - -#include -#include - -G_BEGIN_DECLS - -#define DOUBLE_CLICK_DETECTOR_TYPE (double_click_detector_get_type ()) -#define DOUBLE_CLICK_DETECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DOUBLE_CLICK_DETECTOR_TYPE, DoubleClickDetector)) -#define DOUBLE_CLICK_DETECTOR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), DOUBLE_CLICK_DETECTOR_TYPE, DoubleClickDetectorClass)) -#define IS_DOUBLE_CLICK_DETECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DOUBLE_CLICK_DETECTOR_TYPE)) -#define IS_DOUBLE_CLICK_DETECTOR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), DOUBLE_CLICK_DETECTOR_TYPE)) -#define DOUBLE_CLICK_DETECTOR_GET_CLASS(o) (G_TYPE_CHECK_GET_CLASS ((o), DOUBLE_CLICK_DETECTOR_TYPE, DoubleClickDetectorClass)) - -typedef struct -{ - GObject parent_placeholder; - - gint32 double_click_time; - guint32 last_click_time; -} DoubleClickDetector; - -typedef struct -{ - GObjectClass parent_class; -} DoubleClickDetectorClass; - -GType double_click_detector_get_type (void); - -DoubleClickDetector *double_click_detector_new (void); - -gboolean double_click_detector_is_double_click (DoubleClickDetector * detector, guint32 event_time, - gboolean auto_update); - -G_END_DECLS - -#endif /* __DOUBLE_CLICK_DETECTOR_H__ */ diff --git a/libslab/libslab-utils.c b/libslab/libslab-utils.c deleted file mode 100644 index 5ee4d09c..00000000 --- a/libslab/libslab-utils.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "libslab-utils.h" - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -MateDesktopItem * -libslab_mate_desktop_item_new_from_unknown_id (const gchar *id) -{ - MateDesktopItem *item; - gchar *basename; - - GError *error = NULL; - - if (! id) - return NULL; - - item = mate_desktop_item_new_from_uri (id, 0, & error); - - if (! error) - return item; - else { - g_error_free (error); - error = NULL; - } - - item = mate_desktop_item_new_from_file (id, 0, & error); - - if (! error) - return item; - else { - g_error_free (error); - error = NULL; - } - - item = mate_desktop_item_new_from_basename (id, 0, & error); - - if (! error) - return item; - else { - g_error_free (error); - error = NULL; - } - - basename = g_strrstr (id, "/"); - - if (basename) { - basename++; - - item = mate_desktop_item_new_from_basename (basename, 0, &error); - - if (! error) - return item; - else { - g_error_free (error); - error = NULL; - } - } - - return NULL; -} diff --git a/libslab/libslab-utils.h b/libslab/libslab-utils.h deleted file mode 100644 index 069ff3c7..00000000 --- a/libslab/libslab-utils.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __LIBSLAB_UTILS_H__ -#define __LIBSLAB_UTILS_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -MateDesktopItem *libslab_mate_desktop_item_new_from_unknown_id (const gchar *id); - -G_END_DECLS - -#endif /* __LIBSLAB_UTILS_H__ */ diff --git a/libslab/mate-slab.pc.in b/libslab/mate-slab.pc.in deleted file mode 100644 index 074fa8f2..00000000 --- a/libslab/mate-slab.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: mate-slab -Description: Beautiful App Slab -Requires: glib-2.0 gobject-2.0 gio-2.0 gtk+-3.0 mate-desktop-2.0 libmate-menu -Requires.private: gdk-3.0 librsvg-2.0 -Version: @VERSION@ -Libs: -L${libdir} -lmate-slab -Cflags: -I${includedir}/libmate-slab diff --git a/libslab/mate-utils.c b/libslab/mate-utils.c deleted file mode 100644 index e42d02c4..00000000 --- a/libslab/mate-utils.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "mate-utils.h" - -#include - -gboolean -load_image_by_id (GtkImage *image, GtkIconSize size, const gchar *image_id) -{ - cairo_surface_t *surface; - gint width; - gint height; - gint scale_factor; - - GtkIconTheme *icon_theme; - - gchar *id; - - gboolean icon_exists; - - if (!image_id) - return FALSE; - - id = g_strdup (image_id); - scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (image)); - - gtk_icon_size_lookup (size, &width, &height); - gtk_image_set_pixel_size (image, width); - - if (g_path_is_absolute (id)) - { - GdkPixbuf *pixbuf; - - pixbuf = gdk_pixbuf_new_from_file_at_size (id, width * scale_factor, height * scale_factor, NULL); - - icon_exists = (pixbuf != NULL); - - if (icon_exists) - { - surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL); - gtk_image_set_from_surface (image, surface); - - cairo_surface_destroy (surface); - g_object_unref (pixbuf); - } - else - gtk_image_set_from_icon_name (image, "image-missing", size); - } - else - { - if ( /* file extensions are not copesetic with loading by "name" */ - g_str_has_suffix (id, ".png") || - g_str_has_suffix (id, ".svg") || - g_str_has_suffix (id, ".xpm") - ) - - id[strlen (id) - 4] = '\0'; - - if (gtk_widget_has_screen (GTK_WIDGET (image))) - icon_theme = - gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET - (image))); - else - icon_theme = gtk_icon_theme_get_default (); - - surface = gtk_icon_theme_load_surface (icon_theme, id, - width, scale_factor, - NULL, - GTK_ICON_LOOKUP_FORCE_SIZE, - NULL); - icon_exists = (surface != NULL); - if (icon_exists) { - gtk_image_set_from_surface (image, surface); - cairo_surface_destroy (surface); - } - else - gtk_image_set_from_icon_name (image, "image-missing", size); - - } - - g_free (id); - - return icon_exists; -} diff --git a/libslab/mate-utils.h b/libslab/mate-utils.h deleted file mode 100644 index 0fa4cd3f..00000000 --- a/libslab/mate-utils.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __MATE_UTILS_H__ -#define __MATE_UTILS_H__ - -#include -#include - -G_BEGIN_DECLS - -gboolean load_image_by_id (GtkImage * image, GtkIconSize size, - const gchar * image_id); - -G_END_DECLS - -#endif /* __MATE_UTILS_H__ */ diff --git a/libslab/nameplate-tile.c b/libslab/nameplate-tile.c deleted file mode 100644 index 7d14452c..00000000 --- a/libslab/nameplate-tile.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * This file is part of libtile. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libtile is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libtile 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "nameplate-tile.h" - -static void nameplate_tile_get_property (GObject *, guint, GValue *, GParamSpec *); -static void nameplate_tile_set_property (GObject *, guint, const GValue *, GParamSpec *); -static GObject *nameplate_tile_constructor (GType, guint, GObjectConstructParam *); - -static void nameplate_tile_drag_begin (GtkWidget *, GdkDragContext *); - -static void nameplate_tile_setup (NameplateTile *); - -typedef struct -{ - GtkContainer *image_ctnr; - GtkContainer *header_ctnr; - GtkContainer *subheader_ctnr; -} NameplateTilePrivate; - -enum -{ - PROP_0, - PROP_NAMEPLATE_IMAGE, - PROP_NAMEPLATE_HEADER, - PROP_NAMEPLATE_SUBHEADER, -}; - -G_DEFINE_TYPE_WITH_PRIVATE (NameplateTile, nameplate_tile, TILE_TYPE) - -GtkWidget *nameplate_tile_new (const gchar * uri, GtkWidget * image, GtkWidget * header, - GtkWidget * subheader) -{ - return GTK_WIDGET ( - g_object_new (NAMEPLATE_TILE_TYPE, - "tile-uri", uri, - "nameplate-image", image, - "nameplate-header", header, - "nameplate-subheader", subheader, - NULL)); -} - -static void -nameplate_tile_class_init (NameplateTileClass * this_class) -{ - GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (this_class); - - g_obj_class->constructor = nameplate_tile_constructor; - g_obj_class->get_property = nameplate_tile_get_property; - g_obj_class->set_property = nameplate_tile_set_property; - - widget_class->drag_begin = nameplate_tile_drag_begin; - - g_object_class_install_property (g_obj_class, PROP_NAMEPLATE_IMAGE, - g_param_spec_object ("nameplate-image", "nameplate-image", "nameplate image", - GTK_TYPE_WIDGET, G_PARAM_READWRITE)); - - g_object_class_install_property (g_obj_class, PROP_NAMEPLATE_HEADER, - g_param_spec_object ("nameplate-header", "nameplate-header", "nameplate header", - GTK_TYPE_WIDGET, G_PARAM_READWRITE)); - - g_object_class_install_property (g_obj_class, PROP_NAMEPLATE_SUBHEADER, - g_param_spec_object ("nameplate-subheader", "nameplate-subheader", - "nameplate subheader", GTK_TYPE_WIDGET, G_PARAM_READWRITE)); -} - -static void -nameplate_tile_init (NameplateTile * this) -{ -} - -static GObject * -nameplate_tile_constructor (GType type, guint n_param, GObjectConstructParam * param) -{ - GObject *g_obj = - (*G_OBJECT_CLASS (nameplate_tile_parent_class)->constructor) (type, n_param, param); - - nameplate_tile_setup (NAMEPLATE_TILE (g_obj)); - - return g_obj; -} - -static void -nameplate_tile_get_property (GObject * g_object, guint prop_id, GValue * value, - GParamSpec * param_spec) -{ - NameplateTile *np_tile = NAMEPLATE_TILE (g_object); - - switch (prop_id) - { - case PROP_NAMEPLATE_IMAGE: - g_value_set_object (value, np_tile->image); - break; - - case PROP_NAMEPLATE_HEADER: - g_value_set_object (value, np_tile->header); - break; - - case PROP_NAMEPLATE_SUBHEADER: - g_value_set_object (value, np_tile->subheader); - break; - default: - break; - } -} - -static void -nameplate_tile_set_property (GObject * g_object, guint prop_id, const GValue * value, - GParamSpec * param_spec) -{ - NameplateTile *this = NAMEPLATE_TILE (g_object); - NameplateTilePrivate *priv = nameplate_tile_get_instance_private (this); - - GObject *widget_obj = NULL; - - switch (prop_id) { - case PROP_NAMEPLATE_IMAGE: - case PROP_NAMEPLATE_HEADER: - case PROP_NAMEPLATE_SUBHEADER: - widget_obj = g_value_get_object (value); - break; - default: - break; - } - - switch (prop_id) - { - case PROP_NAMEPLATE_IMAGE: - if (GTK_IS_WIDGET (widget_obj)) - { - if (GTK_IS_WIDGET (this->image)) - gtk_widget_destroy (this->image); - - this->image = GTK_WIDGET (widget_obj); - - gtk_container_add (priv->image_ctnr, this->image); - - gtk_widget_show_all (this->image); - } - else if (GTK_IS_WIDGET (this->image)) - gtk_widget_destroy (this->image); - - break; - - case PROP_NAMEPLATE_HEADER: - if (GTK_IS_WIDGET (widget_obj)) - { - if (GTK_IS_WIDGET (this->header)) - gtk_widget_destroy (this->header); - - this->header = GTK_WIDGET (widget_obj); - - gtk_container_add (priv->header_ctnr, this->header); - - gtk_widget_show_all (this->header); - } - else if (GTK_IS_WIDGET (this->header)) - gtk_widget_destroy (this->header); - - break; - - case PROP_NAMEPLATE_SUBHEADER: - if (GTK_IS_WIDGET (widget_obj)) - { - if (GTK_IS_WIDGET (this->subheader)) - gtk_widget_destroy (this->subheader); - - this->subheader = GTK_WIDGET (widget_obj); - - gtk_container_add (priv->subheader_ctnr, this->subheader); - - gtk_widget_show_all (this->subheader); - } - else if (GTK_IS_WIDGET (this->subheader)) - gtk_widget_destroy (this->subheader); - - break; - - default: - break; - } -} - -static void -nameplate_tile_setup (NameplateTile *this) -{ - NameplateTilePrivate *priv = nameplate_tile_get_instance_private (this); - - GtkWidget *hbox; - GtkWidget *vbox; - - priv->image_ctnr = GTK_CONTAINER (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); - gtk_widget_set_valign (GTK_WIDGET (priv->image_ctnr), GTK_ALIGN_CENTER); - - priv->header_ctnr = GTK_CONTAINER (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); - - priv->subheader_ctnr = GTK_CONTAINER (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); - gtk_widget_set_halign (GTK_WIDGET (priv->subheader_ctnr), GTK_ALIGN_START); - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_halign (vbox, GTK_ALIGN_FILL); - gtk_widget_set_valign (vbox, GTK_ALIGN_CENTER); - - gtk_container_add (GTK_CONTAINER (this), hbox); - gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (priv->image_ctnr), FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (priv->header_ctnr), FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (priv->subheader_ctnr), FALSE, FALSE, 0); - - if (GTK_IS_WIDGET (this->image)) - gtk_container_add (priv->image_ctnr, this->image); - - if (GTK_IS_WIDGET (this->header)) - gtk_container_add (priv->header_ctnr, this->header); - - if (GTK_IS_WIDGET (this->subheader)) - gtk_container_add (priv->subheader_ctnr, this->subheader); - - gtk_widget_set_focus_on_click (GTK_WIDGET (this), FALSE); -} - -static void -nameplate_tile_drag_begin (GtkWidget * widget, GdkDragContext * context) -{ - NameplateTile *this = NAMEPLATE_TILE (widget); - GtkImage *image; - const gchar *name; - - (*GTK_WIDGET_CLASS (nameplate_tile_parent_class)->drag_begin) (widget, context); - - if (!this->image || !GTK_IS_IMAGE (this->image)) - return; - - image = GTK_IMAGE (this->image); - - switch (gtk_image_get_storage_type (image)) - { - case GTK_IMAGE_PIXBUF: - if (gtk_image_get_pixbuf (image)) - gtk_drag_set_icon_pixbuf (context, gtk_image_get_pixbuf (image), 0, 0); - - break; - - case GTK_IMAGE_ICON_NAME: - gtk_image_get_icon_name (image, &name, NULL); - if (name) - gtk_drag_set_icon_name (context, name, 0, 0); - - break; - - default: - break; - } -} diff --git a/libslab/nameplate-tile.h b/libslab/nameplate-tile.h deleted file mode 100644 index d51ff40f..00000000 --- a/libslab/nameplate-tile.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of libtile. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libtile is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libtile 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __NAMEPLATE_TILE_H__ -#define __NAMEPLATE_TILE_H__ - -#include "tile.h" - -#include -#include - -G_BEGIN_DECLS - -#define NAMEPLATE_TILE_TYPE (nameplate_tile_get_type ()) -#define NAMEPLATE_TILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NAMEPLATE_TILE_TYPE, NameplateTile)) -#define NAMEPLATE_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), NAMEPLATE_TILE_TYPE, NameplateTileClass)) -#define IS_NAMEPLATE_TILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NAMEPLATE_TILE_TYPE)) -#define IS_NAMEPLATE_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), NAMEPLATE_TILE_TYPE)) -#define NAMEPLATE_TILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NAMEPLATE_TILE_TYPE, NameplateTileClass)) - -typedef struct { - Tile tile; - - GtkWidget *image; - GtkWidget *header; - GtkWidget *subheader; -} NameplateTile; - -typedef struct { - TileClass tile_class; -} NameplateTileClass; - -GType nameplate_tile_get_type (void); - -GtkWidget *nameplate_tile_new (const gchar * uri, GtkWidget * image, GtkWidget * header, - GtkWidget * subheader); - -G_END_DECLS - -#endif /* __NAMEPLATE_TILE_H__ */ diff --git a/libslab/nld-marshal.list b/libslab/nld-marshal.list deleted file mode 100644 index 30ba5d8d..00000000 --- a/libslab/nld-marshal.list +++ /dev/null @@ -1 +0,0 @@ -VOID:STRING diff --git a/libslab/search-bar.c b/libslab/search-bar.c deleted file mode 100644 index f560f649..00000000 --- a/libslab/search-bar.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "search-bar.h" -#include "config.h" - -#include "nld-marshal.h" - -#include - -typedef struct -{ - GtkWidget *hbox; - GtkEntry *entry; - GtkWidget *button; - - int search_timeout; - guint timeout_id; - - gboolean block_signal; -} NldSearchBarPrivate; - -static void nld_search_bar_finalize (GObject *); - -static gboolean nld_search_bar_focus (GtkWidget *, GtkDirectionType); -static void nld_search_bar_grab_focus (GtkWidget *); - -enum -{ - SEARCH, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE_WITH_PRIVATE (NldSearchBar, nld_search_bar, GTK_TYPE_BOX) - -static void emit_search (NldSearchBar * search_bar); -static void emit_search_callback (GtkWidget * widget, gpointer search_bar); - -static void nld_search_bar_class_init (NldSearchBarClass * nld_search_bar_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (nld_search_bar_class); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (nld_search_bar_class); - - object_class->finalize = nld_search_bar_finalize; - widget_class->focus = nld_search_bar_focus; - widget_class->grab_focus = nld_search_bar_grab_focus; - - signals[SEARCH] = - g_signal_new ("search", G_TYPE_FROM_CLASS (nld_search_bar_class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NldSearchBarClass, search), - NULL, NULL, nld_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); -} - -static void -nld_search_bar_init (NldSearchBar * search_bar) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - GtkWidget *entry; - - gtk_widget_set_can_focus (GTK_WIDGET (search_bar), TRUE); - gtk_orientable_set_orientation (GTK_ORIENTABLE (search_bar), GTK_ORIENTATION_VERTICAL); - - priv->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); - gtk_box_pack_start (GTK_BOX (search_bar), priv->hbox, TRUE, FALSE, 0); - - entry = gtk_search_entry_new (); - gtk_widget_set_halign (entry, GTK_ALIGN_START); - gtk_widget_set_valign (entry, GTK_ALIGN_CENTER); - priv->entry = GTK_ENTRY (entry); - gtk_widget_show (entry); - gtk_box_pack_start (GTK_BOX (priv->hbox), entry, TRUE, TRUE, 0); - - g_signal_connect (entry, "activate", G_CALLBACK (emit_search_callback), search_bar); - - priv->search_timeout = -1; -} - -static void -nld_search_bar_finalize (GObject * object) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (NLD_SEARCH_BAR(object)); - - if (priv->timeout_id) - g_source_remove (priv->timeout_id); - - G_OBJECT_CLASS (nld_search_bar_parent_class)->finalize (object); -} - -static gboolean -nld_search_bar_focus (GtkWidget * widget, GtkDirectionType dir) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (NLD_SEARCH_BAR(widget)); - - return gtk_widget_child_focus (priv->hbox, dir); -} - -gboolean -nld_search_bar_has_focus (NldSearchBar * search_bar) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - - return gtk_widget_has_focus (GTK_WIDGET (priv->entry)); -} - -static void -nld_search_bar_grab_focus (GtkWidget * widget) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (NLD_SEARCH_BAR(widget)); - - gtk_widget_grab_focus (GTK_WIDGET (priv->entry)); -} - -GtkWidget * -nld_search_bar_new (void) -{ - return g_object_new (NLD_TYPE_SEARCH_BAR, NULL); -} - -void -nld_search_bar_clear (NldSearchBar * search_bar) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - - priv->block_signal = TRUE; - gtk_entry_set_text (priv->entry, ""); - priv->block_signal = FALSE; -} - -static void -emit_search (NldSearchBar * search_bar) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - - if (priv->block_signal) - return; - - if (priv->timeout_id) - { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } - - g_signal_emit (search_bar, signals[SEARCH], 0, - nld_search_bar_get_text (search_bar)); -} - -static void -emit_search_callback (GtkWidget * widget, gpointer search_bar) -{ - emit_search (search_bar); -} - -static gboolean -search_timeout (gpointer search_bar) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - - priv->timeout_id = 0; - emit_search (search_bar); - return FALSE; -} - -static void -entry_changed (GtkWidget * entry, gpointer search_bar) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - - if (priv->search_timeout == 0) - emit_search (search_bar); - else if (priv->search_timeout > 0) - { - if (priv->timeout_id != 0) - g_source_remove (priv->timeout_id); - priv->timeout_id = - g_timeout_add (priv->search_timeout * 1000, search_timeout, search_bar); - } -} - -int -nld_search_bar_get_search_timeout (NldSearchBar * search_bar) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - - return priv->search_timeout; -} - -void -nld_search_bar_set_search_timeout (NldSearchBar * search_bar, int search_timeout) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - - if (priv->search_timeout != -1 && search_timeout == -1) - g_signal_handlers_disconnect_by_func (priv->entry, entry_changed, search_bar); - else if (search_timeout != -1) - { - g_signal_connect (priv->entry, "changed", G_CALLBACK (entry_changed), search_bar); - } - - priv->search_timeout = search_timeout; -} - -const char * -nld_search_bar_get_text (NldSearchBar * search_bar) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - - return gtk_entry_get_text (priv->entry); -} - -void -nld_search_bar_set_text (NldSearchBar * search_bar, const char *text, gboolean activate) -{ - NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); - - gtk_entry_set_text (priv->entry, text); - if (activate) - emit_search (search_bar); -} - diff --git a/libslab/search-bar.h b/libslab/search-bar.h deleted file mode 100644 index fca5216d..00000000 --- a/libslab/search-bar.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __NLD_SEARCH_BAR_H__ -#define __NLD_SEARCH_BAR_H__ - -#include -#include - -G_BEGIN_DECLS - -#define NLD_TYPE_SEARCH_BAR (nld_search_bar_get_type ()) -#define NLD_SEARCH_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NLD_TYPE_SEARCH_BAR, NldSearchBar)) -#define NLD_SEARCH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NLD_TYPE_SEARCH_BAR, NldSearchBarClass)) -#define NLD_IS_SEARCH_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NLD_TYPE_SEARCH_BAR)) -#define NLD_IS_SEARCH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NLD_TYPE_SEARCH_BAR)) -#define NLD_SEARCH_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NLD_TYPE_SEARCH_BAR, NldSearchBarClass)) - -typedef struct -{ - GtkBox parent; -} NldSearchBar; - -typedef struct -{ - GtkBoxClass parent_class; - - void (*search) (NldSearchBar *, const char *text); -} NldSearchBarClass; - -GType nld_search_bar_get_type (void); - -GtkWidget *nld_search_bar_new (void); - -void nld_search_bar_clear (NldSearchBar * search_bar); -gboolean nld_search_bar_has_focus (NldSearchBar * search_bar); - -gboolean nld_search_bar_get_show_button (NldSearchBar * search_bar); -void nld_search_bar_set_show_button (NldSearchBar * search_bar, gboolean show_button); - -int nld_search_bar_get_search_timeout (NldSearchBar * search_bar); -void nld_search_bar_set_search_timeout (NldSearchBar * search_bar, int search_timeout); - -const char *nld_search_bar_get_text (NldSearchBar * search_bar); -void nld_search_bar_set_text (NldSearchBar * search_bar, const char *text, gboolean activate); - -G_END_DECLS - -#endif /* __NLD_SEARCH_BAR_H__ */ diff --git a/libslab/shell-window.c b/libslab/shell-window.c deleted file mode 100644 index 19f3c5e8..00000000 --- a/libslab/shell-window.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "shell-window.h" - -#include -#include - -#include "app-resizer.h" - -G_DEFINE_TYPE (ShellWindow, shell_window, GTK_TYPE_FRAME); - -static void -shell_window_class_init (ShellWindowClass * klass) -{ -} - -static void -shell_window_init (ShellWindow * window) -{ - window->_hbox = NULL; - window->_left_pane = NULL; - window->_right_pane = NULL; -} - -GtkWidget * -shell_window_new (AppShellData * app_data) -{ - ShellWindow *window = g_object_new (SHELL_WINDOW_TYPE, NULL); - - gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE); - gtk_frame_set_shadow_type(GTK_FRAME(window), GTK_SHADOW_NONE); - - window->_hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); - gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (window->_hbox)); - - return GTK_WIDGET (window); -} - -void -shell_window_clear_resize_handler (ShellWindow * win) -{ - if (win->resize_handler_id) - { - g_signal_handler_disconnect (win, win->resize_handler_id); - win->resize_handler_id = 0; - } -} - -void -shell_window_set_contents (ShellWindow * shell, GtkWidget * left_pane, GtkWidget * right_pane) -{ - shell->_left_pane = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_margin_top (GTK_WIDGET (shell->_left_pane), 15); - gtk_widget_set_margin_bottom (GTK_WIDGET (shell->_left_pane), 15); - gtk_widget_set_margin_start (GTK_WIDGET (shell->_left_pane), 15); - gtk_widget_set_margin_end (GTK_WIDGET (shell->_left_pane), 15); - - shell->_right_pane = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - - gtk_box_pack_start (shell->_hbox, shell->_left_pane, FALSE, FALSE, 0); - gtk_box_pack_start (shell->_hbox, shell->_right_pane, TRUE, TRUE, 0); /* this one takes any extra space */ - - gtk_container_add (GTK_CONTAINER (shell->_left_pane), left_pane); - gtk_container_add (GTK_CONTAINER (shell->_right_pane), right_pane); -} diff --git a/libslab/shell-window.h b/libslab/shell-window.h deleted file mode 100644 index 2aa51e3f..00000000 --- a/libslab/shell-window.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __SHELL_WINDOW_H__ -#define __SHELL_WINDOW_H__ - -#include -#include - -#include "app-shell.h" - -G_BEGIN_DECLS - -#define SHELL_WINDOW_TYPE (shell_window_get_type ()) -#define SHELL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_WINDOW_TYPE, ShellWindow)) -#define SHELL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_WINDOW_TYPE, ShellWindowClass)) -#define IS_SHELL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_WINDOW_TYPE)) -#define IS_SHELL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_WINDOW_TYPE)) -#define SHELL_WINDOW_GET_CLASS(obj) (G_TYPE_CHECK_GET_CLASS ((obj), SHELL_WINDOW_TYPE, ShellWindowClass)) - -typedef struct _ShellWindow ShellWindow; -typedef struct _ShellWindowClass ShellWindowClass; - -struct _ShellWindow -{ - GtkFrame frame; - - GtkBox *_hbox; - GtkWidget *_left_pane; - GtkWidget *_right_pane; - - gulong resize_handler_id; -}; - -struct _ShellWindowClass -{ - GtkFrameClass parent_class; -}; - -GType shell_window_get_type (void); -GtkWidget *shell_window_new (AppShellData * app_data); -void shell_window_set_contents (ShellWindow * window, GtkWidget * left_pane, - GtkWidget * right_pane); -void shell_window_clear_resize_handler (ShellWindow * win); - -G_END_DECLS - -#endif /* __SHELL_WINDOW_H__ */ diff --git a/libslab/slab-mate-util.c b/libslab/slab-mate-util.c deleted file mode 100644 index b036de18..00000000 --- a/libslab/slab-mate-util.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "slab-mate-util.h" -#include "libslab-utils.h" - -#include -#include - -MateDesktopItem * -load_desktop_item_from_unknown (const gchar *id) -{ - MateDesktopItem *item; - gchar *basename; - - GError *error = NULL; - - item = mate_desktop_item_new_from_uri (id, 0, &error); - - if (! error) - return item; - else { - g_error_free (error); - error = NULL; - } - - item = mate_desktop_item_new_from_file (id, 0, &error); - - if (! error) - return item; - else { - g_error_free (error); - error = NULL; - } - - item = mate_desktop_item_new_from_basename (id, 0, &error); - - if (! error) - return item; - else { - g_error_free (error); - error = NULL; - } - - basename = g_strrstr (id, "/"); - - if (basename) { - basename++; - - item = mate_desktop_item_new_from_basename (basename, 0, &error); - - if (! error) - return item; - else { - g_error_free (error); - error = NULL; - } - } - - return NULL; -} - -gboolean -open_desktop_item_exec (MateDesktopItem * desktop_item) -{ - GError *error = NULL; - - if (!desktop_item) - return FALSE; - - mate_desktop_item_launch (desktop_item, NULL, MATE_DESKTOP_ITEM_LAUNCH_ONLY_ONE | MATE_DESKTOP_ITEM_LAUNCH_DO_NOT_REAP_CHILD, &error); - - if (error) - { - g_warning ("error launching %s [%s]\n", - mate_desktop_item_get_location (desktop_item), error->message); - - g_error_free (error); - return FALSE; - } - - return TRUE; -} - -gboolean -open_desktop_item_help (MateDesktopItem * desktop_item) -{ - const gchar *doc_path; - gchar *help_uri; - - GError *error; - - if (!desktop_item) - return FALSE; - - doc_path = mate_desktop_item_get_string (desktop_item, "DocPath"); - - if (doc_path) - { - help_uri = g_strdup_printf ("help:%s", doc_path); - - error = NULL; - if (!gtk_show_uri_on_window (NULL, help_uri, gtk_get_current_event_time (), &error)) - { - g_warning ("error opening %s [%s]\n", help_uri, error->message); - - g_free (help_uri); - g_error_free (error); - return FALSE; - } - - g_free (help_uri); - } - else - return FALSE; - - return TRUE; -} - -void -copy_file (const gchar * src_uri, const gchar * dst_uri) -{ - GFile *src; - GFile *dst; - GError *error = NULL; - gboolean res; - - src = g_file_new_for_uri (src_uri); - dst = g_file_new_for_uri (dst_uri); - - res = g_file_copy (src, dst, - G_FILE_COPY_NONE, - NULL, NULL, NULL, &error); - - if (!res) - { - g_warning ("error copying [%s] to [%s]: %s.", src_uri, dst_uri, error->message); - g_error_free (error); - } - - g_object_unref (src); - g_object_unref (dst); -} diff --git a/libslab/slab-mate-util.h b/libslab/slab-mate-util.h deleted file mode 100644 index 211e76c4..00000000 --- a/libslab/slab-mate-util.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __SLAB_MATE_UTIL_H__ -#define __SLAB_MATE_UTIL_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -MateDesktopItem *load_desktop_item_from_unknown (const gchar * id); - -gboolean open_desktop_item_exec (MateDesktopItem * desktop_item); -gboolean open_desktop_item_help (MateDesktopItem * desktop_item); - -void copy_file (const gchar * src_uri, const gchar * dst_uri); - -G_END_DECLS - -#endif /* __SLAB_MATE_UTIL_H__ */ diff --git a/libslab/slab-section.c b/libslab/slab-section.c deleted file mode 100644 index f86820cf..00000000 --- a/libslab/slab-section.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "slab-section.h" - -G_DEFINE_TYPE (SlabSection, slab_section, GTK_TYPE_BOX) - -static void slab_section_finalize (GObject *); - -static void slab_section_class_init (SlabSectionClass * slab_section_class) -{ - GObjectClass *g_obj_class = G_OBJECT_CLASS (slab_section_class); - - g_obj_class->finalize = slab_section_finalize; -} - -static void -slab_section_init (SlabSection * section) -{ - section->title = NULL; - section->contents = NULL; -} - -static void -slab_section_finalize (GObject * obj) -{ - g_assert (IS_SLAB_SECTION (obj)); - (*G_OBJECT_CLASS (slab_section_parent_class)->finalize) (obj); -} - -static void -set_override_color (GtkWidget *widget, - GdkRGBA *rgba) -{ - gchar *css; - GtkCssProvider *provider; - - provider = gtk_css_provider_new (); - - css = g_strdup_printf ("* { color: %s;}", - gdk_rgba_to_string (rgba)); - gtk_css_provider_load_from_data (provider, css, -1, NULL); - g_free (css); - - gtk_style_context_add_provider (gtk_widget_get_style_context (widget), - GTK_STYLE_PROVIDER (provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - g_object_unref (provider); -} - -static void -slab_section_set_title_color (GtkWidget * widget) -{ - GtkStyleContext *context; - GdkRGBA *rgba = NULL; - - context = gtk_widget_get_style_context (widget); - - switch (SLAB_SECTION (widget)->style) - { - case Style1: - gtk_style_context_get (context, - GTK_STATE_FLAG_SELECTED, - "background-color", &rgba, - NULL); - set_override_color (SLAB_SECTION (widget)->title, rgba); - break; - case Style2: - if (SLAB_SECTION (widget)->selected) - { - gtk_style_context_get (context, - GTK_STATE_FLAG_SELECTED, - "background-color", &rgba, - NULL); - set_override_color (SLAB_SECTION (widget)->title, rgba); - } - else - { - gtk_style_context_get (context, - GTK_STATE_FLAG_INSENSITIVE, - "color", &rgba, - NULL); - set_override_color (SLAB_SECTION (widget)->title, rgba); - } - break; - default: - g_assert_not_reached (); - } -} - -static void -slab_section_style_set (GtkWidget * widget, GtkStyle * prev_style, gpointer user_data) -{ - static gboolean recursively_entered = FALSE; - if (!recursively_entered) - { - recursively_entered = TRUE; - - slab_section_set_title_color (widget); - - recursively_entered = FALSE; - } -} - -/* -gboolean -slab_section_expose_event (GtkWidget * widget, GdkEventExpose * event, gpointer data) -{ - gdk_draw_rectangle (widget->window, widget->style->light_gc[GTK_STATE_SELECTED], TRUE, - widget->allocation.x, widget->allocation.y, - widget->allocation.width + 40, widget->allocation.height); - - return FALSE; -} -*/ - -void -slab_section_set_selected (SlabSection * section, gboolean selected) -{ - if (selected == section->selected) - return; - section->selected = selected; - -/* - if(selected) - { - section->expose_handler_id = - g_signal_connect (section, "expose-event", - G_CALLBACK (slab_section_expose_event), - NULL); - } - else - { - g_signal_handler_disconnect(section, section->expose_handler_id); - } -*/ - - slab_section_set_title_color (GTK_WIDGET (section)); -} - -GtkWidget * -slab_section_new_with_markup (const gchar * title_markup, SlabStyle style) -{ - SlabSection *section; - gchar * widget_theming_name; - - section = g_object_new (SLAB_SECTION_TYPE, NULL); - gtk_orientable_set_orientation (GTK_ORIENTABLE (section), GTK_ORIENTATION_VERTICAL); - gtk_box_set_homogeneous (GTK_BOX (section), FALSE); - gtk_box_set_spacing (GTK_BOX (section), 0); - section->style = style; - section->selected = FALSE; - - section->childbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 10)); - switch (style) - { - case Style1: - widget_theming_name = "slab_section_style1"; - break; - case Style2: - gtk_widget_set_margin_top (GTK_WIDGET (section->childbox), SLAB_TOP_PADDING); - gtk_widget_set_margin_bottom (GTK_WIDGET (section->childbox), SLAB_BOTTOM_PADDING); - gtk_widget_set_margin_start (GTK_WIDGET (section->childbox), SLAB_LEFT_PADDING); - gtk_widget_set_margin_end (GTK_WIDGET (section->childbox), 0); - widget_theming_name = "slab_section_style2"; - break; - default: - g_assert_not_reached (); - } - gtk_box_pack_start (GTK_BOX (section), GTK_WIDGET (section->childbox), TRUE, TRUE, 0); - - section->title = gtk_label_new (title_markup); - gtk_label_set_use_markup (GTK_LABEL (section->title), TRUE); - gtk_label_set_xalign (GTK_LABEL (section->title), 0.0); - - gtk_widget_set_name (GTK_WIDGET (section), widget_theming_name); - g_signal_connect (section, "style-set", - G_CALLBACK (slab_section_style_set), - NULL); - - gtk_box_pack_start (section->childbox, section->title, FALSE, FALSE, 0); - - return GTK_WIDGET (section); -} - -GtkWidget * -slab_section_new (const gchar * title, SlabStyle style) -{ - GtkWidget *section; - gchar *markup; - - markup = g_strdup_printf ("%s", title); - section = slab_section_new_with_markup (markup, style); - - g_free (markup); - - return section; -} - -void -slab_section_set_title (SlabSection * section, const gchar * title) -{ - gchar *markup = g_strdup_printf ("%s", title); - - gtk_label_set_markup (GTK_LABEL (section->title), markup); - - g_free (markup); -} - -void -slab_section_set_contents (SlabSection * section, GtkWidget * contents) -{ - section->contents = contents; - - gtk_box_pack_start (section->childbox, contents, FALSE, FALSE, 0); -} diff --git a/libslab/slab-section.h b/libslab/slab-section.h deleted file mode 100644 index 04288a87..00000000 --- a/libslab/slab-section.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __SLAB_SECTION_H__ -#define __SLAB_SECTION_H__ - -#include -#include - -G_BEGIN_DECLS - -#define SLAB_SECTION_TYPE (slab_section_get_type ()) -#define SLAB_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SLAB_SECTION_TYPE, SlabSection)) -#define SLAB_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SLAB_SECTION_TYPE, SlabSectionClass)) -#define IS_SLAB_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SLAB_SECTION_TYPE )) -#define IS_SLAB_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SLAB_SECTION_TYPE )) -#define SLAB_SECTION_GET_CLASS(obj) (G_TYPE_CHECK_GET_CLASS ((obj), SLAB_SECTION_TYPE, SlabSectionClass)) - -#define SLAB_TOP_PADDING 5 -#define SLAB_BOTTOM_PADDING 5 -#define SLAB_LEFT_PADDING 10 - -typedef enum -{ - Style1, /* SlabSections in left pane - no padding */ - Style2 /* SlabSections in right pane - padding, label text changes as group is selected */ -} SlabStyle; - -typedef struct -{ - GtkBox parent_vbox; - - GtkWidget *title; - GtkWidget *contents; - SlabStyle style; - gulong expose_handler_id; - GtkBox *childbox; - gboolean selected; -} SlabSection; - -typedef struct -{ - GtkBoxClass parent_class; -} SlabSectionClass; - -GType slab_section_get_type (void); -GtkWidget *slab_section_new (const gchar * title, SlabStyle style); -GtkWidget *slab_section_new_with_markup (const gchar * title_markup, SlabStyle style); -void slab_section_set_title (SlabSection * section, const gchar * title); -void slab_section_set_contents (SlabSection * section, GtkWidget * contents); -void slab_section_set_selected (SlabSection * section, gboolean selected); - -G_END_DECLS - -#endif /* __SLAB_SECTION_H__ */ diff --git a/libslab/slab.h b/libslab/slab.h deleted file mode 100644 index 721943a0..00000000 --- a/libslab/slab.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#ifndef __SLAB_H__ -#define __SLAB_H__ - -#include "app-resizer.h" -#include "app-shell.h" -#include "application-tile.h" -#include "bookmark-agent.h" -#include "double-click-detector.h" -#include "mate-utils.h" -#include "libslab-utils.h" -#include "nameplate-tile.h" -#include "search-bar.h" -#include "shell-window.h" -#include "slab-mate-util.h" -#include "slab-section.h" -#include "tile.h" - -#endif /* __SLAB_H__ */ - diff --git a/libslab/themed-icon.c b/libslab/themed-icon.c deleted file mode 100644 index aabf4b89..00000000 --- a/libslab/themed-icon.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "themed-icon.h" - -#include "mate-utils.h" - -static void themed_icon_finalize (GObject *); -static void themed_icon_get_property (GObject *, guint, GValue *, GParamSpec *); -static void themed_icon_set_property (GObject *, guint, const GValue *, GParamSpec *); - -static void themed_icon_show (GtkWidget *); -static void themed_icon_style_updated (GtkWidget *); - -enum -{ - PROP_0, - PROP_ICON_ID, - PROP_ICON_SIZE -}; - -typedef struct -{ - gboolean icon_loaded; -} ThemedIconPrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (ThemedIcon, themed_icon, GTK_TYPE_IMAGE) - -static void themed_icon_class_init (ThemedIconClass * themed_icon_class) -{ - GObjectClass *g_obj_class = G_OBJECT_CLASS (themed_icon_class); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (themed_icon_class); - - g_obj_class->get_property = themed_icon_get_property; - g_obj_class->set_property = themed_icon_set_property; - g_obj_class->finalize = themed_icon_finalize; - - widget_class->show = themed_icon_show; - widget_class->style_updated = themed_icon_style_updated; - - g_object_class_install_property (g_obj_class, PROP_ICON_ID, g_param_spec_string ("icon-id", - "icon-id", "the identifier of the icon", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (g_obj_class, PROP_ICON_SIZE, - g_param_spec_enum ("icon-size", "icon-size", "the size of the icon", - GTK_TYPE_ICON_SIZE, GTK_ICON_SIZE_BUTTON, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -} - -static void -themed_icon_init (ThemedIcon * icon) -{ - ThemedIconPrivate *priv = themed_icon_get_instance_private (icon); - - priv->icon_loaded = FALSE; -} - -GtkWidget * -themed_icon_new (const gchar * id, GtkIconSize size) -{ - GtkWidget *icon = GTK_WIDGET (g_object_new ( - THEMED_ICON_TYPE, "icon-id", id, "icon-size", size, NULL)); - - return icon; -} - -static void -themed_icon_finalize (GObject * object) -{ - ThemedIcon *icon = THEMED_ICON (object); - if (icon->id) - g_free (icon->id); - (*G_OBJECT_CLASS (themed_icon_parent_class)->finalize) (object); -} - -static void -themed_icon_get_property (GObject * g_obj, guint prop_id, GValue * value, GParamSpec * param_spec) -{ - ThemedIcon *icon = THEMED_ICON (g_obj); - - switch (prop_id) - { - case PROP_ICON_ID: - g_value_set_string (value, icon->id); - break; - - case PROP_ICON_SIZE: - g_value_set_enum (value, icon->size); - break; - - default: - break; - } -} - -static void -themed_icon_set_property (GObject * g_obj, guint prop_id, const GValue * value, - GParamSpec * param_spec) -{ - ThemedIcon *icon = THEMED_ICON (g_obj); - - switch (prop_id) - { - case PROP_ICON_ID: - icon->id = g_strdup (g_value_get_string (value)); - -/* gtk_image_load_by_id (GTK_IMAGE (icon), icon->size, icon->id); */ - - break; - - case PROP_ICON_SIZE: - icon->size = g_value_get_enum (value); - -/* gtk_image_load_by_id (GTK_IMAGE (icon), icon->size, icon->id); */ - - break; - - default: - break; - } -} - -static void -themed_icon_show (GtkWidget * widget) -{ - ThemedIcon *icon = THEMED_ICON (widget); - ThemedIconPrivate *priv = themed_icon_get_instance_private (icon); - - if (!priv->icon_loaded) - priv->icon_loaded = load_image_by_id (GTK_IMAGE (icon), icon->size, icon->id); - - (*GTK_WIDGET_CLASS (themed_icon_parent_class)->show) (widget); -} - -static void -themed_icon_style_updated (GtkWidget * widget) -{ - ThemedIcon *icon = THEMED_ICON (widget); - - load_image_by_id (GTK_IMAGE (icon), icon->size, icon->id); -} diff --git a/libslab/themed-icon.h b/libslab/themed-icon.h deleted file mode 100644 index d4604430..00000000 --- a/libslab/themed-icon.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of libslab. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libslab is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libslab 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __THEMED_ICON_H__ -#define __THEMED_ICON_H__ - -#include -#include - -G_BEGIN_DECLS - -#define THEMED_ICON_TYPE (themed_icon_get_type ()) -#define THEMED_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THEMED_ICON_TYPE, ThemedIcon)) -#define THEMED_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THEMED_ICON_TYPE, ThemedIconClass)) -#define IS_THEMED_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THEMED_ICON_TYPE)) -#define IS_THEMED_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THEMED_ICON_TYPE)) -#define THEMED_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THEMED_ICON_TYPE, ThemedIconClass)) - -typedef struct -{ - GtkImage parent; - - GtkIconSize size; - gchar *id; -} ThemedIcon; - -typedef struct -{ - GtkImageClass parent_class; -} ThemedIconClass; - -GType themed_icon_get_type (void); -GtkWidget *themed_icon_new (const gchar * id, GtkIconSize size); - -G_END_DECLS - -#endif /* __THEMED_ICON_H__ */ diff --git a/libslab/tile-action.c b/libslab/tile-action.c deleted file mode 100644 index c1d5906c..00000000 --- a/libslab/tile-action.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * This file is part of libtile. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libtile is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libtile 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "tile.h" - -G_DEFINE_TYPE (TileAction, tile_action, G_TYPE_OBJECT) - -static void tile_action_finalize (GObject *); -static void tile_action_menu_item_activate_cb (GtkMenuItem *, gpointer); - -static void tile_action_class_init (TileActionClass * this_class) -{ - GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); - - g_obj_class->finalize = tile_action_finalize; -} - -static void -tile_action_init (TileAction * this) -{ - this->tile = NULL; - this->func = 0; - this->menu_item = NULL; - this->flags = 0; -} - -static void -tile_action_finalize (GObject * g_object) -{ - TileAction *action = TILE_ACTION (g_object); - if (action->menu_item) - gtk_widget_destroy (GTK_WIDGET (action->menu_item)); - - (*G_OBJECT_CLASS (tile_action_parent_class)->finalize) (g_object); -} - -TileAction * -tile_action_new (Tile * tile, TileActionFunc func, const gchar * menu_item_markup, guint32 flags) -{ - TileAction *this = g_object_new (TILE_ACTION_TYPE, NULL); - - this->tile = tile; - this->func = func; - - if (menu_item_markup) - tile_action_set_menu_item_label (this, menu_item_markup); - else - this->menu_item = NULL; - - this->flags = flags; - - return this; -} - -void -tile_action_set_menu_item_label (TileAction * this, const gchar * markup) -{ - GtkWidget *label; - - if (this->menu_item) - { - label = gtk_bin_get_child (GTK_BIN (this->menu_item)); - gtk_label_set_markup (GTK_LABEL (label), markup); - } - else - { - label = gtk_label_new (markup); - gtk_label_set_use_markup (GTK_LABEL (label), TRUE); - gtk_label_set_xalign (GTK_LABEL (label), 0.0); - - this->menu_item = GTK_MENU_ITEM (gtk_menu_item_new ()); - gtk_container_add (GTK_CONTAINER (this->menu_item), label); - - g_signal_connect (this->menu_item, "activate", - G_CALLBACK (tile_action_menu_item_activate_cb), - this); - } -} - -GtkMenuItem * -tile_action_get_menu_item (TileAction * this) -{ - return this->menu_item; -} - -static void -tile_action_menu_item_activate_cb (GtkMenuItem * menu_item, gpointer user_data) -{ - TileAction *this = TILE_ACTION (user_data); - - tile_trigger_action (this->tile, this); -} diff --git a/libslab/tile.c b/libslab/tile.c deleted file mode 100644 index 96ff2120..00000000 --- a/libslab/tile.c +++ /dev/null @@ -1,529 +0,0 @@ -/* - * This file is part of libtile. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libtile is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libtile 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "tile.h" - -#include -#include - -#include "double-click-detector.h" - -typedef struct -{ - DoubleClickDetector *double_click_detector; - - gboolean is_dragging; -} TilePrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (Tile, tile, GTK_TYPE_BUTTON) - -static void tile_finalize (GObject *); -static void tile_dispose (GObject *); -static void tile_get_property (GObject *, guint, GValue *, GParamSpec *); -static void tile_set_property (GObject *, guint, const GValue *, GParamSpec *); -static GObject *tile_constructor (GType, guint, GObjectConstructParam *); - -static void tile_setup (Tile *); - -static void tile_enter (GtkButton * widget); -static void tile_leave (GtkButton * widget); -static void tile_clicked (GtkButton *widget); - -static gboolean tile_focus_in (GtkWidget *, GdkEventFocus *); -static gboolean tile_focus_out (GtkWidget *, GdkEventFocus *); -static gboolean tile_draw (GtkWidget *, cairo_t *); -static gboolean tile_button_release (GtkWidget *, GdkEventButton *); -static gboolean tile_key_release (GtkWidget *, GdkEventKey *); -static gboolean tile_popup_menu (GtkWidget *); - -static void tile_drag_begin (GtkWidget *, GdkDragContext *); -static void tile_drag_data_get (GtkWidget *, GdkDragContext *, GtkSelectionData *, guint, -guint); - -static void tile_tile_action_triggered (Tile *, TileEvent *, TileAction *); -static void tile_action_triggered_event_marshal (GClosure *, GValue *, guint, const GValue *, -gpointer, gpointer); - -typedef void (*marshal_func_VOID__POINTER_POINTER) (gpointer, gpointer, gpointer, gpointer); - -enum -{ - TILE_ACTIVATED_SIGNAL, - TILE_ACTION_TRIGGERED_SIGNAL, - LAST_SIGNAL -}; - -static guint tile_signals[LAST_SIGNAL] = { 0 }; - -enum -{ - PROP_0, - PROP_TILE_URI, - PROP_TILE_CONTEXT_MENU, - PROP_TILE_ACTIONS -}; - -static void -tile_class_init (TileClass * this_class) -{ - GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (this_class); - GtkButtonClass *button_class = GTK_BUTTON_CLASS (this_class); - - g_obj_class->constructor = tile_constructor; - g_obj_class->get_property = tile_get_property; - g_obj_class->set_property = tile_set_property; - g_obj_class->finalize = tile_finalize; - g_obj_class->dispose = tile_dispose; - - widget_class->focus_in_event = tile_focus_in; - widget_class->focus_out_event = tile_focus_out; - widget_class->draw = tile_draw; - widget_class->button_release_event = tile_button_release; - widget_class->key_release_event = tile_key_release; - widget_class->drag_begin = tile_drag_begin; - widget_class->drag_data_get = tile_drag_data_get; - widget_class->popup_menu = tile_popup_menu; - - button_class->enter = tile_enter; - button_class->leave = tile_leave; - button_class->clicked = tile_clicked; - - this_class->tile_activated = NULL; - this_class->tile_action_triggered = tile_tile_action_triggered; - - g_object_class_install_property (g_obj_class, PROP_TILE_URI, - g_param_spec_string ("tile-uri", "tile-uri", "the uri of the tile", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (g_obj_class, PROP_TILE_CONTEXT_MENU, - g_param_spec_object ("context-menu", "context-menu", - "the context menu for the tile", GTK_TYPE_MENU, G_PARAM_READWRITE)); - - tile_signals[TILE_ACTIVATED_SIGNAL] = g_signal_new ("tile-activated", - G_TYPE_FROM_CLASS (this_class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (TileClass, tile_activated), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - - tile_signals[TILE_ACTION_TRIGGERED_SIGNAL] = g_signal_new ("tile-action-triggered", - G_TYPE_FROM_CLASS (this_class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (TileClass, tile_action_triggered), - NULL, NULL, tile_action_triggered_event_marshal, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); -} - -static GObject * -tile_constructor (GType type, guint n_param, GObjectConstructParam * param) -{ - GObject *g_obj; - TilePrivate *priv; - - g_obj = (*G_OBJECT_CLASS (tile_parent_class)->constructor) (type, n_param, param); - - priv = tile_get_instance_private (TILE(g_obj)); - priv->double_click_detector = double_click_detector_new (); - - tile_setup (TILE (g_obj)); - - return g_obj; -} - -static void -tile_init (Tile * tile) -{ - TilePrivate *priv = tile_get_instance_private (tile); - - tile->uri = NULL; - tile->context_menu = NULL; - tile->entered = FALSE; - tile->enabled = TRUE; - - tile->actions = NULL; - tile->n_actions = 0; - - tile->default_action = NULL; - - priv->double_click_detector = NULL; - priv->is_dragging = FALSE; -} - -static void -tile_finalize (GObject * g_object) -{ - Tile *tile = TILE (g_object); - TilePrivate *priv = tile_get_instance_private (TILE(tile)); - - if (tile->n_actions) /* this will also free "default_action" entry */ - { - g_free (tile->actions); - } - - if (tile->uri) - g_free (tile->uri); - - g_object_unref (priv->double_click_detector); - - (*G_OBJECT_CLASS (tile_parent_class)->finalize) (g_object); -} - -static void -tile_dispose (GObject * g_object) -{ - Tile *tile = TILE (g_object); - - /* free the TileAction object */ - if (tile->n_actions) - { - gint x; - for (x = 0; x < tile->n_actions; x++) - { - if (tile->actions[x] != NULL) { - g_object_unref (tile->actions[x]); - tile->actions[x] = NULL; - } - } - } - - /* free the GtkMenu object */ - if (tile->context_menu != NULL) { - gtk_widget_destroy (GTK_WIDGET (tile->context_menu)); - tile->context_menu = NULL; - } - - (*G_OBJECT_CLASS (tile_parent_class)->dispose) (g_object); -} - -static void -tile_get_property (GObject * g_obj, guint prop_id, GValue * value, GParamSpec * param_spec) -{ - if (!IS_TILE (g_obj)) - return; - - switch (prop_id) - { - case PROP_TILE_URI: - g_value_set_string (value, TILE (g_obj)->uri); - break; - - case PROP_TILE_CONTEXT_MENU: - g_value_set_object (value, TILE (g_obj)->context_menu); - break; - - default: - break; - } -} - -static void -tile_set_property (GObject * g_obj, guint prop_id, const GValue * value, GParamSpec * param_spec) -{ - Tile *tile; - GtkMenu *menu; - - if (!IS_TILE (g_obj)) - return; - - tile = TILE (g_obj); - - switch (prop_id) - { - case PROP_TILE_URI: - tile->uri = g_strdup (g_value_get_string (value)); - break; - - case PROP_TILE_CONTEXT_MENU: - menu = g_value_get_object (value); - - if (menu == tile->context_menu) - break; - - if (tile->context_menu) - gtk_menu_detach (tile->context_menu); - - tile->context_menu = menu; - - if (tile->context_menu) - gtk_menu_attach_to_widget (tile->context_menu, GTK_WIDGET (tile), NULL); - - break; - - default: - break; - } -} - -static void -tile_setup (Tile * tile) -{ - gtk_button_set_relief (GTK_BUTTON (tile), GTK_RELIEF_NONE); - - if (tile->uri) - { - gtk_drag_source_set (GTK_WIDGET (tile), GDK_BUTTON1_MASK, NULL, 0, - GDK_ACTION_COPY | GDK_ACTION_MOVE); - - gtk_drag_source_add_uri_targets (GTK_WIDGET (tile)); - } -} - -static void -tile_enter (GtkButton * widget) -{ - gtk_widget_set_state_flags (GTK_WIDGET (widget), TILE_STATE_ENTERED, TRUE); - - TILE (widget)->entered = TRUE; -} - -static void -tile_leave (GtkButton * widget) -{ - if (gtk_widget_has_focus (GTK_WIDGET (widget))) - gtk_widget_set_state_flags (GTK_WIDGET (widget), TILE_STATE_FOCUSED, TRUE); - else - gtk_widget_set_state_flags (GTK_WIDGET (widget), GTK_STATE_FLAG_NORMAL, TRUE); - - TILE (widget)->entered = FALSE; -} - -static void -tile_clicked (GtkButton * widget) -{ - TileEvent *tile_event; - GdkEvent *event; - gboolean handled; - - tile_event = g_new0 (TileEvent, 1); - tile_event->type = TILE_EVENT_ACTIVATED_DOUBLE_CLICK; - tile_event->time = gtk_get_current_event_time (); - - g_signal_emit (widget, tile_signals[TILE_ACTIVATED_SIGNAL], 0, tile_event); - g_signal_emit_by_name (widget, "button-release-event", &event, &handled); - - g_free (tile_event); -} - -static gboolean -tile_focus_in (GtkWidget * widget, GdkEventFocus * event) -{ - gtk_widget_set_state_flags (widget, TILE_STATE_FOCUSED, TRUE); - - return FALSE; -} - -static gboolean -tile_focus_out (GtkWidget * widget, GdkEventFocus * event) -{ - if (TILE (widget)->entered) - gtk_widget_set_state_flags (widget, TILE_STATE_ENTERED, TRUE); - else - gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_NORMAL, TRUE); - - return FALSE; -} - -static gboolean -tile_draw (GtkWidget * widget, cairo_t * cr) -{ - /* FIXME: there ought to be a better way to prevent the focus from being rendered. */ - - gboolean has_focus; - gboolean retval; - - if ((has_focus = gtk_widget_has_focus (widget))) - gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_FOCUSED); - - retval = (*GTK_WIDGET_CLASS (tile_parent_class)->draw) (widget, cr); - - if (has_focus) - gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_FOCUSED, TRUE); - - return retval; -} - -static gboolean -tile_button_release (GtkWidget * widget, GdkEventButton * event) -{ - Tile *tile = TILE (widget); - TilePrivate *priv = tile_get_instance_private (tile); - - TileEvent *tile_event; - gboolean handled; - - if (priv->is_dragging) - { - priv->is_dragging = FALSE; - - return TRUE; - } - - switch (event->button) - { - case 1: - tile_event = g_new0 (TileEvent, 1); - tile_event->time = event->time; - - if (double_click_detector_is_double_click (priv->double_click_detector, event->time, - TRUE)) - tile_event->type = TILE_EVENT_ACTIVATED_DOUBLE_CLICK; - else - tile_event->type = TILE_EVENT_ACTIVATED_SINGLE_CLICK; - - g_signal_emit (tile, tile_signals[TILE_ACTIVATED_SIGNAL], 0, tile_event); - g_signal_emit_by_name (GTK_BUTTON (widget), "button-release-event", &event, &handled); - - g_free (tile_event); - - break; - - case 3: - if (GTK_IS_MENU (tile->context_menu)) - gtk_menu_popup_at_widget (GTK_MENU (tile->context_menu), - widget, - GDK_GRAVITY_SOUTH_WEST, - GDK_GRAVITY_NORTH_WEST, - (const GdkEvent*) event); - - break; - - default: - break; - } - - return TRUE; -} - -static gboolean -tile_key_release (GtkWidget * widget, GdkEventKey * event) -{ - TileEvent *tile_event; - - if (event->keyval == GDK_KEY_Return) - { - tile_event = g_new0 (TileEvent, 1); - tile_event->type = TILE_EVENT_ACTIVATED_KEYBOARD; - tile_event->time = event->time; - - g_signal_emit (widget, tile_signals[TILE_ACTIVATED_SIGNAL], 0, tile_event); - - return TRUE; - } - - return FALSE; -} - -static gboolean -tile_popup_menu (GtkWidget * widget) -{ - Tile *tile = TILE (widget); - - if (GTK_IS_MENU (tile->context_menu)) - { - gtk_menu_popup_at_widget (GTK_MENU (tile->context_menu), - widget, - GDK_GRAVITY_SOUTH_WEST, - GDK_GRAVITY_NORTH_WEST, - NULL); - - return TRUE; - } - - else - return FALSE; -} - -static void -tile_drag_begin (GtkWidget * widget, GdkDragContext * context) -{ - TilePrivate *priv; - - priv = tile_get_instance_private (TILE(widget)); - priv->is_dragging = TRUE; -} - -static void -tile_drag_data_get (GtkWidget * widget, GdkDragContext * context, GtkSelectionData * data, - guint info, guint time) -{ - gchar *uris[2]; - - if (TILE (widget)->uri) - { - uris[0] = TILE (widget)->uri; - uris[1] = NULL; - - gtk_selection_data_set_uris (data, uris); - } -} - -static void -tile_tile_action_triggered (Tile * tile, TileEvent * event, TileAction * action) -{ - if (action && action->func) - (*action->func) (tile, event, action); -} - -void -tile_trigger_action (Tile * tile, TileAction * action) -{ - tile_trigger_action_with_time (tile, action, GDK_CURRENT_TIME); -} - -void -tile_trigger_action_with_time (Tile * tile, TileAction * action, guint32 time) -{ - TileEvent *event = g_new0 (TileEvent, 1); - - event->type = TILE_EVENT_ACTION_TRIGGERED; - event->time = time; - - g_signal_emit (tile, tile_signals[TILE_ACTION_TRIGGERED_SIGNAL], 0, event, action); - g_free (event); -} - -static void -tile_action_triggered_event_marshal (GClosure * closure, GValue * retval, guint n_param, - const GValue * param, gpointer invocation_hint, gpointer marshal_data) -{ - marshal_func_VOID__POINTER_POINTER callback; - GCClosure *cc = (GCClosure *) closure; - gpointer data_0, data_1; - - g_return_if_fail (n_param == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data_0 = closure->data; - data_1 = g_value_peek_pointer (param); - } - else - { - data_0 = g_value_peek_pointer (param); - data_1 = closure->data; - } - - if (marshal_data) - callback = (marshal_func_VOID__POINTER_POINTER) marshal_data; - else - callback = (marshal_func_VOID__POINTER_POINTER) cc->callback; - - callback (data_0, g_value_peek_pointer (param + 1), g_value_peek_pointer (param + 2), - data_1); -} diff --git a/libslab/tile.h b/libslab/tile.h deleted file mode 100644 index 9c8d3f2a..00000000 --- a/libslab/tile.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file is part of libtile. - * - * Copyright (c) 2006 Novell, Inc. - * - * Libtile is free software; you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * Libtile 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 Lesser General Public License - * along with libslab; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __TILE_H__ -#define __TILE_H__ - -#include -#include - -G_BEGIN_DECLS - -#define TILE_TYPE (tile_get_type ()) -#define TILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TILE_TYPE, Tile)) -#define TILE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TILE_TYPE, TileClass)) -#define IS_TILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TILE_TYPE)) -#define IS_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TILE_TYPE)) -#define TILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TILE_TYPE, TileClass)) -#define TILE_ACTION_TYPE (tile_action_get_type ()) -#define TILE_ACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TILE_ACTION_TYPE, TileAction)) -#define TILE_ACTION_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TILE_ACTION_TYPE, TileActionClass)) -#define IS_TILE_ACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TILE_ACTION_TYPE)) -#define IS_TILE_ACTION_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TILE_ACTION_TYPE)) -#define TILE_ACTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TILE_ACTION_TYPE, TileActionClass)) -#define TILE_ACTION_CHECK_FLAG(action,flag) ((TILE_ACTION (action)->flags & (flag)) != 0) -#define TILE_STATE_ENTERED GTK_STATE_FLAG_PRELIGHT -#define TILE_STATE_FOCUSED GTK_STATE_FLAG_PRELIGHT - -typedef struct _Tile Tile; -typedef struct _TileClass TileClass; -typedef struct _TileAction TileAction; -typedef struct _TileActionClass TileActionClass; -typedef struct _TileEvent TileEvent; - -typedef void (*TileActionFunc) (Tile *, TileEvent *, TileAction *); - -typedef enum -{ - TILE_EVENT_ACTIVATED_SINGLE_CLICK, - TILE_EVENT_ACTIVATED_DOUBLE_CLICK, - TILE_EVENT_ACTIVATED_KEYBOARD, - TILE_EVENT_ACTION_TRIGGERED -} TileEventType; - -typedef enum -{ - TILE_ACTION_OPENS_NEW_WINDOW = 1 << 0, - TILE_ACTION_OPENS_HELP = 1 << 1 -} TileActionFlags; - -struct _Tile -{ - GtkButton gtk_button; - - gchar *uri; - GtkMenu *context_menu; - gboolean entered; - gboolean enabled; - - TileAction **actions; - gint n_actions; - - TileAction *default_action; -}; - -struct _TileClass -{ - GtkButtonClass gtk_button_class; - - void (*tile_activated) (Tile *, TileEvent *); - void (*tile_action_triggered) (Tile *, TileEvent *, TileAction *); -}; - -struct _TileAction -{ - GObject parent; - - Tile *tile; - - TileActionFunc func; - GtkMenuItem *menu_item; - - guint32 flags; -}; - -struct _TileActionClass -{ - GObjectClass parent_class; -}; - -struct _TileEvent -{ - TileEventType type; - guint32 time; -}; - -GType tile_get_type (void); -GType tile_action_get_type (void); - -void tile_trigger_action (Tile * tile, TileAction * action); -void tile_trigger_action_with_time (Tile * tile, TileAction * action, guint32 time); - -TileAction *tile_action_new (Tile * tile, TileActionFunc func, const gchar * menu_item_markup, - guint32 flags); - -void tile_action_set_menu_item_label (TileAction * action, const gchar * markup); -GtkMenuItem *tile_action_get_menu_item (TileAction * action); - -G_END_DECLS - -#endif /* __TILE_H__ */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 02c194ae..41edb47a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -90,7 +90,7 @@ typing-break/main.c font-viewer/font-view.c font-viewer/mate-font-viewer.desktop.in font-viewer/font-thumbnailer.c -libslab/app-shell.c -libslab/application-tile.c -libslab/bookmark-agent.c -libslab/search-bar.c +shell/app-shell.c +shell/application-tile.c +shell/bookmark-agent.c +shell/search-bar.c diff --git a/shell/Makefile.am b/shell/Makefile.am index d3e4d8bd..5f0b5f7d 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -1,21 +1,48 @@ -REAL_LIBSLAB_CFLAGS = -I$(top_srcdir)/libslab -REAL_LIBSLAB_LIBS = $(top_builddir)/libslab/libmate-slab.la - AM_CPPFLAGS = \ -I$(top_srcdir) \ $(WARN_CFLAGS) \ - $(REAL_LIBSLAB_CFLAGS) \ $(MATECC_SHELL_CFLAGS) \ -DMATELOCALEDIR="\"$(datadir)/locale\"" bin_PROGRAMS = mate-control-center mate_control_center_SOURCES = \ - control-center.c + $(MARSHAL_GENERATED) \ + app-resizer.c \ + app-shell.c \ + application-tile.c \ + bookmark-agent.c \ + control-center.c \ + double-click-detector.c \ + mate-utils.c \ + libslab-utils.c \ + nameplate-tile.c \ + search-bar.c \ + shell-window.c \ + slab-mate-util.c \ + slab-section.c \ + themed-icon.c \ + themed-icon.h \ + tile-action.c \ + tile.c \ + application-tile.h \ + app-resizer.h \ + app-shell.h \ + bookmark-agent.h \ + double-click-detector.h \ + libslab-utils.h \ + mate-utils.h \ + nameplate-tile.h \ + search-bar.h \ + shell-window.h \ + slab.h \ + slab-mate-util.h \ + slab-section.h \ + themed-icon.h \ + tile.h mate_control_center_LDADD = \ - $(MATECC_SHELL_LIBS) \ - $(REAL_LIBSLAB_LIBS) + $(MATECC_SHELL_LIBS) sysdir = $(datadir)/applications sys_in_files = matecc.desktop.in @@ -37,10 +64,22 @@ else $(AM_V_GEN) sed '/^# Translators/d' < $< > $@ endif +MARSHAL_GENERATED = nld-marshal.c nld-marshal.h + +nld-marshal.h: nld-marshal.list + ( @GLIB_GENMARSHAL@ --prefix=nld_marshal $(srcdir)/nld-marshal.list --header > nld-marshal.tmp \ + && mv nld-marshal.tmp nld-marshal.h ) \ + || ( rm -f nld-marshal.tmp && exit 1 ) + +nld-marshal.c: nld-marshal.h + ( (echo '#include "nld-marshal.h"'; @GLIB_GENMARSHAL@ --prefix=nld_marshal $(srcdir)/nld-marshal.list --body) > nld-marshal.tmp \ + && mv nld-marshal.tmp nld-marshal.c ) \ + || ( rm -f nld-marshal.tmp && exit 1 ) + menudir = $(sysconfdir)/xdg/menus menu_DATA = matecc.menu -EXTRA_DIST = $(sys_in_files) matecc.directory.desktop.in matecc.menu +EXTRA_DIST = $(sys_in_files) matecc.directory.desktop.in matecc.menu nld-marshal.list DISTCLEANFILES = $(sys_DATA) matecc.directory diff --git a/shell/app-resizer.c b/shell/app-resizer.c new file mode 100644 index 00000000..0e1a15b8 --- /dev/null +++ b/shell/app-resizer.c @@ -0,0 +1,321 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "app-shell.h" +#include "app-resizer.h" + +static void app_resizer_size_allocate (GtkWidget * resizer, GtkAllocation * allocation); +static gboolean app_resizer_paint_window (GtkWidget * widget, cairo_t * cr, AppShellData * app_data); + +G_DEFINE_TYPE (AppResizer, app_resizer, GTK_TYPE_LAYOUT); + +static void +app_resizer_class_init (AppResizerClass * klass) +{ + GtkWidgetClass *widget_class; + + widget_class = GTK_WIDGET_CLASS (klass); + widget_class->size_allocate = app_resizer_size_allocate; +} + +static void +app_resizer_init (AppResizer * window) +{ + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), + GTK_STYLE_CLASS_VIEW); +} + +void +remove_container_entries (GtkContainer * widget) +{ + GList *children, *l; + + children = gtk_container_get_children (widget); + for (l = children; l; l = l->next) + { + GtkWidget *child = GTK_WIDGET (l->data); + gtk_container_remove (GTK_CONTAINER (widget), GTK_WIDGET (child)); + } + + if (children) + g_list_free (children); +} + +static void +resize_table (AppResizer *widget, GtkGrid * table, gint columns) +{ + remove_container_entries (GTK_CONTAINER (table)); + widget->column = columns; +} + +static void +relayout_table (AppResizer *widget, GtkGrid * table, GList * element_list) +{ + gint row = 0, col = 0; + do + { + GtkWidget *element = GTK_WIDGET (element_list->data); + gtk_grid_attach (table, element, col, row, 1, 1); + col++; + if (col == widget->column) + { + col = 0; + row++; + } + } + while (NULL != (element_list = g_list_next (element_list))); +} + +void +app_resizer_layout_table_default (AppResizer * widget, GtkGrid * table, GList * element_list) +{ + resize_table (widget, table, widget->cur_num_cols); + relayout_table (widget, table, element_list); +} + +static void +relayout_tables (AppResizer * widget, gint num_cols) +{ + GtkGrid *table; + GList *table_list, *launcher_list; + + for (table_list = widget->cached_tables_list; table_list != NULL; + table_list = g_list_next (table_list)) + { + table = GTK_GRID (table_list->data); + launcher_list = gtk_container_get_children (GTK_CONTAINER (table)); + launcher_list = g_list_reverse (launcher_list); /* Fixme - ugly hack because table stores prepend */ + resize_table (widget, table, num_cols); + relayout_table (widget, table, launcher_list); + g_list_free (launcher_list); + } +} + +static gint +calculate_num_cols (AppResizer * resizer, gint avail_width) +{ + if (resizer->table_elements_homogeneous) + { + gint num_cols; + + if (resizer->cached_element_width == -1) + { + GtkGrid *table = GTK_GRID (resizer->cached_tables_list->data); + GList *children = gtk_container_get_children (GTK_CONTAINER (table)); + GtkWidget *table_element = GTK_WIDGET (children->data); + gint natural_width; + g_list_free (children); + + gtk_widget_get_preferred_width (table_element, NULL, &natural_width); + resizer->cached_element_width = natural_width; + resizer->cached_table_spacing = gtk_grid_get_column_spacing (table); + } + + num_cols = + (avail_width + + resizer->cached_table_spacing) / (resizer->cached_element_width + + resizer->cached_table_spacing); + return num_cols; + } + else + g_assert_not_reached (); /* Fixme - implement... */ +} + +static gint +relayout_tables_if_needed (AppResizer * widget, gint avail_width, gint current_num_cols) +{ + gint num_cols = calculate_num_cols (widget, avail_width); + if (num_cols < 1) + { + num_cols = 1; /* just horiz scroll if avail_width is less than one column */ + } + + if (current_num_cols != num_cols) + { + relayout_tables (widget, num_cols); + current_num_cols = num_cols; + } + return current_num_cols; +} + +void +app_resizer_set_table_cache (AppResizer * widget, GList * cache_list) +{ + widget->cached_tables_list = cache_list; +} + +static void +app_resizer_size_allocate (GtkWidget * widget, GtkAllocation * allocation) +{ + AppResizer *resizer = APP_RESIZER (widget); + GtkWidget *child = GTK_WIDGET (APP_RESIZER (resizer)->child); + GtkAllocation widget_allocation; + GtkRequisition child_requisition; + + static gboolean first_time = TRUE; + gint new_num_cols; + + if (first_time) + { + /* we are letting the first show be the "natural" size of the child widget so do nothing. */ + if (GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) + (*GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) (widget, allocation); + + first_time = FALSE; + gtk_widget_get_allocation (child, &widget_allocation); + gtk_layout_set_size (GTK_LAYOUT (resizer), widget_allocation.width, + widget_allocation.height); + return; + } + + gtk_widget_get_preferred_size (child, &child_requisition, NULL); + + if (!resizer->cached_tables_list) /* if everthing is currently filtered out - just return */ + { + GtkAllocation child_allocation; + + if (GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) + (*GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) (widget, allocation); + + /* We want the message to center itself and only scroll if it's bigger than the available real size. */ + child_allocation.x = 0; + child_allocation.y = 0; + child_allocation.width = MAX (allocation->width, child_requisition.width); + child_allocation.height = MAX (allocation->height, child_requisition.height); + + gtk_widget_size_allocate (child, &child_allocation); + gtk_layout_set_size (GTK_LAYOUT (resizer), child_allocation.width, + child_allocation.height); + return; + } + GtkRequisition other_requisiton; + gtk_widget_get_preferred_size (GTK_WIDGET (resizer->cached_tables_list->data), &other_requisiton, NULL); + + new_num_cols = + relayout_tables_if_needed (APP_RESIZER (resizer), allocation->width, + resizer->cur_num_cols); + if (resizer->cur_num_cols != new_num_cols) + { + GtkRequisition req; + + /* Have to do this so that it requests, and thus gets allocated, new amount */ + gtk_widget_get_preferred_size (child, &req, NULL); + + resizer->cur_num_cols = new_num_cols; + } + + if (GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) + (*GTK_WIDGET_CLASS (app_resizer_parent_class)->size_allocate) (widget, allocation); + gtk_widget_get_allocation (child, &widget_allocation); + gtk_layout_set_size (GTK_LAYOUT (resizer), widget_allocation.width, + widget_allocation.height); +} + +GtkWidget * +app_resizer_new (GtkBox * child, gint initial_num_columns, gboolean homogeneous, + AppShellData * app_data) +{ + AppResizer *widget; + + g_assert (child != NULL); + + widget = g_object_new (APP_RESIZER_TYPE, NULL); + widget->cached_element_width = -1; + widget->cur_num_cols = initial_num_columns; + widget->table_elements_homogeneous = homogeneous; + widget->setting_style = FALSE; + widget->app_data = app_data; + + g_signal_connect (widget, "draw", + G_CALLBACK (app_resizer_paint_window), + app_data); + + gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (child)); + widget->child = child; + + return GTK_WIDGET (widget); +} + +void +app_resizer_set_vadjustment_value (GtkWidget * widget, gdouble value) +{ + GtkAdjustment *adjust; + + adjust = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (widget)); + + gdouble upper = gtk_adjustment_get_upper (adjust); + gdouble page_size = gtk_adjustment_get_page_size (adjust); + if (value > upper - page_size) + { + value = upper - page_size; + } + gtk_adjustment_set_value (adjust, value); +} + +static gboolean +app_resizer_paint_window (GtkWidget * widget, cairo_t * cr, AppShellData * app_data) +{ + cairo_save(cr); + GtkStyleContext *context; + GdkRGBA *bg_rgba = NULL; + + GtkAllocation widget_allocation; + gtk_widget_get_allocation (widget, &widget_allocation); + + context = gtk_widget_get_style_context (widget); + gtk_style_context_get (context, + GTK_STATE_FLAG_NORMAL, + "background-color", &bg_rgba, + NULL); + + gdk_cairo_set_source_rgba (cr, bg_rgba); + cairo_set_line_width(cr, 1); + + cairo_rectangle(cr, widget_allocation.x, widget_allocation.y, widget_allocation.width, widget_allocation.height); + cairo_stroke_preserve(cr); + cairo_fill(cr); + + if (app_data->selected_group) + { + GtkWidget *selected_widget = GTK_WIDGET (app_data->selected_group); + GdkRGBA *rgba; + GtkAllocation selected_widget_allocation; + gtk_widget_get_allocation (selected_widget, &selected_widget_allocation); + + gtk_style_context_get (context, + GTK_STATE_FLAG_PRELIGHT, + "background-color", &rgba, + NULL); + + gdk_cairo_set_source_rgba (cr, rgba); + cairo_set_line_width(cr, 1); + cairo_rectangle(cr, selected_widget_allocation.x, selected_widget_allocation.y, selected_widget_allocation.width, selected_widget_allocation.height); + cairo_stroke_preserve(cr); + cairo_fill(cr); + gdk_rgba_free (rgba); + } + + cairo_restore(cr); + gdk_rgba_free (bg_rgba); + + return FALSE; +} diff --git a/shell/app-resizer.h b/shell/app-resizer.h new file mode 100644 index 00000000..1c65f533 --- /dev/null +++ b/shell/app-resizer.h @@ -0,0 +1,74 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __APP_RESIZER_H__ +#define __APP_RESIZER_H__ + +#include +#include + +#include "app-shell.h" + +G_BEGIN_DECLS + +#define INITIAL_NUM_COLS 3 +#define APP_RESIZER_TYPE (app_resizer_get_type ()) +#define APP_RESIZER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), APP_RESIZER_TYPE, AppResizer)) +#define APP_RESIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), APP_RESIZER_TYPE, AppResizerClass)) +#define IS_APP_RESIZER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), APP_RESIZER_TYPE)) +#define IS_APP_RESIZER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_RESIZER_TYPE)) +#define APP_RESIZER_GET_CLASS(obj) (G_TYPE_CHECK_GET_CLASS ((obj), APP_RESIZER_TYPE, AppResizerClass)) + +typedef struct _AppResizer AppResizer; +typedef struct _AppResizerClass AppResizerClass; + +struct _AppResizer +{ + GtkLayout parent; + + GtkBox *child; + GList *cached_tables_list; + gint cached_element_width; + gint cached_table_spacing; + gboolean table_elements_homogeneous; + gint cur_num_cols; + gboolean setting_style; + + guint column; + AppShellData *app_data; +}; + +struct _AppResizerClass +{ + GtkLayoutClass parent_class; +}; + +void remove_container_entries (GtkContainer * widget); + +GType app_resizer_get_type (void); +GtkWidget *app_resizer_new (GtkBox * child, gint initial_num_columns, gboolean homogeneous, + AppShellData * app_data); +void app_resizer_set_table_cache (AppResizer * widget, GList * cache_list); +void app_resizer_layout_table_default (AppResizer * widget, GtkGrid * table, GList * element_list); +void app_resizer_set_vadjustment_value (GtkWidget * widget, gdouble value); + +G_END_DECLS + +#endif /* __APP_RESIZER_H__ */ diff --git a/shell/app-shell.c b/shell/app-shell.c new file mode 100644 index 00000000..0e681c2e --- /dev/null +++ b/shell/app-shell.c @@ -0,0 +1,1448 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "app-shell.h" +#include "shell-window.h" +#include "app-resizer.h" +#include "slab-section.h" +#include "slab-mate-util.h" +#include "search-bar.h" + +#include "application-tile.h" +#include "themed-icon.h" + +#define TILE_EXEC_NAME "Tile_desktop_exec_name" +#define CC_SCHEMA "org.mate.control-center" +#define EXIT_SHELL_ON_ACTION_START "cc-exit-shell-on-action-start" +#define EXIT_SHELL_ON_ACTION_HELP "cc-exit-shell-on-action-help" +#define EXIT_SHELL_ON_ACTION_ADD_REMOVE "cc-exit-shell-on-action-add-remove" +#define EXIT_SHELL_ON_ACTION_UPGRADE_UNINSTALL "cc-exit-shell-on-action-upgrade-uninstall" + +static void create_application_category_sections (AppShellData * app_data); +static GtkWidget *create_filter_section (AppShellData * app_data, const gchar * title); +static GtkWidget *create_groups_section (AppShellData * app_data, const gchar * title); +static GtkWidget *create_actions_section (AppShellData * app_data, const gchar * title, + void (*actions_handler) (Tile *, TileEvent *, gpointer)); + +static void generate_category (const char * category, MateMenuTreeDirectory * root_dir, AppShellData * app_data, gboolean recursive); +static void generate_launchers (MateMenuTreeDirectory * root_dir, AppShellData * app_data, + CategoryData * cat_data, gboolean recursive); +static void generate_new_apps (AppShellData * app_data); +static void insert_launcher_into_category (CategoryData * cat_data, MateDesktopItem * desktop_item, + AppShellData * app_data); + +static gboolean main_keypress_callback (GtkWidget * widget, GdkEventKey * event, + AppShellData * app_data); +static gboolean main_delete_callback (GtkWidget * widget, GdkEvent * event, + AppShellData * app_data); +static void application_launcher_clear_search_bar (AppShellData * app_data); +static void launch_selected_app (AppShellData * app_data); +static void generate_potential_apps (gpointer catdata, gpointer user_data); + +static void relayout_shell (AppShellData * app_data); +static gboolean handle_filter_changed (NldSearchBar * search_bar, const char *text, + gpointer user_data); +static void handle_group_clicked (Tile * tile, TileEvent * event, gpointer user_data); +static void set_state (AppShellData * app_data, GtkWidget * widget); +static void populate_groups_section (AppShellData * app_data); +static void generate_filtered_lists (gpointer catdata, gpointer user_data); +static void show_no_results_message (AppShellData * app_data, GtkWidget * containing_vbox); +static void populate_application_category_sections (AppShellData * app_data, + GtkWidget * containing_vbox); +static void populate_application_category_section (AppShellData * app_data, SlabSection * section, + GList * launcher_list); +static void tile_activated_cb (Tile * tile, TileEvent * event, gpointer user_data); +static void handle_launcher_single_clicked (Tile * launcher, gpointer data); +static void handle_menu_action_performed (Tile * launcher, TileEvent * event, TileAction * action, + gpointer data); +static gint application_launcher_compare (gconstpointer a, gconstpointer b); +static void matemenu_tree_changed_callback (MateMenuTree * tree, gpointer user_data); +gboolean regenerate_categories (AppShellData * app_data); + +void +hide_shell (AppShellData * app_data) +{ + gtk_window_get_position (GTK_WINDOW (app_data->main_app), + &app_data->main_app_window_x, &app_data->main_app_window_y); + /* clear the search bar now so reshowing is fast and flicker free - BNC#283186 */ + application_launcher_clear_search_bar (app_data); + gtk_widget_hide (app_data->main_app); +} + +void +show_shell (AppShellData * app_data) +{ + gtk_widget_show_all (app_data->main_app); + if (!app_data->static_actions) + gtk_widget_hide (app_data->actions_section); /* don't show unless a launcher is selected */ + + if (app_data->main_app_window_shown_once) + gtk_window_move (GTK_WINDOW (app_data->main_app), + app_data->main_app_window_x, app_data->main_app_window_y); + + /* if this is the first time shown, need to clear this handler */ + else + shell_window_clear_resize_handler (SHELL_WINDOW (app_data->shell)); + app_data->main_app_window_shown_once = TRUE; +} + +gboolean +create_main_window (AppShellData * app_data, const gchar * app_name, const gchar * title, + const gchar * window_icon, gint width, gint height, gboolean hidden) +{ + GtkWidget *main_app = gtk_window_new (GTK_WINDOW_TOPLEVEL); + app_data->main_app = main_app; + gtk_widget_set_name (main_app, app_name); + gtk_window_set_title (GTK_WINDOW (main_app), title); + gtk_window_set_default_size(GTK_WINDOW(main_app), width, height); + gtk_window_set_icon_name (GTK_WINDOW (main_app), window_icon); + gtk_container_add (GTK_CONTAINER (main_app), app_data->shell); + + g_signal_connect (main_app, "delete-event", G_CALLBACK (main_delete_callback), app_data); + g_signal_connect (main_app, "key-press-event", G_CALLBACK (main_keypress_callback), + app_data); + + gtk_window_set_position (GTK_WINDOW (app_data->main_app), GTK_WIN_POS_CENTER); + if (!hidden) + show_shell (app_data); + + return TRUE; +} + +static void +generate_potential_apps (gpointer catdata, gpointer user_data) +{ + GHashTable *app_hash = (GHashTable *) user_data; + CategoryData *data = (CategoryData *) catdata; + gchar *uri; + + GList *launcher_list = data->filtered_launcher_list; + + while (launcher_list) + { + g_object_get (launcher_list->data, "tile-uri", &uri, NULL); + /* eliminate dups of same app in multiple categories */ + if (!g_hash_table_lookup (app_hash, uri)) + g_hash_table_insert (app_hash, uri, launcher_list->data); + else + g_free (uri); + launcher_list = g_list_next (launcher_list); + } +} + +static gboolean +return_first_entry (gpointer key, gpointer value, gpointer unused) +{ + return TRUE; /*better way to pull an entry out ? */ +} + +static void +launch_selected_app (AppShellData * app_data) +{ + GHashTable *app_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + guint num_apps; + + g_list_foreach (app_data->categories_list, generate_potential_apps, app_hash); + num_apps = g_hash_table_size (app_hash); + if (num_apps == 1) + { + ApplicationTile *launcher = + APPLICATION_TILE (g_hash_table_find (app_hash, return_first_entry, NULL)); + g_hash_table_destroy (app_hash); + handle_launcher_single_clicked (TILE (launcher), app_data); + return; + } + + g_hash_table_destroy (app_hash); +} + +static gboolean +main_keypress_callback (GtkWidget * widget, GdkEventKey * event, AppShellData * app_data) +{ + GApplication *app; + + if (event->keyval == GDK_KEY_Return) + { + SlabSection *section = SLAB_SECTION (app_data->filter_section); + NldSearchBar *search_bar; + + /* Make sure our implementation has not changed */ + g_assert (NLD_IS_SEARCH_BAR (section->contents)); + search_bar = NLD_SEARCH_BAR (section->contents); + if (nld_search_bar_has_focus (search_bar)) + { + launch_selected_app (app_data); + return TRUE; + } + } + + /* quit on ESC or Ctl-W or Ctl-Q */ + if (event->keyval == GDK_KEY_Escape || + ((event->keyval == GDK_KEY_w || event->keyval == GDK_KEY_W) && (event->state & GDK_CONTROL_MASK)) || + ((event->keyval == GDK_KEY_q || event->keyval == GDK_KEY_Q) && (event->state & GDK_CONTROL_MASK))) + { + if (app_data->exit_on_close) + { + app=g_application_get_default(); + g_application_quit(app); + } + else + hide_shell (app_data); + + return TRUE; + } + return FALSE; +} + +static gboolean +main_delete_callback (GtkWidget * widget, GdkEvent * event, AppShellData * app_data) +{ + GApplication *app; + + if (app_data->exit_on_close) + { + app=g_application_get_default(); + g_application_quit(app); + return FALSE; + } + + hide_shell (app_data); + return TRUE; /* stop the processing of this event */ +} + +void +layout_shell (AppShellData * app_data, const gchar * filter_title, const gchar * groups_title, + const gchar * actions_title, GSList * actions, + void (*actions_handler) (Tile *, TileEvent *, gpointer)) +{ + GtkWidget *filter_section; + GtkWidget *groups_section; + GtkWidget *actions_section; + + GtkWidget *left_vbox; + GtkWidget *right_vbox; + gint num_cols; + + GtkWidget *sw; + GtkAdjustment *adjustment; + + app_data->shell = shell_window_new (app_data); + app_data->static_actions = actions; + + right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + + num_cols = SIZING_SCREEN_WIDTH_LARGE_NUMCOLS; + + GdkRectangle geometry = {0}; + + GdkDisplay *display; + GdkMonitor *monitor; + + display= gdk_screen_get_display (gdk_screen_get_default ()); + monitor = gdk_display_get_monitor (display, 0); + gdk_monitor_get_geometry (monitor, &geometry); + + if (geometry.width <= SIZING_SCREEN_WIDTH_LARGE) + { + if (geometry.width <= SIZING_SCREEN_WIDTH_MEDIUM) + num_cols = SIZING_SCREEN_WIDTH_SMALL_NUMCOLS; + else + num_cols = SIZING_SCREEN_WIDTH_MEDIUM_NUMCOLS; + } + app_data->category_layout = + app_resizer_new (GTK_BOX (right_vbox), num_cols, TRUE, app_data); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_widget_set_vexpand (GTK_WIDGET (sw), TRUE); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (sw), app_data->category_layout); + adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw)); + g_object_set (adjustment, "step-increment", (double) 20, NULL); + + create_application_category_sections (app_data); + populate_application_category_sections (app_data, right_vbox); + app_resizer_set_table_cache (APP_RESIZER (app_data->category_layout), + app_data->cached_tables_list); + + gtk_container_set_focus_vadjustment (GTK_CONTAINER (right_vbox), + gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw))); + + left_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 15); + + filter_section = create_filter_section (app_data, filter_title); + app_data->filter_section = filter_section; + gtk_box_pack_start (GTK_BOX (left_vbox), filter_section, FALSE, FALSE, 0); + + groups_section = create_groups_section (app_data, groups_title); + app_data->groups_section = groups_section; + populate_groups_section (app_data); + gtk_box_pack_start (GTK_BOX (left_vbox), groups_section, FALSE, FALSE, 0); + + actions_section = create_actions_section (app_data, actions_title, actions_handler); + app_data->actions_section = actions_section; + gtk_box_pack_start (GTK_BOX (left_vbox), actions_section, FALSE, FALSE, 0); + + shell_window_set_contents (SHELL_WINDOW (app_data->shell), left_vbox, sw); +} + +static gboolean +relayout_shell_partial (gpointer user_data) +{ + AppShellData *app_data = (AppShellData *) user_data; + GtkBox *vbox = APP_RESIZER (app_data->category_layout)->child; + CategoryData *data; + + if (app_data->stop_incremental_relayout) + return FALSE; + + if (app_data->incremental_relayout_cat_list != NULL) + { + /* There are still categories to layout */ + data = (CategoryData *) app_data->incremental_relayout_cat_list->data; + if (data->filtered_launcher_list != NULL) + { + populate_application_category_section (app_data, data->section, + data->filtered_launcher_list); + gtk_box_pack_start (vbox, GTK_WIDGET (data->section), TRUE, TRUE, + 0); + app_data->filtered_out_everything = FALSE; + } + + app_data->incremental_relayout_cat_list = + g_list_next (app_data->incremental_relayout_cat_list); + return TRUE; + } + + /* We're done laying out the categories; finish up */ + if (app_data->filtered_out_everything) + show_no_results_message (app_data, GTK_WIDGET (vbox)); + + app_resizer_set_table_cache (APP_RESIZER (app_data->category_layout), + app_data->cached_tables_list); + populate_groups_section (app_data); + + gtk_widget_show_all (app_data->category_layout); + gdk_window_set_cursor (gtk_widget_get_window (app_data->shell), NULL); + + app_data->stop_incremental_relayout = TRUE; + return FALSE; +} + +static void +relayout_shell_incremental (AppShellData * app_data) +{ + GtkBox *vbox = APP_RESIZER (app_data->category_layout)->child; + + app_data->stop_incremental_relayout = FALSE; + app_data->filtered_out_everything = TRUE; + app_data->incremental_relayout_cat_list = app_data->categories_list; + + if (app_data->cached_tables_list) + g_list_free (app_data->cached_tables_list); + app_data->cached_tables_list = NULL; + + remove_container_entries (GTK_CONTAINER (vbox)); + + g_idle_add ((GSourceFunc) relayout_shell_partial, app_data); +} + +static void +relayout_shell (AppShellData * app_data) +{ + GtkWidget *shell = app_data->shell; + GtkBox *vbox = APP_RESIZER (app_data->category_layout)->child; + + populate_application_category_sections (app_data, GTK_WIDGET (vbox)); + app_resizer_set_table_cache (APP_RESIZER (app_data->category_layout), + app_data->cached_tables_list); + populate_groups_section (app_data); + + gtk_widget_show_all (shell); + if (!app_data->static_actions && !app_data->last_clicked_launcher) + gtk_widget_hide (app_data->actions_section); /* don't show unless a launcher is selected */ +} + +static GtkWidget * +create_actions_section (AppShellData * app_data, const gchar * title, + void (*actions_handler) (Tile *, TileEvent *, gpointer)) +{ + GtkWidget *section, *launcher; + GtkWidget *vbox; + GSList *actions; + AppAction *action; + AtkObject *a11y_cat; + + g_assert (app_data != NULL); + + section = slab_section_new (title, Style1); + g_object_ref (section); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + slab_section_set_contents (SLAB_SECTION (section), vbox); + + if (app_data->static_actions) + { + for (actions = app_data->static_actions; actions; actions = actions->next) + { + GtkWidget *header; + + action = (AppAction *) actions->data; + header = gtk_label_new (action->name); + gtk_label_set_line_wrap (GTK_LABEL (header), TRUE); + gtk_label_set_max_width_chars (GTK_LABEL (header), 0); + gtk_label_set_xalign (GTK_LABEL (header), 0.0); + launcher = nameplate_tile_new (NULL, NULL, header, NULL); + + g_object_set_data (G_OBJECT (launcher), APP_ACTION_KEY, action->item); + g_signal_connect (launcher, "tile-activated", G_CALLBACK (actions_handler), + app_data); + gtk_box_pack_start (GTK_BOX (vbox), launcher, FALSE, FALSE, 0); + + a11y_cat = gtk_widget_get_accessible (GTK_WIDGET (launcher)); + atk_object_set_name (a11y_cat, action->name); + } + } + + return section; +} + +static GtkWidget * +create_groups_section (AppShellData * app_data, const gchar * title) +{ + GtkWidget *section; + GtkWidget *vbox; + + g_assert (app_data != NULL); + + section = slab_section_new (title, Style1); + g_object_ref (section); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + slab_section_set_contents (SLAB_SECTION (section), vbox); + + return section; +} + +static void +populate_groups_section (AppShellData * app_data) +{ + SlabSection *section = SLAB_SECTION (app_data->groups_section); + GtkBox *vbox; + GList *cat_list; + + vbox = GTK_BOX (section->contents); + remove_container_entries (GTK_CONTAINER (vbox)); + + cat_list = app_data->categories_list; + do + { + CategoryData *data = (CategoryData *) cat_list->data; + if (NULL != data->filtered_launcher_list) + { + gtk_widget_set_state_flags (GTK_WIDGET (data->group_launcher), GTK_STATE_FLAG_NORMAL, FALSE); + gtk_box_pack_start (vbox, GTK_WIDGET (data->group_launcher), + FALSE, FALSE, 0); + } + } + while (NULL != (cat_list = g_list_next (cat_list))); +} + +static void +handle_group_clicked (Tile * tile, TileEvent * event, gpointer user_data) +{ + AppShellData *app_data = (AppShellData *) user_data; + GtkWidget *section = NULL; + GtkAllocation allocation; + + gint clicked_pos = + GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tile), GROUP_POSITION_NUMBER_KEY)); + + GList *cat_list = app_data->categories_list; + + gint total = 0; + do + { + CategoryData *cat_data = (CategoryData *) cat_list->data; + gint pos = + GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cat_data->group_launcher), + GROUP_POSITION_NUMBER_KEY)); + if (pos == clicked_pos) + { + section = GTK_WIDGET (cat_data->section); + break; + } + + if (NULL != cat_data->filtered_launcher_list) + { + gtk_widget_get_allocation (GTK_WIDGET (cat_data->section), &allocation); + total += allocation.height; + } + } + while (NULL != (cat_list = g_list_next (cat_list))); + + g_assert (section != NULL); + set_state (app_data, section); + + app_resizer_set_vadjustment_value (app_data->category_layout, total); +} + +static void +set_state (AppShellData * app_data, GtkWidget * widget) +{ + if (app_data->selected_group) + { + slab_section_set_selected (app_data->selected_group, FALSE); + app_data->selected_group = NULL; + } + + if (widget) + { + app_data->selected_group = SLAB_SECTION (widget); + slab_section_set_selected (SLAB_SECTION (widget), TRUE); + } + gtk_widget_queue_draw (app_data->shell); +} + +static GtkWidget * +create_filter_section (AppShellData * app_data, const gchar * title) +{ + GtkWidget *section; + + GtkWidget *search_bar; + + section = slab_section_new (title, Style1); + g_object_ref (section); + + search_bar = nld_search_bar_new (); + nld_search_bar_set_search_timeout (NLD_SEARCH_BAR (search_bar), 0); + slab_section_set_contents (SLAB_SECTION (section), search_bar); + + g_signal_connect (search_bar, "search", + G_CALLBACK (handle_filter_changed), + app_data); + + return section; +} + +static gboolean +handle_filter_changed_delayed (gpointer user_data) +{ + AppShellData *app_data = (AppShellData *) user_data; + + g_list_foreach (app_data->categories_list, generate_filtered_lists, + (gpointer) app_data->filter_string); + app_data->last_clicked_launcher = NULL; + + /* showing the updates incremtally is very visually distracting. Much worse than just blanking until + the incremental work is done and then doing one show. It would be nice to optimize this though + somehow and not even show any change but the cursor change until all the work is done. But since + we do the work incrementally in an idle loop I don't know how else besides hiding to not show + incremental updates + */ + /* gdk_window_freeze_updates(app_data->category_layout->window); */ + gtk_widget_hide (app_data->category_layout); + app_data->busy_cursor = + gdk_cursor_new_for_display (gtk_widget_get_display (app_data->shell), GDK_WATCH); + gdk_window_set_cursor (gtk_widget_get_window (app_data->shell), app_data->busy_cursor); + g_object_unref (app_data->busy_cursor); + + set_state (app_data, NULL); + app_resizer_set_vadjustment_value (app_data->category_layout, 0); + + relayout_shell_incremental (app_data); + + app_data->filter_changed_timeout = 0; + return FALSE; +} + +static gboolean +handle_filter_changed (NldSearchBar * search_bar, const char *text, gpointer data) +{ + AppShellData *app_data; + + app_data = (AppShellData *) data; + + if (app_data->filter_string) + g_free (app_data->filter_string); + app_data->filter_string = g_strdup (text); + + if (app_data->filter_changed_timeout) + g_source_remove (app_data->filter_changed_timeout); + + app_data->filter_changed_timeout = + g_timeout_add (75, handle_filter_changed_delayed, app_data); + app_data->stop_incremental_relayout = TRUE; + + return FALSE; +} + +static void +generate_filtered_lists (gpointer catdata, gpointer user_data) +{ + CategoryData *data = (CategoryData *) catdata; + + /* Fixme - everywhere you use ascii you need to fix up for multibyte */ + gchar *filter_string = g_ascii_strdown (user_data, -1); + gchar *temp1, *temp2; + GList *launcher_list = data->launcher_list; + + g_list_free (data->filtered_launcher_list); + data->filtered_launcher_list = NULL; + + do + { + ApplicationTile *launcher = APPLICATION_TILE (launcher_list->data); + const gchar *filename; + + temp1 = NULL; + temp2 = NULL; + + /* Since the filter may remove this entry from the + container it will not get a mouse out event */ + gtk_widget_set_state_flags (GTK_WIDGET (launcher), GTK_STATE_FLAG_NORMAL, FALSE); + filename = g_object_get_data (G_OBJECT (launcher), TILE_EXEC_NAME); /* do I need to free this */ + + temp1 = g_ascii_strdown (launcher->name, -1); + if (launcher->description) + temp2 = g_ascii_strdown (launcher->description, -1); + if (g_strrstr (temp1, filter_string) || (launcher->description + && g_strrstr (temp2, filter_string)) + || g_strrstr (filename, filter_string)) + { + data->filtered_launcher_list = + g_list_append (data->filtered_launcher_list, launcher); + } + if (temp1) + g_free (temp1); + if (temp2) + g_free (temp2); + } + while (NULL != (launcher_list = g_list_next (launcher_list))); + g_free (filter_string); +} + +static void +delete_old_data (AppShellData * app_data) +{ + GList *temp; + GList *cat_list; + + g_assert (app_data != NULL); + g_assert (app_data->categories_list != NULL); + + cat_list = app_data->categories_list; + + do + { + CategoryData *data = (CategoryData *) cat_list->data; + gtk_widget_destroy (GTK_WIDGET (data->section)); + gtk_widget_destroy (GTK_WIDGET (data->group_launcher)); + g_object_unref (data->section); + g_object_unref (data->group_launcher); + g_free (data->category); + + for (temp = data->launcher_list; temp; temp = g_list_next (temp)) + { + g_free (g_object_get_data (G_OBJECT (temp->data), TILE_EXEC_NAME)); + g_object_unref (temp->data); + } + + g_list_free (data->launcher_list); + g_list_free (data->filtered_launcher_list); + g_free (data); + } + while (NULL != (cat_list = g_list_next (cat_list))); + + g_list_free (app_data->categories_list); + app_data->categories_list = NULL; + app_data->selected_group = NULL; +} + +static void +create_application_category_sections (AppShellData * app_data) +{ + GList *cat_list; + AtkObject *a11y_cat; + gint pos = 0; + + g_assert (app_data != NULL); + g_assert (app_data->categories_list != NULL); /* Fixme - pop up a dialog box and then close */ + + cat_list = app_data->categories_list; + + do + { + CategoryData *data = (CategoryData *) cat_list->data; + GtkWidget *header = gtk_label_new (data->category); + gchar *markup; + GtkWidget *hbox; + GtkWidget *table; + + gtk_label_set_xalign (GTK_LABEL (header), 0.0); + data->group_launcher = TILE (nameplate_tile_new (NULL, NULL, header, NULL)); + g_object_ref (data->group_launcher); + + g_object_set_data (G_OBJECT (data->group_launcher), GROUP_POSITION_NUMBER_KEY, + GINT_TO_POINTER (pos)); + pos++; + g_signal_connect (data->group_launcher, "tile-activated", + G_CALLBACK (handle_group_clicked), app_data); + a11y_cat = gtk_widget_get_accessible (GTK_WIDGET (data->group_launcher)); + atk_object_set_name (a11y_cat, data->category); + + markup = g_markup_printf_escaped ("%s", + data->category); + data->section = SLAB_SECTION (slab_section_new_with_markup (markup, Style2)); + + /* as we filter these will be added/removed from parent container and we dont want them destroyed */ + g_object_ref (data->section); + g_free (markup); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + table = gtk_grid_new (); + gtk_grid_set_column_spacing (GTK_GRID (table), 5); + gtk_grid_set_row_spacing (GTK_GRID (table), 5); + gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 15); + slab_section_set_contents (SLAB_SECTION (data->section), hbox); + } + while (NULL != (cat_list = g_list_next (cat_list))); +} + +static void +show_no_results_message (AppShellData * app_data, GtkWidget * containing_vbox) +{ + gchar *markup; + gchar *str1; + gchar *str2; + + if (!app_data->filtered_out_everything_widget) + { + GtkWidget *image; + GtkWidget *label; + + app_data->filtered_out_everything_widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_halign (app_data->filtered_out_everything_widget, GTK_ALIGN_CENTER); + gtk_widget_set_valign (app_data->filtered_out_everything_widget, GTK_ALIGN_CENTER); + g_object_ref (app_data->filtered_out_everything_widget); + + image = themed_icon_new ("face-surprise", GTK_ICON_SIZE_DIALOG); + gtk_box_pack_start (GTK_BOX (app_data->filtered_out_everything_widget), image, FALSE, FALSE, 0); + + label = gtk_label_new (NULL); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_box_pack_start (GTK_BOX (app_data->filtered_out_everything_widget), label, TRUE, TRUE, 15); + app_data->filtered_out_everything_widget_label = GTK_LABEL (label); + } + + str1 = g_markup_printf_escaped ("%s", app_data->filter_string); + str2 = g_strdup_printf (_("Your filter \"%s\" does not match any items."), str1); + markup = g_strdup_printf ("%s\n\n%s", + _("No matches found."), str2); + gtk_label_set_text (app_data->filtered_out_everything_widget_label, markup); + gtk_label_set_use_markup (app_data->filtered_out_everything_widget_label, TRUE); + gtk_box_pack_start (GTK_BOX (containing_vbox), app_data->filtered_out_everything_widget, + TRUE, TRUE, 0); + g_free (str1); + g_free (str2); + g_free (markup); +} + +static void +populate_application_category_sections (AppShellData * app_data, GtkWidget * containing_vbox) +{ + GList *cat_list = app_data->categories_list; + gboolean filtered_out_everything = TRUE; + if (app_data->cached_tables_list) + g_list_free (app_data->cached_tables_list); + app_data->cached_tables_list = NULL; + + remove_container_entries (GTK_CONTAINER (containing_vbox)); + do + { + CategoryData *data = (CategoryData *) cat_list->data; + if (NULL != data->filtered_launcher_list) + { + populate_application_category_section (app_data, data->section, + data->filtered_launcher_list); + gtk_box_pack_start (GTK_BOX (containing_vbox), GTK_WIDGET (data->section), + TRUE, TRUE, 0); + filtered_out_everything = FALSE; + } + } + while (NULL != (cat_list = g_list_next (cat_list))); + + if (TRUE == filtered_out_everything) + show_no_results_message (app_data, containing_vbox); +} + +static void +populate_application_category_section (AppShellData * app_data, SlabSection * section, + GList * launcher_list) +{ + GtkWidget *hbox; + GtkGrid *table; + GList *children; + + hbox = GTK_WIDGET (section->contents); + + children = gtk_container_get_children (GTK_CONTAINER (hbox)); + table = children->data; + g_list_free (children); + + /* Make sure our implementation has not changed and it's still a GtkGrid */ + g_assert (GTK_IS_GRID (table)); + + app_data->cached_tables_list = g_list_append (app_data->cached_tables_list, table); + + app_resizer_layout_table_default (APP_RESIZER (app_data->category_layout), table, + launcher_list); + +} + +gboolean +regenerate_categories (AppShellData * app_data) +{ + delete_old_data (app_data); + generate_categories (app_data); + create_application_category_sections (app_data); + relayout_shell (app_data); + + return FALSE; /* remove this function from the list */ +} + +static void +matemenu_tree_changed_callback (MateMenuTree * old_tree, gpointer user_data) +{ + /* + This method only gets called on the first change (matemenu appears to ignore subsequent) until + we reget the root dir which we can't do in this method because if we do for some reason this + method then gets called multiple times for one actual change. This actually is okay because + it's probably a good idea to wait a couple seconds to regenerate the categories in case there + are multiple quick changes being made, no sense regenerating multiple times. + */ + GError *error = NULL; + AppShellData * app_data = user_data; + if (!matemenu_tree_load_sync (app_data->tree, &error)) { + g_warning ("Menu tree loading got error:%s\n", error->message); + g_object_unref (app_data->tree); + app_data->tree = NULL; + g_error_free (error); + } else { + g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 3000, (GSourceFunc) regenerate_categories, + user_data, NULL); + } +} + +AppShellData * +appshelldata_new (const gchar * menu_name, GtkIconSize icon_size, gboolean show_tile_generic_name, gboolean exit_on_close, gint new_apps_max_items) +{ + AppShellData *app_data = g_new0 (AppShellData, 1); + app_data->settings = g_settings_new (CC_SCHEMA); + app_data->menu_name = menu_name; + app_data->icon_size = icon_size; + app_data->stop_incremental_relayout = TRUE; + app_data->show_tile_generic_name = show_tile_generic_name; + app_data->exit_on_close = exit_on_close; + if (new_apps_max_items > 0) { + app_data->new_apps = g_new0 (NewAppConfig, 1); + app_data->new_apps->max_items = new_apps_max_items; + app_data->new_apps->name = _("New Applications"); + } + return app_data; +} + +void +generate_categories (AppShellData * app_data) +{ + MateMenuTreeDirectory *root_dir; + gboolean need_misc = FALSE; + MateMenuTreeIter *iter; + MateMenuTreeItemType type; + + if (!app_data->tree) + { + GError *error = NULL; + + app_data->tree = matemenu_tree_new (app_data->menu_name, MATEMENU_TREE_FLAGS_NONE); + g_signal_connect (app_data->tree, "changed", G_CALLBACK (matemenu_tree_changed_callback), app_data); + if (! matemenu_tree_load_sync (app_data->tree, &error)) { + g_warning("Menu tree loading got error:%s\n", error->message); + g_error_free(error); + g_object_unref(app_data->tree); + app_data->tree = NULL; + } + } + + if (app_data->tree != NULL) + root_dir = matemenu_tree_get_root_directory (app_data->tree); + else + root_dir = NULL; + + if ( app_data->tree == NULL || root_dir == NULL) { + GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Failure loading - %s", + app_data->menu_name); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + exit (1); /* Fixme - is there a MATE/GTK way to do this. */ + } + + iter = matemenu_tree_directory_iter (root_dir); + while ((type = matemenu_tree_iter_next (iter)) != MATEMENU_TREE_ITEM_INVALID) { + gpointer item; + const char *category; + switch (type) { + case MATEMENU_TREE_ITEM_DIRECTORY: + item = matemenu_tree_iter_get_directory (iter); + category = matemenu_tree_directory_get_name (item); + generate_category(category, item, app_data, TRUE); + matemenu_tree_item_unref (item); + break; + case MATEMENU_TREE_ITEM_ENTRY: + need_misc = TRUE; + break; + default: + break; + } + } + matemenu_tree_iter_unref(iter); + + if (need_misc) + generate_category (_("Other"), root_dir, app_data, FALSE); + + if (app_data->hash) + { + g_hash_table_destroy (app_data->hash); + app_data->hash = NULL; + } + + matemenu_tree_item_unref (root_dir); + + if (app_data->new_apps && (app_data->new_apps->max_items > 0)) + generate_new_apps (app_data); +} + +static void +generate_category (const char * category, MateMenuTreeDirectory * root_dir, AppShellData * app_data, gboolean recursive) +{ + CategoryData *data; + /* This is not needed. MateMenu already returns an ordered, non duplicate list + GList *list_entry; + list_entry = + g_list_find_custom (app_data->categories_list, category, + category_name_compare); + if (!list_entry) + { + */ + data = g_new0 (CategoryData, 1); + data->category = g_strdup (category); + app_data->categories_list = + /* use the matemenu order instead of alphabetical */ + g_list_append (app_data->categories_list, data); + /* g_list_insert_sorted (app_data->categories_list, data, category_data_compare); */ + /* + } + else + { + data = list_entry->data; + } + */ + + if (app_data->hash) /* used to eliminate dups on a per category basis. */ + g_hash_table_destroy (app_data->hash); + app_data->hash = g_hash_table_new (g_str_hash, g_str_equal); + generate_launchers (root_dir, app_data, data, recursive); +} + +static gboolean +check_specific_apps_hack (MateDesktopItem * item) +{ + static const gchar *COMMAND_LINE_LOCKDOWN_SCHEMA = "org.mate.lockdown"; + static const gchar *COMMAND_LINE_LOCKDOWN_KEY = "disable-command-line"; + static const gchar *COMMAND_LINE_LOCKDOWN_DESKTOP_CATEGORY = "TerminalEmulator"; + static gboolean got_lockdown_value = FALSE; + static gboolean command_line_lockdown; + + gchar *path; + const char *exec; + + if (!got_lockdown_value) + { + got_lockdown_value = TRUE; + GSettings *lockdown_settings; + lockdown_settings = g_settings_new (COMMAND_LINE_LOCKDOWN_SCHEMA); + command_line_lockdown = g_settings_get_boolean (lockdown_settings, COMMAND_LINE_LOCKDOWN_KEY); + g_object_unref (lockdown_settings); + } + + /* This seems like an ugly hack but it's the way it's currently done in the old control center */ + exec = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_EXEC); + + /* discard xscreensaver if mate-screensaver is installed */ + if ((exec && !strcmp (exec, "xscreensaver-demo")) + && (path = g_find_program_in_path ("mate-screensaver-preferences"))) + { + g_free (path); + return TRUE; + } + + /* discard gnome-keyring-manager if CASA is installed */ + if ((exec && !strcmp (exec, "gnome-keyring-manager")) + && (path = g_find_program_in_path ("CASAManager.sh"))) + { + g_free (path); + return TRUE; + } + + /* discard terminals if lockdown key is set */ + if (command_line_lockdown) + { + const gchar *categories = + mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_CATEGORIES); + if (g_strrstr (categories, COMMAND_LINE_LOCKDOWN_DESKTOP_CATEGORY)) + { + return TRUE; + } + } + + return FALSE; +} + +static void +generate_launchers (MateMenuTreeDirectory * root_dir, AppShellData * app_data, CategoryData * cat_data, gboolean recursive) +{ + MateDesktopItem *desktop_item; + const gchar *desktop_file; + MateMenuTreeIter *iter; + MateMenuTreeItemType type; + + iter = matemenu_tree_directory_iter (root_dir); + while ((type = matemenu_tree_iter_next (iter)) != MATEMENU_TREE_ITEM_INVALID) { + gpointer item; + switch (type) { + case MATEMENU_TREE_ITEM_DIRECTORY: + item = matemenu_tree_iter_get_directory(iter); + /* g_message ("Found sub-category %s", matemenu_tree_directory_get_name (item)); */ + if (recursive) + generate_launchers (item, app_data, cat_data, TRUE); + matemenu_tree_item_unref (item); + break; + case MATEMENU_TREE_ITEM_ENTRY: + item = matemenu_tree_iter_get_entry(iter); + /* g_message ("Found item name is:%s", matemenu_tree_entry_get_desktop_file_id(item)); */ + desktop_file = matemenu_tree_entry_get_desktop_file_path (item); + if (desktop_file) + { + if (g_hash_table_lookup (app_data->hash, desktop_file)) + { + break; /* duplicate */ + } + /* Fixme - make sure it's safe to store this without duping it. As far as I can tell it is + safe as long as I don't hang on to this anylonger than I hang on to the MateMenuTreeEntry* + which brings up another point - am I supposed to free these or does freeing the top level recurse + */ + g_hash_table_insert (app_data->hash, (gpointer) desktop_file, + (gpointer) desktop_file); + } + desktop_item = mate_desktop_item_new_from_file (desktop_file, 0, NULL); + if (!desktop_item) + { + g_critical ("Failure - mate_desktop_item_new_from_file(%s)", + desktop_file); + break; + } + if (!check_specific_apps_hack (desktop_item)) + insert_launcher_into_category (cat_data, desktop_item, app_data); + mate_desktop_item_unref (desktop_item); + matemenu_tree_item_unref (item); + break; + default: + break; + } + } + matemenu_tree_iter_unref(iter); +} + +static void +generate_new_apps (AppShellData * app_data) +{ + GHashTable *all_apps_cache = NULL; + gchar *all_apps; + GError *error = NULL; + gchar *separator = "\n"; + + gchar *all_apps_file_name; + gchar **all_apps_split; + gint x; + gboolean got_new_apps; + CategoryData *new_apps_category = NULL; + GList *categories, *launchers; + GHashTable *new_apps_dups; + + all_apps_file_name = g_build_filename (g_get_user_config_dir (), "mate", "ab-newapps.txt", NULL); + + if (!g_file_get_contents (all_apps_file_name, &all_apps, NULL, &error)) + { + /* If file does not exist, this is the first time this user has run this, create the baseline file */ + GList *categories, *launchers; + GString *gstr; + gchar *dirname; + + g_error_free (error); + error = NULL; + + /* best initial size determined by running on a couple different platforms */ + gstr = g_string_sized_new (10000); + + for (categories = app_data->categories_list; categories; categories = categories->next) + { + CategoryData *data = categories->data; + for (launchers = data->launcher_list; launchers; launchers = launchers->next) + { + Tile *tile = TILE (launchers->data); + MateDesktopItem *item = + application_tile_get_desktop_item (APPLICATION_TILE (tile)); + const gchar *uri = mate_desktop_item_get_location (item); + g_string_append (gstr, uri); + g_string_append (gstr, separator); + } + } + + dirname = g_path_get_dirname (all_apps_file_name); + g_mkdir_with_parents (dirname, 0700); /* creates if does not exist */ + g_free (dirname); + + if (!g_file_set_contents (all_apps_file_name, gstr->str, -1, &error)) + g_warning ("Error setting all apps file:%s\n", error->message); + + g_string_free (gstr, TRUE); + g_free (all_apps_file_name); + return; + } + + all_apps_cache = g_hash_table_new (g_str_hash, g_str_equal); + all_apps_split = g_strsplit (all_apps, separator, -1); + for (x = 0; all_apps_split[x]; x++) + { + g_hash_table_insert (all_apps_cache, all_apps_split[x], all_apps_split[x]); + } + + got_new_apps = FALSE; + new_apps_dups = g_hash_table_new (g_str_hash, g_str_equal); + for (categories = app_data->categories_list; categories; categories = categories->next) + { + CategoryData *cat_data = categories->data; + for (launchers = cat_data->launcher_list; launchers; launchers = launchers->next) + { + Tile *tile = TILE (launchers->data); + MateDesktopItem *item = + application_tile_get_desktop_item (APPLICATION_TILE (tile)); + const gchar *uri = mate_desktop_item_get_location (item); + if (!g_hash_table_lookup (all_apps_cache, uri)) + { + GFile *file; + GFileInfo *info; + long filetime; + + if (g_hash_table_lookup (new_apps_dups, uri)) + { + /* if a desktop file is in 2 or more top level categories, only show it once */ + break; + } + g_hash_table_insert (new_apps_dups, (gpointer) uri, (gpointer) uri); + + if (!got_new_apps) + { + new_apps_category = g_new0 (CategoryData, 1); + new_apps_category->category = + g_strdup (app_data->new_apps->name); + app_data->new_apps->garray = + g_array_sized_new (FALSE, TRUE, + sizeof (NewAppData *), + app_data->new_apps->max_items); + + /* should not need this, but a bug in glib does not actually clear the elements until you call this method */ + g_array_set_size (app_data->new_apps->garray, app_data->new_apps->max_items); + got_new_apps = TRUE; + } + + file = g_file_new_for_uri (uri); + info = g_file_query_info (file, + G_FILE_ATTRIBUTE_TIME_MODIFIED, + 0, NULL, NULL); + + if (!info) + { + g_object_unref (file); + g_warning ("Cant get vfs info for %s\n", uri); + if (new_apps_category) { + g_free (new_apps_category->category); + g_free (new_apps_category); + } + g_free (all_apps_file_name); + g_strfreev (all_apps_split); + return; + } + filetime = (long) g_file_info_get_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_MODIFIED); + g_object_unref (info); + g_object_unref (file); + + for (x = 0; x < app_data->new_apps->max_items; x++) + { + NewAppData *temp_data = (NewAppData *) + g_array_index (app_data->new_apps->garray, NewAppData *, x); + if (!temp_data || filetime > temp_data->time) /* if this slot is empty or we are newer than this slot */ + { + NewAppData *temp = g_new0 (NewAppData, 1); + temp->time = filetime; + temp->item = item; + g_array_insert_val (app_data->new_apps->garray, x, + temp); + break; + } + } + } + } + } + g_hash_table_destroy (new_apps_dups); + g_hash_table_destroy (all_apps_cache); + + if (got_new_apps) + { + for (x = 0; x < app_data->new_apps->max_items; x++) + { + NewAppData *data = + (NewAppData *) g_array_index (app_data->new_apps->garray, + NewAppData *, x); + if (data) + { + insert_launcher_into_category (new_apps_category, data->item, + app_data); + g_free (data); + } + else + break; + } + app_data->categories_list = + g_list_prepend (app_data->categories_list, new_apps_category); + + g_array_free (app_data->new_apps->garray, TRUE); + } + g_free (all_apps); + g_free (all_apps_file_name); + g_strfreev (all_apps_split); +} + +static void +insert_launcher_into_category (CategoryData * cat_data, MateDesktopItem * desktop_item, + AppShellData * app_data) +{ + GtkWidget *launcher; + static GtkSizeGroup *icon_group = NULL; + + gchar *filepath; + gchar *filename; + GtkWidget *tile_icon; + + if (!icon_group) + icon_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + launcher = + application_tile_new_full (mate_desktop_item_get_location (desktop_item), + app_data->icon_size, app_data->show_tile_generic_name); + gtk_widget_set_size_request (launcher, SIZING_TILE_WIDTH, -1); + + filepath = + g_strdup (mate_desktop_item_get_string (desktop_item, MATE_DESKTOP_ITEM_EXEC)); + g_strdelimit (filepath, " ", '\0'); /* just want the file name - no args or replacements */ + filename = g_strrstr (filepath, "/"); + if (filename) + g_stpcpy (filepath, filename + 1); + filename = g_ascii_strdown (filepath, -1); + g_free (filepath); + g_object_set_data (G_OBJECT (launcher), TILE_EXEC_NAME, filename); + + tile_icon = NAMEPLATE_TILE (launcher)->image; + gtk_size_group_add_widget (icon_group, tile_icon); + + g_signal_connect (launcher, "tile-activated", G_CALLBACK (tile_activated_cb), app_data); + + /* Note that this will handle the case of the action being launched via the side panel as + well as directly from the context menu of an individual launcher, because they both + funnel through tile_button_action_activate. + */ + g_signal_connect (launcher, "tile-action-triggered", + G_CALLBACK (handle_menu_action_performed), app_data); + + /* These will be inserted/removed from tables as the filter changes and we dont want them */ + /* destroyed when they are removed */ + g_object_ref (launcher); + + /* use alphabetical order instead of the matemenu order. We group all sub items in each top level + category together, ignoring sub menus, so we also ignore sub menu layout hints */ + cat_data->launcher_list = + /* g_list_insert (cat_data->launcher_list, launcher, -1); */ + g_list_insert_sorted (cat_data->launcher_list, launcher, application_launcher_compare); + cat_data->filtered_launcher_list = + /* g_list_insert (cat_data->filtered_launcher_list, launcher, -1); */ + g_list_insert_sorted (cat_data->filtered_launcher_list, launcher, application_launcher_compare); +} + +static gint +application_launcher_compare (gconstpointer a, gconstpointer b) +{ + ApplicationTile *launcher1 = APPLICATION_TILE (a); + ApplicationTile *launcher2 = APPLICATION_TILE (b); + + gchar *val1 = launcher1->name; + gchar *val2 = launcher2->name; + + if (val1 == NULL || val2 == NULL) + { + g_assert_not_reached (); + } + return g_ascii_strcasecmp (val1, val2); +} + +static void +application_launcher_clear_search_bar (AppShellData * app_data) +{ + SlabSection *section = SLAB_SECTION (app_data->filter_section); + NldSearchBar *search_bar; + g_assert (NLD_IS_SEARCH_BAR (section->contents)); + search_bar = NLD_SEARCH_BAR (section->contents); + nld_search_bar_set_text (search_bar, "", TRUE); +} + +/* +static gint +category_name_compare (gconstpointer a, gconstpointer b) +{ + CategoryData *data = (CategoryData *) a; + const gchar *category = b; + + if (category == NULL || data->category == NULL) + { + g_assert_not_reached (); + } + return g_ascii_strcasecmp (category, data->category); +} +*/ + +static void +tile_activated_cb (Tile * tile, TileEvent * event, gpointer user_data) +{ + switch (event->type) + { + case TILE_EVENT_ACTIVATED_SINGLE_CLICK: + case TILE_EVENT_ACTIVATED_KEYBOARD: + handle_launcher_single_clicked (tile, user_data); + break; + default: + break; + } + +} + +static void +handle_launcher_single_clicked (Tile * launcher, gpointer data) +{ + GApplication *app; + AppShellData *app_data = (AppShellData *) data; + + tile_trigger_action (launcher, launcher->actions[APPLICATION_TILE_ACTION_START]); + + if (g_settings_get_boolean (app_data->settings, EXIT_SHELL_ON_ACTION_START)) + { + if (app_data->exit_on_close) + { + app=g_application_get_default(); + g_application_quit(app); + } + else + hide_shell (app_data); + } +} + +static void +handle_menu_action_performed (Tile * launcher, TileEvent * event, TileAction * action, + gpointer data) +{ + GApplication *app; + AppShellData *app_data = (AppShellData *) data; + gchar *temp; + + temp = NULL; + if (action == launcher->actions[APPLICATION_TILE_ACTION_START]) + { + temp = EXIT_SHELL_ON_ACTION_START; + } + + else if (action == launcher->actions[APPLICATION_TILE_ACTION_HELP]) + { + temp = EXIT_SHELL_ON_ACTION_HELP; + } + + else if (action == launcher->actions[APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU] + || action == launcher->actions[APPLICATION_TILE_ACTION_UPDATE_STARTUP]) + { + temp = EXIT_SHELL_ON_ACTION_ADD_REMOVE; + } + + else if (action == launcher->actions[APPLICATION_TILE_ACTION_UPGRADE_PACKAGE] + || action == launcher->actions[APPLICATION_TILE_ACTION_UNINSTALL_PACKAGE]) + { + temp = EXIT_SHELL_ON_ACTION_UPGRADE_UNINSTALL; + } + + if (temp) + { + if (g_settings_get_boolean (app_data->settings, temp)) + { + if (app_data->exit_on_close) + { + app=g_application_get_default(); + g_application_quit(app); + } + else + hide_shell (app_data); + } + } + else + g_warning ("Unknown Action"); +} diff --git a/shell/app-shell.h b/shell/app-shell.h new file mode 100644 index 00000000..97e22b60 --- /dev/null +++ b/shell/app-shell.h @@ -0,0 +1,142 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __APP_SHELL_H__ +#define __APP_SHELL_H__ + +#include +#include +#include +#define MATEMENU_I_KNOW_THIS_IS_UNSTABLE +#include +#include + +#include "slab-section.h" +#include "tile.h" + +G_BEGIN_DECLS + +#define GROUP_POSITION_NUMBER_KEY "Unique Group Position Number" +#define APP_ACTION_KEY "Unique Application Action Key" + +/* constants for initial sizing */ +#define SIZING_SCREEN_WIDTH_LARGE 1024 +#define SIZING_SCREEN_WIDTH_MEDIUM 800 +#define SIZING_SCREEN_WIDTH_SMALL 640 +#define SIZING_SCREEN_WIDTH_LARGE_NUMCOLS 3 +#define SIZING_SCREEN_WIDTH_MEDIUM_NUMCOLS 2 +#define SIZING_SCREEN_WIDTH_SMALL_NUMCOLS 1 +#define SIZING_TILE_WIDTH 230 +#define SIZING_HEIGHT_PERCENT 0.8 + +typedef struct +{ + const gchar *name; + gint max_items; + GArray *garray; +} NewAppConfig; + +typedef struct _AppShellData +{ + GtkWidget *main_app; + gint main_app_window_x; + gint main_app_window_y; + gboolean main_app_window_shown_once; + + GtkWidget *shell; + GtkWidget *groups_section; + + GtkWidget *actions_section; + /* + NULL - if the available actions depend on the current tile selected + NON-NULL - a list of AppAction that are always shown + */ + GSList *static_actions; + + GtkWidget *filter_section; + gchar *filter_string; + GdkCursor *busy_cursor; + + GtkWidget *category_layout; + GList *categories_list; + GList *cached_tables_list; /* list of currently showing (not filtered out) tables */ + Tile *last_clicked_launcher; + SlabSection *selected_group; + GtkIconSize icon_size; + const gchar *menu_name; + NewAppConfig *new_apps; + MateMenuTree *tree; + GHashTable *hash; + + guint filter_changed_timeout; + gboolean stop_incremental_relayout; + GList *incremental_relayout_cat_list; + gboolean filtered_out_everything; + GtkWidget *filtered_out_everything_widget; + GtkLabel *filtered_out_everything_widget_label; + + gboolean show_tile_generic_name; + gboolean exit_on_close; + + GSettings *settings; +} AppShellData; + +typedef struct +{ + gchar *category; + Tile *group_launcher; + + SlabSection *section; + GList *launcher_list; + GList *filtered_launcher_list; +} CategoryData; + +typedef struct +{ + gchar *name; + MateDesktopItem *item; +} AppAction; + +typedef struct +{ + long time; + MateDesktopItem *item; +} NewAppData; + +void generate_categories (AppShellData * app_data); + +/* If new_apps_max_items is 0 then the new applications category is not created */ +AppShellData *appshelldata_new (const gchar * menu_name, + GtkIconSize icon_size, gboolean show_tile_generic_name, gboolean exit_on_close, gint new_apps_max_items); + +void layout_shell (AppShellData * app_data, const gchar * filter_title, const gchar * groups_title, + const gchar * actions_title, GSList * actions, + void (*actions_handler) (Tile *, TileEvent *, gpointer)); + +gboolean create_main_window (AppShellData * app_data, const gchar * app_name, const gchar * title, + const gchar * window_icon, gint width, gint height, gboolean hidden); + +void hide_shell (AppShellData * app_data); + +void show_shell (AppShellData * app_data); + +G_END_DECLS + +#endif /* __APP_SHELL_H__ */ diff --git a/shell/application-tile.c b/shell/application-tile.c new file mode 100644 index 00000000..ab1b4cf5 --- /dev/null +++ b/shell/application-tile.c @@ -0,0 +1,764 @@ +/* + * This file is part of libtile. + * + * Copyright (c) 2006, 2007 Novell, Inc. + * + * Libtile is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libtile 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "application-tile.h" +#include "config.h" + +#include +#include +#include +#include +#include + +#include "slab-mate-util.h" +#include "libslab-utils.h" +#include "bookmark-agent.h" +#include "themed-icon.h" + +typedef enum { + APP_IN_USER_STARTUP_DIR, + APP_NOT_IN_STARTUP_DIR, + APP_NOT_ELIGIBLE +} StartupStatus; + +static void application_tile_get_property (GObject *, guint, GValue *, GParamSpec *); +static void application_tile_set_property (GObject *, guint, const GValue *, GParamSpec *); +static void application_tile_finalize (GObject *); + +static void application_tile_setup (ApplicationTile *); + +static GtkWidget *create_header (const gchar *); +static GtkWidget *create_subheader (const gchar *); + +static void header_size_allocate_cb (GtkWidget *, GtkAllocation *, gpointer); + +static void start_trigger (Tile *, TileEvent *, TileAction *); +static void help_trigger (Tile *, TileEvent *, TileAction *); +static void user_apps_trigger (Tile *, TileEvent *, TileAction *); +static void startup_trigger (Tile *, TileEvent *, TileAction *); + +static void add_to_user_list (ApplicationTile *); +static void remove_from_user_list (ApplicationTile *); +static void add_to_startup_list (ApplicationTile *); +static void remove_from_startup_list (ApplicationTile *); + +static void update_user_list_menu_item (ApplicationTile *); +static void agent_notify_cb (GObject *, GParamSpec *, gpointer); + +static StartupStatus get_desktop_item_startup_status (MateDesktopItem *); +static void update_startup_menu_item (ApplicationTile *); + +typedef struct { + MateDesktopItem *desktop_item; + + gchar *image_id; + gboolean image_is_broken; + GtkIconSize image_size; + + gboolean show_generic_name; + StartupStatus startup_status; + + BookmarkAgent *agent; + BookmarkStoreStatus agent_status; + gboolean is_bookmarked; + gulong notify_signal_id; +} ApplicationTilePrivate; + +enum { + PROP_0, + PROP_APPLICATION_NAME, + PROP_APPLICATION_DESCRIPTION +}; + +G_DEFINE_TYPE_WITH_PRIVATE (ApplicationTile, application_tile, NAMEPLATE_TILE_TYPE) + +static void +application_tile_class_init (ApplicationTileClass *app_tile_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (app_tile_class); + + g_obj_class->get_property = application_tile_get_property; + g_obj_class->set_property = application_tile_set_property; + g_obj_class->finalize = application_tile_finalize; + + g_object_class_install_property ( + g_obj_class, PROP_APPLICATION_NAME, + g_param_spec_string ( + "application-name", "application-name", + "the name of the application", NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + g_obj_class, PROP_APPLICATION_DESCRIPTION, + g_param_spec_string ( + "application-description", "application-description", + "the name of the application", NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); +} + +GtkWidget * +application_tile_new (const gchar *desktop_item_id) +{ + return application_tile_new_full (desktop_item_id, GTK_ICON_SIZE_DND, TRUE); +} + +GtkWidget * +application_tile_new_full (const gchar *desktop_item_id, + GtkIconSize image_size, gboolean show_generic_name) +{ + ApplicationTile *this; + ApplicationTilePrivate *priv; + + const gchar *uri = NULL; + + MateDesktopItem *desktop_item; + + desktop_item = load_desktop_item_from_unknown (desktop_item_id); + + if ( + desktop_item && + mate_desktop_item_get_entry_type (desktop_item) == MATE_DESKTOP_ITEM_TYPE_APPLICATION + ) + uri = mate_desktop_item_get_location (desktop_item); + + if (! uri) { + if (desktop_item) + mate_desktop_item_unref (desktop_item); + + return NULL; + } + + this = g_object_new (APPLICATION_TILE_TYPE, "tile-uri", uri, NULL); + priv = application_tile_get_instance_private (this); + + priv->image_size = image_size; + priv->desktop_item = desktop_item; + priv->show_generic_name = show_generic_name; + + application_tile_setup (this); + + return GTK_WIDGET (this); +} + +static void +application_tile_init (ApplicationTile *tile) +{ + ApplicationTilePrivate *priv = application_tile_get_instance_private (tile); + + priv->desktop_item = NULL; + priv->image_id = NULL; + priv->image_is_broken = TRUE; + + priv->agent = NULL; + priv->agent_status = BOOKMARK_STORE_ABSENT; + priv->is_bookmarked = FALSE; + priv->notify_signal_id = 0; + + tile->name = tile->description = NULL; +} + +static void +application_tile_finalize (GObject *g_object) +{ + ApplicationTile *tile = APPLICATION_TILE (g_object); + ApplicationTilePrivate *priv = application_tile_get_instance_private (tile); + + if (tile->name) { + g_free (tile->name); + tile->name = NULL; + } + if (tile->description) { + g_free (tile->description); + tile->description = NULL; + } + + if (priv->desktop_item) { + mate_desktop_item_unref (priv->desktop_item); + priv->desktop_item = NULL; + } + if (priv->image_id) { + g_free (priv->image_id); + priv->image_id = NULL; + } + + if (priv->notify_signal_id) + g_signal_handler_disconnect (priv->agent, priv->notify_signal_id); + + g_object_unref (G_OBJECT (priv->agent)); + + G_OBJECT_CLASS (application_tile_parent_class)->finalize (g_object); +} + +static void +application_tile_get_property (GObject *g_obj, guint prop_id, GValue *value, GParamSpec *param_spec) +{ + ApplicationTile *tile = APPLICATION_TILE (g_obj); + + switch (prop_id) { + case PROP_APPLICATION_NAME: + g_value_set_string (value, tile->name); + break; + + case PROP_APPLICATION_DESCRIPTION: + g_value_set_string (value, tile->description); + break; + + default: + break; + } +} + +static void +application_tile_set_property (GObject *g_obj, guint prop_id, const GValue *value, GParamSpec *param_spec) +{ + ApplicationTile *tile = APPLICATION_TILE (g_obj); + + switch (prop_id) { + case PROP_APPLICATION_NAME: + if (tile->name) + g_free (tile->name); + tile->name = g_strdup (g_value_get_string (value)); + break; + + case PROP_APPLICATION_DESCRIPTION: + if (tile->description) + g_free (tile->description); + tile->description = g_strdup (g_value_get_string (value)); + break; + + default: + break; + } +} + +static void +application_tile_setup (ApplicationTile *this) +{ + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + + GtkWidget *image; + GtkWidget *header; + GtkWidget *subheader; + GtkMenu *context_menu; + AtkObject *accessible; + + TileAction **actions; + TileAction *action; + GtkWidget *menu_item; + GtkContainer *menu_ctnr; + + gchar *name; + gchar *desc; + + gchar *comment; + + gchar *markup; + gchar *str; + + if (! priv->desktop_item) { + priv->desktop_item = load_desktop_item_from_unknown (TILE (this)->uri); + + if (! priv->desktop_item) + return; + } + + priv->image_id = g_strdup (mate_desktop_item_get_localestring (priv->desktop_item, "Icon")); + image = themed_icon_new (priv->image_id, priv->image_size); + + gchar *filename = g_filename_from_uri (mate_desktop_item_get_location (priv->desktop_item), NULL, NULL); + GKeyFile *keyfile = g_key_file_new (); + g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, NULL); + + name = g_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, "Name", NULL, NULL); + desc = g_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, "GenericName", NULL, NULL); + comment = g_key_file_get_locale_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, "Comment", NULL, NULL); + + accessible = gtk_widget_get_accessible (GTK_WIDGET (this)); + if (name) + atk_object_set_name (accessible, name); + if (desc) + atk_object_set_description (accessible, desc); + + header = create_header (name); + + /*if no GenericName then just show and center the Name */ + if (desc && priv->show_generic_name + && (!name || strcmp(name, desc) != 0)) + subheader = create_subheader (desc); + else + subheader = NULL; + + context_menu = GTK_MENU (gtk_menu_new ()); + + g_object_set ( + G_OBJECT (this), + "nameplate-image", image, + "nameplate-header", header, + "nameplate-subheader", subheader, + "context-menu", context_menu, + "application-name", name, + "application-description", desc, + NULL); + gtk_widget_set_tooltip_text (GTK_WIDGET (this), comment); + + priv->agent = bookmark_agent_get_instance (BOOKMARK_STORE_USER_APPS); + g_object_get (G_OBJECT (priv->agent), BOOKMARK_AGENT_STORE_STATUS_PROP, & priv->agent_status, NULL); + + priv->notify_signal_id = g_signal_connect ( + G_OBJECT (priv->agent), "notify", G_CALLBACK (agent_notify_cb), this); + + priv->startup_status = get_desktop_item_startup_status (priv->desktop_item); + + actions = g_new0 (TileAction *, 6); + + TILE (this)->actions = actions; + TILE (this)->n_actions = 6; + + menu_ctnr = GTK_CONTAINER (TILE (this)->context_menu); + +/* make start action */ + + str = g_strdup_printf (_("Start %s"), this->name); + markup = g_markup_printf_escaped ("%s", str); + action = tile_action_new (TILE (this), start_trigger, markup, TILE_ACTION_OPENS_NEW_WINDOW); + actions [APPLICATION_TILE_ACTION_START] = action; + g_free (markup); + g_free (str); + + menu_item = GTK_WIDGET (tile_action_get_menu_item (action)); + + gtk_container_add (menu_ctnr, menu_item); + + TILE (this)->default_action = action; + +/* insert separator */ + + gtk_container_add (menu_ctnr, gtk_separator_menu_item_new ()); + +/* make help action */ + + if (mate_desktop_item_get_string (priv->desktop_item, "DocPath")) { + action = tile_action_new ( + TILE (this), help_trigger, _("Help"), + TILE_ACTION_OPENS_NEW_WINDOW | TILE_ACTION_OPENS_HELP); + + menu_item = GTK_WIDGET (tile_action_get_menu_item (action)); + gtk_container_add (menu_ctnr, menu_item); + } + else { + action = NULL; + } + + actions [APPLICATION_TILE_ACTION_HELP] = action; + +/* insert separator */ + + if (action != NULL) + gtk_container_add (menu_ctnr, gtk_separator_menu_item_new ()); + +/* make "add/remove to favorites" action */ + + update_user_list_menu_item (this); + +/* make "add/remove to startup" action */ + + if (priv->startup_status != APP_NOT_ELIGIBLE) { + action = tile_action_new (TILE (this), startup_trigger, NULL, 0); + actions [APPLICATION_TILE_ACTION_UPDATE_STARTUP] = action; + + update_startup_menu_item (this); + + menu_item = GTK_WIDGET (tile_action_get_menu_item (action)); + + gtk_container_add (menu_ctnr, menu_item); + } + + gtk_widget_show_all (GTK_WIDGET (TILE (this)->context_menu)); + + g_free (name); + g_free (desc); + g_free (comment); + g_free (filename); + g_key_file_unref (keyfile); +} + +static GtkWidget * +create_header (const gchar *name) +{ + GtkWidget *header; + + header = gtk_label_new (name); + gtk_label_set_line_wrap (GTK_LABEL (header), TRUE); + gtk_label_set_xalign (GTK_LABEL (header), 0.0); + + g_signal_connect ( + G_OBJECT (header), + "size-allocate", + G_CALLBACK (header_size_allocate_cb), + NULL); + + return header; +} + +static void +set_background_color (GtkWidget *widget, + GdkRGBA *rgba) +{ + gchar *css; + GtkCssProvider *provider; + + provider = gtk_css_provider_new (); + + css = g_strdup_printf ("* { background-color: %s;}", + gdk_rgba_to_string (rgba)); + gtk_css_provider_load_from_data (provider, css, -1, NULL); + g_free (css); + + gtk_style_context_add_provider (gtk_widget_get_style_context (widget), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref (provider); +} + +static GtkWidget * +create_subheader (const gchar *desc) +{ + GtkWidget *subheader; + GtkStyleContext *context; + GdkRGBA *rgba = NULL; + + subheader = gtk_label_new (desc); + gtk_label_set_ellipsize (GTK_LABEL (subheader), PANGO_ELLIPSIZE_END); + gtk_label_set_xalign (GTK_LABEL (subheader), 0.0); + context = gtk_widget_get_style_context (subheader); + gtk_style_context_get (context, + GTK_STATE_FLAG_INSENSITIVE, + "background-color", &rgba, + NULL); + + set_background_color (subheader, rgba); + + return subheader; +} + +static void +start_trigger (Tile *tile, TileEvent *event, TileAction *action) +{ + ApplicationTile *this = APPLICATION_TILE (tile); + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + open_desktop_item_exec (priv->desktop_item); +} + +static void +help_trigger (Tile *tile, TileEvent *event, TileAction *action) +{ + ApplicationTile *this = APPLICATION_TILE (tile); + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + open_desktop_item_help (priv->desktop_item); +} + +static void +user_apps_trigger (Tile *tile, TileEvent *event, TileAction *action) +{ + ApplicationTile *this = APPLICATION_TILE (tile); + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + + if (priv->is_bookmarked) + remove_from_user_list (this); + else + add_to_user_list (this); + + update_user_list_menu_item (this); +} + +static void +add_to_user_list (ApplicationTile *this) +{ + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + + BookmarkItem *item; + + item = g_new0 (BookmarkItem, 1); + item->uri = TILE (this)->uri; + item->mime_type = "application/x-desktop"; + + bookmark_agent_add_item (priv->agent, item); + g_free (item); + + priv->is_bookmarked = TRUE; +} + +static void +remove_from_user_list (ApplicationTile *this) +{ + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + + bookmark_agent_remove_item (priv->agent, TILE (this)->uri); + + priv->is_bookmarked = FALSE; +} + +static void +startup_trigger (Tile *tile, TileEvent *event, TileAction *action) +{ + ApplicationTile *this = APPLICATION_TILE (tile); + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + + switch (priv->startup_status) { + case APP_IN_USER_STARTUP_DIR: + remove_from_startup_list (this); + break; + + case APP_NOT_IN_STARTUP_DIR: + add_to_startup_list (this); + break; + + default: + break; + } + + update_startup_menu_item (this); +} + +static void +add_to_startup_list (ApplicationTile *this) +{ + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + + gchar *desktop_item_filename; + gchar *desktop_item_basename; + + gchar *startup_dir; + gchar *dst_filename; + + const gchar *src_uri; + gchar *dst_uri; + + desktop_item_filename = + g_filename_from_uri (mate_desktop_item_get_location (priv->desktop_item), NULL, + NULL); + + g_return_if_fail (desktop_item_filename != NULL); + + desktop_item_basename = g_path_get_basename (desktop_item_filename); + + startup_dir = g_build_filename (g_get_user_config_dir (), "autostart", NULL); + + if (! g_file_test (startup_dir, G_FILE_TEST_EXISTS)) + g_mkdir_with_parents (startup_dir, 0700); + + dst_filename = g_build_filename (startup_dir, desktop_item_basename, NULL); + + src_uri = mate_desktop_item_get_location (priv->desktop_item); + dst_uri = g_filename_to_uri (dst_filename, NULL, NULL); + + copy_file (src_uri, dst_uri); + priv->startup_status = APP_IN_USER_STARTUP_DIR; + + g_free (desktop_item_filename); + g_free (desktop_item_basename); + g_free (startup_dir); + g_free (dst_filename); + g_free (dst_uri); +} + +static void +remove_from_startup_list (ApplicationTile *this) +{ + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + + gchar *ditem_filename; + gchar *ditem_basename; + gchar *src_filename; + + ditem_filename = + g_filename_from_uri (mate_desktop_item_get_location (priv->desktop_item), NULL, + NULL); + + g_return_if_fail (ditem_filename != NULL); + + ditem_basename = g_path_get_basename (ditem_filename); + + src_filename = g_build_filename (g_get_user_config_dir (), "autostart", ditem_basename, NULL); + + priv->startup_status = APP_NOT_IN_STARTUP_DIR; + if (g_file_test (src_filename, G_FILE_TEST_EXISTS)) + { + if(g_file_test (src_filename, G_FILE_TEST_IS_DIR)) + g_assert_not_reached (); + g_unlink (src_filename); + } + + g_free (ditem_filename); + g_free (ditem_basename); + g_free (src_filename); +} + +MateDesktopItem * +application_tile_get_desktop_item (ApplicationTile *tile) +{ + ApplicationTilePrivate *priv; + + priv = application_tile_get_instance_private (tile); + return priv->desktop_item; +} + +static void +update_user_list_menu_item (ApplicationTile *this) +{ + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + + TileAction *action; + GtkWidget *item; + + if (priv->agent_status == BOOKMARK_STORE_ABSENT) { + if (TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU]) + g_object_unref (TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU]); + + TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU] = NULL; + } + else if (! TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU]) { + TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU] = + tile_action_new (TILE (this), user_apps_trigger, NULL, 0); + + tile_action_set_menu_item_label ( + TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU], "blah"); + + item = GTK_WIDGET (tile_action_get_menu_item ( + TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU])); + gtk_menu_shell_insert (GTK_MENU_SHELL (TILE (this)->context_menu), item, 4); + + gtk_widget_show_all (item); + } + else { + /* do nothing */ ; + } + + action = TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU]; + + if (! action) + return; + + priv->is_bookmarked = bookmark_agent_has_item (priv->agent, TILE (this)->uri); + + if (priv->is_bookmarked) + tile_action_set_menu_item_label (action, _("Remove from Favorites")); + else + tile_action_set_menu_item_label (action, _("Add to Favorites")); + + item = GTK_WIDGET (tile_action_get_menu_item (action)); + + if (! GTK_IS_MENU_ITEM (item)) + return; + + g_object_get (G_OBJECT (priv->agent), BOOKMARK_AGENT_STORE_STATUS_PROP, & priv->agent_status, NULL); + + gtk_widget_set_sensitive (item, (priv->agent_status != BOOKMARK_STORE_DEFAULT_ONLY)); +} + +static StartupStatus +get_desktop_item_startup_status (MateDesktopItem *desktop_item) +{ + gchar *filename; + gchar *basename; + + const gchar * const * global_dirs; + gchar *global_target; + gchar *user_target; + + StartupStatus retval; + gint x; + + filename = g_filename_from_uri (mate_desktop_item_get_location (desktop_item), NULL, NULL); + if (!filename) + return APP_NOT_ELIGIBLE; + basename = g_path_get_basename (filename); + + retval = APP_NOT_IN_STARTUP_DIR; + global_dirs = g_get_system_config_dirs(); + for(x=0; global_dirs[x]; x++) + { + global_target = g_build_filename (global_dirs[x], "autostart", basename, NULL); + if (g_file_test (global_target, G_FILE_TEST_EXISTS)) + { + retval = APP_NOT_ELIGIBLE; + g_free (global_target); + break; + } + g_free (global_target); + } + + /* mate-session currently checks these dirs also. see startup-programs.c */ + if (retval != APP_NOT_ELIGIBLE) + { + global_dirs = g_get_system_data_dirs(); + for(x=0; global_dirs[x]; x++) + { + global_target = g_build_filename (global_dirs[x], "mate", "autostart", basename, NULL); + if (g_file_test (global_target, G_FILE_TEST_EXISTS)) + { + retval = APP_NOT_ELIGIBLE; + g_free (global_target); + break; + } + g_free (global_target); + } + } + + if (retval != APP_NOT_ELIGIBLE) + { + user_target = g_build_filename (g_get_user_config_dir (), "autostart", basename, NULL); + if (g_file_test (user_target, G_FILE_TEST_EXISTS)) + retval = APP_IN_USER_STARTUP_DIR; + g_free (user_target); + } + + g_free (basename); + g_free (filename); + + return retval; +} + +static void +update_startup_menu_item (ApplicationTile *this) +{ + TileAction *action = TILE (this)->actions [APPLICATION_TILE_ACTION_UPDATE_STARTUP]; + ApplicationTilePrivate *priv = application_tile_get_instance_private (this); + + if (!action) + return; + + if (priv->startup_status == APP_IN_USER_STARTUP_DIR) + tile_action_set_menu_item_label (action, _("Remove from Startup Programs")); + else + tile_action_set_menu_item_label (action, _("Add to Startup Programs")); +} + +static void +header_size_allocate_cb (GtkWidget *widget, GtkAllocation *alloc, gpointer user_data) +{ + gtk_widget_set_size_request (widget, alloc->width, -1); +} + +static void +agent_notify_cb (GObject *g_obj, GParamSpec *pspec, gpointer user_data) +{ + update_user_list_menu_item (APPLICATION_TILE (user_data)); +} diff --git a/shell/application-tile.h b/shell/application-tile.h new file mode 100644 index 00000000..dea0bde9 --- /dev/null +++ b/shell/application-tile.h @@ -0,0 +1,67 @@ +/* + * This file is part of libtile. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libtile is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libtile 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __APPLICATION_TILE_H__ +#define __APPLICATION_TILE_H__ + +#include "nameplate-tile.h" + +#include +#include + +G_BEGIN_DECLS + +#define APPLICATION_TILE_TYPE (application_tile_get_type ()) +#define APPLICATION_TILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), APPLICATION_TILE_TYPE, ApplicationTile)) +#define APPLICATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), APPLICATION_TILE_TYPE, ApplicationTileClass)) +#define IS_APPLICATION_TILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), APPLICATION_TILE_TYPE)) +#define IS_APPLICATION_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), APPLICATION_TILE_TYPE)) +#define APPLICATION_TILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), APPLICATION_TILE_TYPE, ApplicationTileClass)) +#define APPLICATION_TILE_ACTION_START 0 +#define APPLICATION_TILE_ACTION_HELP 1 +#define APPLICATION_TILE_ACTION_UPDATE_MAIN_MENU 2 +#define APPLICATION_TILE_ACTION_UPDATE_STARTUP 3 +#define APPLICATION_TILE_ACTION_UPGRADE_PACKAGE 4 +#define APPLICATION_TILE_ACTION_UNINSTALL_PACKAGE 5 + +typedef struct +{ + NameplateTile nameplate_tile; + + gchar *name; + gchar *description; +} ApplicationTile; + +typedef struct +{ + NameplateTileClass nameplate_tile_class; +} ApplicationTileClass; + +GType application_tile_get_type (void); + +GtkWidget *application_tile_new (const gchar * desktop_item_id); +GtkWidget *application_tile_new_full (const gchar * desktop_item_id, + GtkIconSize icon_size, gboolean show_generic_name); + +MateDesktopItem *application_tile_get_desktop_item (ApplicationTile * tile); + +G_END_DECLS + +#endif /* __APPLICATION_TILE_H__ */ diff --git a/shell/bookmark-agent.c b/shell/bookmark-agent.c new file mode 100644 index 00000000..0f5f1bee --- /dev/null +++ b/shell/bookmark-agent.c @@ -0,0 +1,1244 @@ +/* + * This file is part of the Main Menu. + * + * Copyright (c) 2007 Novell, Inc. + * + * The Main Menu 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 2 of the License, or (at your option) + * any later version. + * + * The Main Menu 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 General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * the Main Menu; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "bookmark-agent.h" + +#ifdef HAVE_CONFIG_H +# include +#else +# define PACKAGE "mate-main-menu" +#endif + +#include + +#include +#include +#include +#include +#include + +#include "libslab-utils.h" + +#define USER_APPS_STORE_FILE_NAME "applications.xbel" +#define USER_DOCS_STORE_FILE_NAME "documents.xbel" +#define USER_DIRS_STORE_FILE_NAME "places.xbel" +#define SYSTEM_STORE_FILE_NAME "system-items.xbel" +#define CALC_TEMPLATE_FILE_NAME "empty.ots" +#define WRITER_TEMPLATE_FILE_NAME "empty.ott" + +#define GTK_BOOKMARKS_FILE "bookmarks" + +#define TYPE_IS_RECENT(type) ((type) == BOOKMARK_STORE_RECENT_APPS || (type) == BOOKMARK_STORE_RECENT_DOCS) + +typedef struct { + BookmarkStoreType type; + + BookmarkItem **items; + gint n_items; + BookmarkStoreStatus status; + + GBookmarkFile *store; + gboolean needs_sync; + + gchar *store_path; + gchar *user_store_path; + gboolean user_modifiable; + gboolean reorderable; + const gchar *store_filename; + + GFileMonitor *store_monitor; + GFileMonitor *user_store_monitor; + + void (* update_path) (BookmarkAgent *); + void (* load_store) (BookmarkAgent *); + void (* save_store) (BookmarkAgent *); + void (* create_item) (BookmarkAgent *, const gchar *); + + gchar *gtk_store_path; + GFileMonitor *gtk_store_monitor; +} BookmarkAgentPrivate; + +enum { + PROP_0, + PROP_ITEMS, + PROP_STATUS +}; + +static BookmarkAgent *instances [BOOKMARK_STORE_N_TYPES]; + +static BookmarkAgentClass *bookmark_agent_parent_class = NULL; + +static void bookmark_agent_base_init (BookmarkAgentClass *); +static void bookmark_agent_class_init (BookmarkAgentClass *); +static void bookmark_agent_init (BookmarkAgent *); +static BookmarkAgent *bookmark_agent_new (BookmarkStoreType ); + +static void get_property (GObject *, guint, GValue *, GParamSpec *); +static void set_property (GObject *, guint, const GValue *, GParamSpec *); +static void finalize (GObject *); + +static void update_agent (BookmarkAgent *); +static void update_items (BookmarkAgent *); +static void save_store (BookmarkAgent *); +static gint get_rank (BookmarkAgent *, const gchar *); +static void set_rank (BookmarkAgent *, const gchar *, gint); + +static void load_xbel_store (BookmarkAgent *); +static void load_places_store (BookmarkAgent *); +static void update_user_spec_path (BookmarkAgent *); +static void save_xbel_store (BookmarkAgent *); +static void create_app_item (BookmarkAgent *, const gchar *); +static void create_doc_item (BookmarkAgent *, const gchar *); +static void create_dir_item (BookmarkAgent *, const gchar *); + +static void store_monitor_cb (GFileMonitor *, GFile *, GFile *, + GFileMonitorEvent, gpointer); +static void weak_destroy_cb (gpointer, GObject *); + +static gchar *find_package_data_file (const gchar *filename); + +static gint BookmarkAgent_private_offset; + +static inline gpointer bookmark_agent_get_instance_private (BookmarkAgent *this) +{ + return (G_STRUCT_MEMBER_P (this, BookmarkAgent_private_offset)); +} + +GType +bookmark_agent_get_type () +{ + static GType g_define_type_id = 0; + + if (G_UNLIKELY (g_define_type_id == 0)) { + static const GTypeInfo info = { + sizeof (BookmarkAgentClass), + (GBaseInitFunc) bookmark_agent_base_init, + NULL, + (GClassInitFunc) bookmark_agent_class_init, + NULL, NULL, + sizeof (BookmarkAgent), 0, + (GInstanceInitFunc) bookmark_agent_init, + NULL + }; + + g_define_type_id = g_type_register_static ( + G_TYPE_OBJECT, "BookmarkAgent", & info, 0); + G_ADD_PRIVATE (BookmarkAgent); + } + + return g_define_type_id; +} + +gboolean +bookmark_agent_has_item (BookmarkAgent *this, const gchar *uri) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + return g_bookmark_file_has_item (priv->store, uri); +} + +void +bookmark_agent_add_item (BookmarkAgent *this, const BookmarkItem *item) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + if (! item) + return; + + g_return_if_fail (priv->user_modifiable); + g_return_if_fail (item->uri); + g_return_if_fail (item->mime_type); + + g_bookmark_file_set_mime_type (priv->store, item->uri, item->mime_type); + + if (item->mtime) +#if GLIB_CHECK_VERSION(2,66,0) + g_bookmark_file_set_modified_date_time (priv->store, item->uri, item->mtime); +#else + g_bookmark_file_set_modified (priv->store, item->uri, item->mtime); +#endif + + if (item->title) + g_bookmark_file_set_title (priv->store, item->uri, item->title); + + g_bookmark_file_add_application (priv->store, item->uri, item->app_name, item->app_exec); + + set_rank (this, item->uri, g_bookmark_file_get_size (priv->store) - 1); + + save_store (this); +} + +void +bookmark_agent_move_item (BookmarkAgent *this, const gchar *uri, const gchar *uri_new) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + GError *error = NULL; + + if (! TYPE_IS_RECENT (priv->type)) + return; + + gtk_recent_manager_move_item (gtk_recent_manager_get_default (), uri, uri_new, &error); + if (error) { + g_warning ("Unable to update %s with renamed file, [%s] -> [%s]: %s", + priv->store_path, uri, uri_new, error->message); + g_error_free (error); + } +} + +void +bookmark_agent_purge_items (BookmarkAgent *this) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + GError *error = NULL; + + gchar **uris = NULL; + gsize uris_len; + gint i; + g_return_if_fail (priv->user_modifiable); + + uris = g_bookmark_file_get_uris (priv->store, &uris_len); + if (TYPE_IS_RECENT (priv->type)) { + for (i = 0; i < uris_len; i++) { + gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uris [i], &error); + if (error) { + g_warning ("Unable to remove [%s] from %s: %s", + priv->store_path, uris [i], error->message); + g_error_free (error); + } + } + } else { + for (i = 0; i < uris_len; i++) { + g_bookmark_file_remove_item (priv->store, uris [i], NULL); + } + save_store (this); + } + g_strfreev (uris); +} + +void +bookmark_agent_remove_item (BookmarkAgent *this, const gchar *uri) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + gint rank; + + GError *error = NULL; + + gchar **uris = NULL; + gint rank_i; + gint i; + + g_return_if_fail (priv->user_modifiable); + + if (! bookmark_agent_has_item (this, uri)) + return; + + if (TYPE_IS_RECENT (priv->type)) { + gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uri, &error); + if (error) { + g_warning ("Unable to remove [%s] from %s: %s", priv->store_path, uri, error->message); + g_error_free (error); + } + } + else { + rank = get_rank (this, uri); + + g_bookmark_file_remove_item (priv->store, uri, NULL); + + if (rank >= 0) { + uris = g_bookmark_file_get_uris (priv->store, NULL); + + for (i = 0; uris && uris [i]; ++i) { + rank_i = get_rank (this, uris [i]); + + if (rank_i > rank) + set_rank (this, uris [i], rank_i - 1); + } + + g_strfreev (uris); + } + + save_store (this); + } +} + +void +bookmark_agent_reorder_items (BookmarkAgent *this, const gchar **uris) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gint i; + + g_return_if_fail (priv->reorderable); + + for (i = 0; uris && uris [i]; ++i) + set_rank (this, uris [i], i); + + save_store (this); +} + +#if !GLIB_CHECK_VERSION(2,66,0) +static gint +recent_item_mru_comp_func (gconstpointer a, gconstpointer b) +{ + return ((BookmarkItem *) b)->mtime - ((BookmarkItem *) a)->mtime; +} +#endif + +static GList * +make_items_from_bookmark_file (BookmarkAgent *this, GBookmarkFile *store) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + gchar **uris; + gint i; + GList *items_ordered; + + if (!store) + return NULL; + + uris = g_bookmark_file_get_uris (store, NULL); + items_ordered = NULL; + + for (i = 0; uris && uris [i]; ++i) { + gboolean include; + + if (priv->type == BOOKMARK_STORE_RECENT_APPS) + include = g_bookmark_file_has_group (store, uris [i], "recently-used-apps", NULL); + else + include = ! g_bookmark_file_get_is_private (store, uris [i], NULL); + + if (include) { + BookmarkItem *item; + + item = g_new0 (BookmarkItem, 1); + + item->uri = g_strdup (uris [i]); + item->mime_type = g_bookmark_file_get_mime_type (store, uris [i], NULL); +#if GLIB_CHECK_VERSION(2,66,0) + item->mtime = g_bookmark_file_get_modified_date_time (store, uris [i], NULL); +#else + item->mtime = g_bookmark_file_get_modified (store, uris [i], NULL); +#endif + + items_ordered = g_list_prepend (items_ordered, item); + } + } + +#if GLIB_CHECK_VERSION(2,66,0) + items_ordered = g_list_sort (items_ordered, g_date_time_compare); +#else + items_ordered = g_list_sort (items_ordered, recent_item_mru_comp_func); +#endif + g_strfreev (uris); + + return items_ordered; +} + +void +bookmark_agent_update_from_bookmark_file (BookmarkAgent *this, GBookmarkFile *store) +{ + BookmarkAgentPrivate *priv; + GList *items_ordered; + GList *node; + + g_return_if_fail (IS_BOOKMARK_AGENT (this)); + + priv = bookmark_agent_get_instance_private (this); + + items_ordered = make_items_from_bookmark_file (this, store); + + g_bookmark_file_free (priv->store); + priv->store = g_bookmark_file_new (); + + for (node = items_ordered; node; node = node->next) { + BookmarkItem *item; + + item = (BookmarkItem *) node->data; + + g_bookmark_file_set_mime_type (priv->store, item->uri, item->mime_type); + #if GLIB_CHECK_VERSION(2,66,0) + g_bookmark_file_set_modified_date_time (priv->store, item->uri, item->mtime); + #else + g_bookmark_file_set_modified (priv->store, item->uri, item->mtime); + #endif + + bookmark_item_free (item); + } + + g_list_free (items_ordered); + + update_items (this); +} + +void +bookmark_item_free (BookmarkItem *item) +{ + if (! item) + return; + + g_free (item->uri); + g_free (item->title); + g_free (item->mime_type); + g_free (item->icon); + g_free (item->app_name); + g_free (item->app_exec); + g_free (item); +} + +static void +bookmark_agent_base_init (BookmarkAgentClass *this_class) +{ + gint i; + + for (i = 0; i < BOOKMARK_STORE_N_TYPES; ++i) + instances [i] = NULL; +} + +static void +bookmark_agent_class_init (BookmarkAgentClass *this_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); + + GParamSpec *items_pspec; + GParamSpec *status_pspec; + + if (BookmarkAgent_private_offset != 0) + g_type_class_adjust_private_offset (this_class, &BookmarkAgent_private_offset); + + g_obj_class->get_property = get_property; + g_obj_class->set_property = set_property; + g_obj_class->finalize = finalize; + + items_pspec = g_param_spec_pointer ( + BOOKMARK_AGENT_ITEMS_PROP, BOOKMARK_AGENT_ITEMS_PROP, + "the null-terminated list which contains the bookmark items in this store", + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); + + status_pspec = g_param_spec_int ( + BOOKMARK_AGENT_STORE_STATUS_PROP, BOOKMARK_AGENT_STORE_STATUS_PROP, "the status of the store", + BOOKMARK_STORE_DEFAULT_ONLY, BOOKMARK_STORE_USER, BOOKMARK_STORE_DEFAULT, + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); + + g_object_class_install_property (g_obj_class, PROP_ITEMS, items_pspec); + g_object_class_install_property (g_obj_class, PROP_STATUS, status_pspec); + + bookmark_agent_parent_class = g_type_class_peek_parent (this_class); +} + +static void +bookmark_agent_init (BookmarkAgent *this) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + priv->type = -1; + + priv->items = NULL; + priv->n_items = 0; + priv->status = BOOKMARK_STORE_ABSENT; + + priv->store = NULL; + priv->needs_sync = FALSE; + + priv->store_path = NULL; + priv->user_store_path = NULL; + priv->user_modifiable = FALSE; + priv->reorderable = FALSE; + priv->store_filename = NULL; + + priv->store_monitor = NULL; + priv->user_store_monitor = NULL; + + priv->update_path = NULL; + priv->load_store = NULL; + priv->save_store = NULL; + priv->create_item = NULL; + + priv->gtk_store_path = NULL; + priv->gtk_store_monitor = NULL; +} + +static BookmarkAgent * +bookmark_agent_new (BookmarkStoreType type) +{ + BookmarkAgent *this; + BookmarkAgentPrivate *priv; + GFile *gtk_store_file; + + this = g_object_new (BOOKMARK_AGENT_TYPE, NULL); + priv = bookmark_agent_get_instance_private (this); + + priv->type = type; + priv->store = g_bookmark_file_new (); + + switch (type) { + case BOOKMARK_STORE_USER_APPS: + priv->store_filename = USER_APPS_STORE_FILE_NAME; + priv->create_item = create_app_item; + + break; + + case BOOKMARK_STORE_USER_DOCS: + priv->store_filename = USER_DOCS_STORE_FILE_NAME; + priv->create_item = create_doc_item; + + break; + + case BOOKMARK_STORE_USER_DIRS: + priv->store_filename = USER_DIRS_STORE_FILE_NAME; + priv->create_item = create_dir_item; + + priv->user_modifiable = TRUE; + priv->reorderable = FALSE; + + priv->load_store = load_places_store; + + priv->gtk_store_path = g_build_filename (g_get_user_config_dir (), + "gtk-3.0", GTK_BOOKMARKS_FILE, NULL); + gtk_store_file = g_file_new_for_path (priv->gtk_store_path); + priv->gtk_store_monitor = g_file_monitor_file (gtk_store_file, + 0, NULL, NULL); + if (priv->gtk_store_monitor) { + g_signal_connect (priv->gtk_store_monitor, "changed", + G_CALLBACK (store_monitor_cb), this); + } + + g_object_unref (gtk_store_file); + + break; + + case BOOKMARK_STORE_RECENT_APPS: + case BOOKMARK_STORE_RECENT_DOCS: + priv->user_modifiable = TRUE; + priv->reorderable = FALSE; + + priv->store_path = g_build_filename (g_get_user_data_dir (), "recently-used.xbel", NULL); + + break; + + case BOOKMARK_STORE_SYSTEM: + priv->store_filename = SYSTEM_STORE_FILE_NAME; + priv->create_item = create_app_item; + + break; + + default: + break; + } + + if ( + type == BOOKMARK_STORE_USER_APPS || type == BOOKMARK_STORE_USER_DOCS || + type == BOOKMARK_STORE_USER_DIRS || type == BOOKMARK_STORE_SYSTEM) + { + priv->user_modifiable = TRUE; + + priv->user_store_path = g_build_filename ( + g_get_user_data_dir (), PACKAGE, priv->store_filename, NULL); + + priv->update_path = update_user_spec_path; + } + + if (type == BOOKMARK_STORE_USER_APPS || type == BOOKMARK_STORE_USER_DOCS || type == BOOKMARK_STORE_SYSTEM) { + priv->reorderable = TRUE; + priv->load_store = load_xbel_store; + priv->save_store = save_xbel_store; + } + + update_agent (this); + + return this; +} + +BookmarkAgent * +bookmark_agent_get_instance (BookmarkStoreType type) +{ + g_return_val_if_fail (0 <= type, NULL); + g_return_val_if_fail (type < BOOKMARK_STORE_N_TYPES, NULL); + + if (! instances [type]) { + instances [type] = bookmark_agent_new (type); + g_object_weak_ref (G_OBJECT (instances [type]), weak_destroy_cb, GINT_TO_POINTER (type)); + } + else + g_object_ref (G_OBJECT (instances [type])); + + return instances [type]; +} + +static void +get_property (GObject *g_obj, guint prop_id, GValue *value, GParamSpec *pspec) +{ + BookmarkAgent *this = BOOKMARK_AGENT (g_obj); + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + switch (prop_id) { + case PROP_ITEMS: + g_value_set_pointer (value, priv->items); + break; + + case PROP_STATUS: + g_value_set_int (value, priv->status); + break; + } +} + +static void +set_property (GObject *g_obj, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + /* no writeable properties */ +} + +static void +finalize (GObject *g_obj) +{ + BookmarkAgent *this = BOOKMARK_AGENT (g_obj); + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gint i; + + for (i = 0; priv->items && priv->items [i]; ++i) + bookmark_item_free (priv->items [i]); + + g_free (priv->items); + g_free (priv->store_path); + g_free (priv->user_store_path); + g_free (priv->gtk_store_path); + + if (priv->store_monitor) { + g_signal_handlers_disconnect_by_func (priv->store_monitor, store_monitor_cb, this); + g_file_monitor_cancel (priv->store_monitor); + g_object_unref (priv->store_monitor); + } + + if (priv->user_store_monitor) { + g_signal_handlers_disconnect_by_func (priv->user_store_monitor, store_monitor_cb, this); + g_file_monitor_cancel (priv->user_store_monitor); + g_object_unref (priv->user_store_monitor); + } + + if (priv->gtk_store_monitor) { + g_signal_handlers_disconnect_by_func (priv->gtk_store_monitor, store_monitor_cb, this); + g_file_monitor_cancel (priv->gtk_store_monitor); + g_object_unref (priv->gtk_store_monitor); + } + + g_bookmark_file_free (priv->store); + + G_OBJECT_CLASS (bookmark_agent_parent_class)->finalize (g_obj); +} + +static void +update_agent (BookmarkAgent *this) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + if (priv->update_path) + priv->update_path (this); + + if (priv->load_store) + priv->load_store (this); + + update_items (this); +} + +static void +update_items (BookmarkAgent *this) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gchar **uris = NULL; + gchar **uris_ordered = NULL; + gsize n_uris = 0; + gint rank = -1; + gint rank_corr = -1; + gboolean needs_update = FALSE; + gboolean store_corrupted = FALSE; + gchar *new_title, *old_title; + + gint i; + + uris = g_bookmark_file_get_uris (priv->store, & n_uris); + uris_ordered = g_new0 (gchar *, n_uris + 1); + uris_ordered [n_uris] = NULL; + + for (i = 0; uris && uris [i]; ++i) { + rank = get_rank (this, uris [i]); + + if (rank < 0 || rank >= n_uris) + rank = i; + + if (uris_ordered [rank]) { + store_corrupted = TRUE; + rank_corr = rank; + + for (rank = 0; rank < n_uris; ++rank) + if (! uris_ordered [rank]) + break; + + g_warning ( + "store corruption [%s] - multiple uris with same rank (%d): [%s] [%s], moving latter to %d", + priv->store_path, rank_corr, uris_ordered [rank_corr], uris [i], rank); + } + + set_rank (this, uris [i], rank); + + uris_ordered [rank] = uris [i]; + } + + if (priv->n_items != n_uris) + needs_update = TRUE; + + for (i = 0; ! needs_update && uris_ordered && uris_ordered [i]; ++i) { + if (priv->type == BOOKMARK_STORE_USER_DIRS) { + new_title = g_bookmark_file_get_title (priv->store, uris_ordered [i], NULL); + old_title = priv->items [i]->title; + if (!new_title && !old_title) { + if (strcmp (priv->items [i]->uri, uris_ordered [i])) + needs_update = TRUE; + } + else if ((new_title && !old_title) || (!new_title && old_title)) + needs_update = TRUE; + else if (strcmp (old_title, new_title)) + needs_update = TRUE; + g_free (new_title); + } + else if (strcmp (priv->items [i]->uri, uris_ordered [i])) + needs_update = TRUE; + } + + if (needs_update) { + for (i = 0; priv->items && priv->items [i]; ++i) + bookmark_item_free (priv->items [i]); + + g_free (priv->items); + + priv->n_items = n_uris; + priv->items = g_new0 (BookmarkItem *, priv->n_items + 1); + + for (i = 0; uris_ordered && uris_ordered [i]; ++i) { + priv->items [i] = g_new0 (BookmarkItem, 1); + priv->items [i]->uri = g_strdup (uris_ordered [i]); + priv->items [i]->title = g_bookmark_file_get_title (priv->store, uris_ordered [i], NULL); + priv->items [i]->mime_type = g_bookmark_file_get_mime_type (priv->store, uris_ordered [i], NULL); + #if GLIB_CHECK_VERSION(2,66,0) + priv->items [i]->mtime = g_bookmark_file_get_modified_date_time (priv->store, uris_ordered [i], NULL); + #else + priv->items [i]->mtime = g_bookmark_file_get_modified (priv->store, uris_ordered [i], NULL); + #endif + priv->items [i]->app_name = NULL; + priv->items [i]->app_exec = NULL; + + g_bookmark_file_get_icon (priv->store, uris_ordered [i], & priv->items [i]->icon, NULL, NULL); + } + + /* Since the bookmark store for recently-used items is updated by the caller of BookmarkAgent, + * we don't emit notifications in that case. The caller will know when to update itself. + */ + if (!TYPE_IS_RECENT (priv->type)) + g_object_notify (G_OBJECT (this), BOOKMARK_AGENT_ITEMS_PROP); + } + + if (store_corrupted) + save_store (this); + + g_strfreev (uris); + g_free (uris_ordered); +} + +static void +save_store (BookmarkAgent *this) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gchar *dir; + + g_return_if_fail (priv->user_modifiable); + + priv->needs_sync = TRUE; + priv->update_path (this); + + dir = g_path_get_dirname (priv->store_path); + g_mkdir_with_parents (dir, 0700); + g_free (dir); + + priv->save_store (this); + update_items (this); +} + +static gint +get_rank (BookmarkAgent *this, const gchar *uri) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gchar **groups; + gint rank; + + gint i; + + if (! priv->reorderable) + return -1; + + groups = g_bookmark_file_get_groups (priv->store, uri, NULL, NULL); + rank = -1; + + for (i = 0; groups && groups [i]; ++i) { + if (g_str_has_prefix (groups [i], "rank-")) { + if (rank >= 0) + g_warning ( + "store corruption - multiple ranks for same uri: [%s] [%s]", + priv->store_path, uri); + + rank = atoi (& groups [i] [5]); + } + } + + g_strfreev (groups); + + return rank; +} + +static void +set_rank (BookmarkAgent *this, const gchar *uri, gint rank) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gchar **groups; + gchar *group; + + gint i; + + if (! (priv->reorderable && bookmark_agent_has_item (this, uri))) + return; + + groups = g_bookmark_file_get_groups (priv->store, uri, NULL, NULL); + + for (i = 0; groups && groups [i]; ++i) + if (g_str_has_prefix (groups [i], "rank-")) + g_bookmark_file_remove_group (priv->store, uri, groups [i], NULL); + + g_strfreev (groups); + + group = g_strdup_printf ("rank-%d", rank); + g_bookmark_file_add_group (priv->store, uri, group); + g_free (group); +} + +static void +load_xbel_store (BookmarkAgent *this) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gchar **uris = NULL; + + GError *error = NULL; + + gint i; + gboolean success; + + if (!priv->store_path) + success = FALSE; + else { + success = g_bookmark_file_load_from_file (priv->store, priv->store_path, & error); + } + + if (!success) { + g_bookmark_file_free (priv->store); + priv->store = g_bookmark_file_new (); + + if (error) { + g_debug ("Couldn't load bookmark file [%s]: %s", priv->store_path, error->message); + g_error_free (error); + } else { + g_debug ("Couldn't load bookmark file [NULL]"); + } + return; + } + + uris = g_bookmark_file_get_uris (priv->store, NULL); + + for (i = 0; uris && uris [i]; ++i) + priv->create_item (this, uris [i]); + + g_strfreev (uris); +} + +static void +load_places_store (BookmarkAgent *this) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gchar **uris; + gchar **groups; + gchar **bookmarks = NULL; + + gchar *buf, *label, *uri; + + gint i, j, bookmark_len; + + load_xbel_store (this); + + uris = g_bookmark_file_get_uris (priv->store, NULL); + + for (i = 0; uris && uris [i]; ++i) { + groups = g_bookmark_file_get_groups (priv->store, uris [i], NULL, NULL); + + for (j = 0; groups && groups [j]; ++j) { + if (! strcmp (groups [j], "gtk-bookmarks")) { + g_bookmark_file_remove_item (priv->store, uris [i], NULL); + + break; + } + } + + g_strfreev (groups); + } + + g_strfreev (uris); + + g_file_get_contents (priv->gtk_store_path, & buf, NULL, NULL); + + if (buf) { + bookmarks = g_strsplit (buf, "\n", -1); + g_free (buf); + } + + for (i = 0; bookmarks && bookmarks [i]; ++i) { + bookmark_len = strlen (bookmarks [i]); + if (bookmark_len > 0) { + label = strstr (bookmarks[i], " "); + if (label != NULL) + uri = g_strndup (bookmarks [i], bookmark_len - strlen (label)); + else + uri = bookmarks [i]; + g_bookmark_file_add_group (priv->store, uri, "gtk-bookmarks"); + priv->create_item (this, uri); + if (label != NULL) { + label++; + if (strlen (label) > 0) + g_bookmark_file_set_title (priv->store, uri, label); + g_free (uri); + } + } + } + + g_strfreev (bookmarks); +} + +static gchar * +find_package_data_file (const gchar *filename) +{ + const gchar * const *dirs = NULL; + gchar *path = NULL; + gint i; + + dirs = g_get_system_data_dirs (); + + for (i = 0; ! path && dirs && dirs [i]; ++i) { + path = g_build_filename (dirs [i], PACKAGE, filename, NULL); + + if (! g_file_test (path, G_FILE_TEST_EXISTS)) { + g_free (path); + path = NULL; + } + } + + return path; +} + +static void +update_user_spec_path (BookmarkAgent *this) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gboolean use_user_path; + gchar *path = NULL; + + BookmarkStoreStatus status; + + use_user_path = priv->user_modifiable && + (priv->needs_sync || g_file_test (priv->user_store_path, G_FILE_TEST_EXISTS)); + + if (use_user_path) + path = g_strdup (priv->user_store_path); + else + path = find_package_data_file (priv->store_filename); + + if (use_user_path) + status = BOOKMARK_STORE_USER; + else if (path && priv->user_modifiable) + status = BOOKMARK_STORE_DEFAULT; + else if (path) + status = BOOKMARK_STORE_DEFAULT_ONLY; + else + status = BOOKMARK_STORE_ABSENT; + + if (priv->status != status) { + priv->status = status; + g_object_notify (G_OBJECT (this), BOOKMARK_AGENT_STORE_STATUS_PROP); + + if (priv->user_store_monitor) { + g_file_monitor_cancel (priv->user_store_monitor); + g_object_unref (priv->user_store_monitor); + priv->user_store_monitor = NULL; + } + + if (priv->status == BOOKMARK_STORE_DEFAULT) { + GFile *user_store_file; + + user_store_file = g_file_new_for_path (priv->user_store_path); + priv->user_store_monitor = g_file_monitor_file (user_store_file, + 0, NULL, NULL); + if (priv->user_store_monitor) { + g_signal_connect (priv->user_store_monitor, "changed", + G_CALLBACK (store_monitor_cb), this); + } + + g_object_unref (user_store_file); + } + } + + if (g_strcmp0 (priv->store_path, path)) { + g_free (priv->store_path); + priv->store_path = path; + + if (priv->store_monitor) { + g_file_monitor_cancel (priv->store_monitor); + g_object_unref (priv->store_monitor); + } + + if (priv->store_path) { + GFile *store_file; + + store_file = g_file_new_for_path (priv->store_path); + priv->store_monitor = g_file_monitor_file (store_file, + 0, NULL, NULL); + if (priv->store_monitor) { + g_signal_connect (priv->store_monitor, "changed", + G_CALLBACK (store_monitor_cb), this); + } + + g_object_unref (store_file); + } + } + else + g_free (path); +} + +static void +save_xbel_store (BookmarkAgent *this) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + GError *error = NULL; + + if (g_bookmark_file_to_file (priv->store, priv->store_path, &error)) + return; + + if (error) { + g_warning ("Couldn't save bookmark file [%s]: %s", priv->store_path, error->message); + g_error_free (error); + } else { + g_warning ("Couldn't save bookmark file [%s]", priv->store_path); + } +} + +static void +create_app_item (BookmarkAgent *this, const gchar *uri) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + MateDesktopItem *ditem; + gchar *uri_new = NULL; + + ditem = libslab_mate_desktop_item_new_from_unknown_id (uri); + + if (ditem) { + uri_new = g_strdup (mate_desktop_item_get_location (ditem)); + mate_desktop_item_unref (ditem); + } + + if (! uri_new) + return; + + if (g_strcmp0 (uri, uri_new)) + g_bookmark_file_move_item (priv->store, uri, uri_new, NULL); + + g_free (uri_new); +} + +static void +create_doc_item (BookmarkAgent *this, const gchar *uri) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gchar *uri_new = NULL; + + if ((strcmp (uri, "BLANK_SPREADSHEET") == 0) || (strcmp (uri, "BLANK_DOCUMENT") == 0)) { + gchar *template = NULL; + gchar *file; + + gchar *dir = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); + if (!dir) + dir = g_build_filename (g_get_home_dir (), "Documents", NULL); + + if (strcmp (uri, "BLANK_SPREADSHEET") == 0) { + g_bookmark_file_set_title (priv->store, uri, "BLANK_SPREADSHEET"); + file = g_strconcat (_("New Spreadsheet"), ".ots", NULL); + template = find_package_data_file (CALC_TEMPLATE_FILE_NAME); + } else { + g_bookmark_file_set_title (priv->store, uri, "BLANK_DOCUMENT"); + file = g_strconcat (_("New Document"), ".ott", NULL); + template = find_package_data_file (WRITER_TEMPLATE_FILE_NAME); + } + + gchar *path = g_build_filename (dir, file, NULL); + if (!g_file_test (path, G_FILE_TEST_EXISTS)) { + g_mkdir_with_parents (dir, 0700); + + if (template != NULL) { + gchar *contents; + gsize length; + + if (g_file_get_contents (template, &contents, &length, NULL)) + g_file_set_contents (path, contents, length, NULL); + + g_free (contents); + } else { + fclose (g_fopen (path, "w")); + } + } + + uri_new = g_filename_to_uri (path, NULL, NULL); + + g_free (dir); + g_free (file); + g_free (path); + g_free (template); + } + + if (!uri_new) + return; + + if (g_strcmp0 (uri, uri_new)) + g_bookmark_file_move_item (priv->store, uri, uri_new, NULL); + + g_free (uri_new); +} + +static void +create_dir_item (BookmarkAgent *this, const gchar *uri) +{ + BookmarkAgentPrivate *priv = bookmark_agent_get_instance_private (this); + + gchar *uri_new = NULL; + gchar *path = NULL; + gchar *name = NULL; + gchar *icon = NULL; + + gchar *search_string = NULL; + + gboolean gotta_free_name = FALSE; + + if (strcmp (uri, "HOME") == 0) { + uri_new = g_filename_to_uri (g_get_home_dir (), NULL, NULL); + name = g_strdup (C_("Home folder", "Home")); + gotta_free_name = TRUE; + icon = "user-home"; + } else if (strcmp (uri, "DOCUMENTS") == 0) { + path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); + if (!path) + path = g_build_filename (g_get_home_dir (), "Documents", NULL); + name = _("Documents"); + uri_new = g_filename_to_uri (path, NULL, NULL); + } else if (strcmp (uri, "DESKTOP") == 0) { + path = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)); + if (!path) + path = g_build_filename (g_get_home_dir (), "Desktop", NULL); + name = _("Desktop"); + uri_new = g_filename_to_uri (path, NULL, NULL); + icon = "user-desktop"; + } else if (strcmp (uri, "file:///") == 0) { + icon = "drive-harddisk"; + name = _("File System"); + } else if (strcmp (uri, "network:") == 0) { + icon = "network-workgroup"; + name = _("Network Servers"); + } else if (g_str_has_prefix (uri, "x-caja-search")) { + icon = "system-search"; + + path = g_build_filename (g_get_user_data_dir (), "caja", "searches", & uri [21], NULL); + + if (g_file_test (path, G_FILE_TEST_EXISTS)) { + gchar *buf = NULL; + g_file_get_contents (path, &buf, NULL, NULL); + + gchar *tag_open_ptr = NULL; + gchar *tag_close_ptr = NULL; + + if (buf) { + tag_open_ptr = strstr (buf, ""); + tag_close_ptr = strstr (buf, ""); + } + + if (tag_open_ptr && tag_close_ptr) { + tag_close_ptr [0] = '\0'; + tag_close_ptr [0] = 'a'; + search_string = g_strdup_printf ("\"%s\"", &tag_open_ptr[6]); + } + + g_free (buf); + } + + if (search_string) { + name = search_string; + gotta_free_name = TRUE; + } else { + name = _("Search"); + } + } + + if (icon) + g_bookmark_file_set_icon (priv->store, uri, icon, "image/png"); + + if (name) + g_bookmark_file_set_title (priv->store, uri, name); + + if (uri_new && g_strcmp0 (uri, uri_new)) + g_bookmark_file_move_item (priv->store, uri, uri_new, NULL); + + if (gotta_free_name) { + g_free (name); + } + + g_free (path); + g_free (uri_new); +} + +static void +store_monitor_cb (GFileMonitor *mon, GFile *f1, GFile *f2, + GFileMonitorEvent event_type, gpointer user_data) +{ + update_agent (BOOKMARK_AGENT (user_data)); +} + +static void +weak_destroy_cb (gpointer data, GObject *g_obj) +{ + instances [GPOINTER_TO_INT (data)] = NULL; +} diff --git a/shell/bookmark-agent.h b/shell/bookmark-agent.h new file mode 100644 index 00000000..f54415bf --- /dev/null +++ b/shell/bookmark-agent.h @@ -0,0 +1,98 @@ +/* + * This file is part of the Main Menu. + * + * Copyright (c) 2007 Novell, Inc. + * + * The Main Menu 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 2 of the License, or (at your option) + * any later version. + * + * The Main Menu 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 General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * the Main Menu; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __BOOKMARK_AGENT_H__ +#define __BOOKMARK_AGENT_H__ + +#include +#include + +#if !GLIB_CHECK_VERSION(2,66,0) +#include +#endif + +G_BEGIN_DECLS + +#define BOOKMARK_AGENT_TYPE (bookmark_agent_get_type ()) +#define BOOKMARK_AGENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), BOOKMARK_AGENT_TYPE, BookmarkAgent)) +#define BOOKMARK_AGENT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), BOOKMARK_AGENT_TYPE, BookmarkAgentClass)) +#define IS_BOOKMARK_AGENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), BOOKMARK_AGENT_TYPE)) +#define IS_BOOKMARK_AGENT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), BOOKMARK_AGENT_TYPE)) +#define BOOKMARK_AGENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), BOOKMARK_AGENT_TYPE, BookmarkAgentClass)) + +#define BOOKMARK_AGENT_STORE_STATUS_PROP "store-status" +#define BOOKMARK_AGENT_ITEMS_PROP "items" + +typedef struct { + gchar *uri; + gchar *title; + gchar *mime_type; +#if GLIB_CHECK_VERSION(2,66,0) + GDateTime *mtime; +#else + time_t mtime; +#endif + gchar *icon; + gchar *app_name; + gchar *app_exec; +} BookmarkItem; + +typedef enum { + BOOKMARK_STORE_DEFAULT_ONLY, + BOOKMARK_STORE_DEFAULT, + BOOKMARK_STORE_USER, + BOOKMARK_STORE_ABSENT +} BookmarkStoreStatus; + +typedef enum { + BOOKMARK_STORE_USER_APPS = 0, + BOOKMARK_STORE_USER_DOCS = 1, + BOOKMARK_STORE_USER_DIRS = 2, + BOOKMARK_STORE_RECENT_APPS = 3, + BOOKMARK_STORE_RECENT_DOCS = 4, + BOOKMARK_STORE_SYSTEM = 5, + BOOKMARK_STORE_N_TYPES = 6 +} BookmarkStoreType; + +typedef struct { + GObject g_object; +} BookmarkAgent; + +typedef struct { + GObjectClass g_object_class; +} BookmarkAgentClass; + +GType bookmark_agent_get_type (void); + +BookmarkAgent *bookmark_agent_get_instance (BookmarkStoreType type); +gboolean bookmark_agent_has_item (BookmarkAgent *this, const gchar *uri); +void bookmark_agent_add_item (BookmarkAgent *this, const BookmarkItem *item); +void bookmark_agent_move_item (BookmarkAgent *this, const gchar *uri, const gchar *uri_new); +void bookmark_agent_remove_item (BookmarkAgent *this, const gchar *uri); +void bookmark_agent_reorder_items (BookmarkAgent *this, const gchar **uris); + +void bookmark_agent_update_from_bookmark_file (BookmarkAgent *this, GBookmarkFile *store); +void bookmark_agent_purge_items (BookmarkAgent *this); + +void bookmark_item_free (BookmarkItem *item); + +G_END_DECLS + +#endif /* __BOOKMARK_AGENT_H__ */ diff --git a/shell/control-center.c b/shell/control-center.c index 2bdc741c..f0f391c4 100644 --- a/shell/control-center.c +++ b/shell/control-center.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include "slab.h" void handle_static_action_clicked(Tile* tile, TileEvent* event, gpointer data); static GSList* get_actions_list(void); diff --git a/shell/double-click-detector.c b/shell/double-click-detector.c new file mode 100644 index 00000000..e6874d11 --- /dev/null +++ b/shell/double-click-detector.c @@ -0,0 +1,87 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006, 2007 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "double-click-detector.h" + +#include + +#include "libslab-utils.h" + +G_DEFINE_TYPE (DoubleClickDetector, double_click_detector, G_TYPE_OBJECT); + +void double_click_detector_update_click_time (DoubleClickDetector * detector, guint32 event_time); + +static void +double_click_detector_class_init (DoubleClickDetectorClass * detector_class) +{ +} + +static void +double_click_detector_init (DoubleClickDetector * detector) +{ + GtkSettings *settings; + gint click_interval; + + settings = gtk_settings_get_default (); + + g_object_get (G_OBJECT (settings), "gtk-double-click-time", &click_interval, NULL); + + detector->double_click_time = (gint32) click_interval; + detector->last_click_time = 0; +} + +DoubleClickDetector * +double_click_detector_new () +{ + return g_object_new (DOUBLE_CLICK_DETECTOR_TYPE, NULL); +} + +gboolean +double_click_detector_is_double_click (DoubleClickDetector *this, guint32 event_time, + gboolean auto_update) +{ + gint32 delta; + + if (event_time == 0) + event_time = (guint32) (g_get_monotonic_time () / 1000); /* milliseconds */ + + if (this->last_click_time == 0) { + if (auto_update) + double_click_detector_update_click_time (this, event_time); + + return FALSE; + } + + delta = (gint32) event_time - (gint32) this->last_click_time; + + if (auto_update) + double_click_detector_update_click_time (this, event_time); + + return delta < this->double_click_time; +} + +void +double_click_detector_update_click_time (DoubleClickDetector *this, guint32 event_time) +{ + if (event_time == 0) + event_time = (guint32) (g_get_monotonic_time () / 1000); /* milliseconds */ + + this->last_click_time = event_time; +} diff --git a/shell/double-click-detector.h b/shell/double-click-detector.h new file mode 100644 index 00000000..4a745d8e --- /dev/null +++ b/shell/double-click-detector.h @@ -0,0 +1,58 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __DOUBLE_CLICK_DETECTOR_H__ +#define __DOUBLE_CLICK_DETECTOR_H__ + +#include +#include + +G_BEGIN_DECLS + +#define DOUBLE_CLICK_DETECTOR_TYPE (double_click_detector_get_type ()) +#define DOUBLE_CLICK_DETECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DOUBLE_CLICK_DETECTOR_TYPE, DoubleClickDetector)) +#define DOUBLE_CLICK_DETECTOR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), DOUBLE_CLICK_DETECTOR_TYPE, DoubleClickDetectorClass)) +#define IS_DOUBLE_CLICK_DETECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DOUBLE_CLICK_DETECTOR_TYPE)) +#define IS_DOUBLE_CLICK_DETECTOR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), DOUBLE_CLICK_DETECTOR_TYPE)) +#define DOUBLE_CLICK_DETECTOR_GET_CLASS(o) (G_TYPE_CHECK_GET_CLASS ((o), DOUBLE_CLICK_DETECTOR_TYPE, DoubleClickDetectorClass)) + +typedef struct +{ + GObject parent_placeholder; + + gint32 double_click_time; + guint32 last_click_time; +} DoubleClickDetector; + +typedef struct +{ + GObjectClass parent_class; +} DoubleClickDetectorClass; + +GType double_click_detector_get_type (void); + +DoubleClickDetector *double_click_detector_new (void); + +gboolean double_click_detector_is_double_click (DoubleClickDetector * detector, guint32 event_time, + gboolean auto_update); + +G_END_DECLS + +#endif /* __DOUBLE_CLICK_DETECTOR_H__ */ diff --git a/shell/libslab-utils.c b/shell/libslab-utils.c new file mode 100644 index 00000000..5ee4d09c --- /dev/null +++ b/shell/libslab-utils.c @@ -0,0 +1,70 @@ +#include "libslab-utils.h" + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +MateDesktopItem * +libslab_mate_desktop_item_new_from_unknown_id (const gchar *id) +{ + MateDesktopItem *item; + gchar *basename; + + GError *error = NULL; + + if (! id) + return NULL; + + item = mate_desktop_item_new_from_uri (id, 0, & error); + + if (! error) + return item; + else { + g_error_free (error); + error = NULL; + } + + item = mate_desktop_item_new_from_file (id, 0, & error); + + if (! error) + return item; + else { + g_error_free (error); + error = NULL; + } + + item = mate_desktop_item_new_from_basename (id, 0, & error); + + if (! error) + return item; + else { + g_error_free (error); + error = NULL; + } + + basename = g_strrstr (id, "/"); + + if (basename) { + basename++; + + item = mate_desktop_item_new_from_basename (basename, 0, &error); + + if (! error) + return item; + else { + g_error_free (error); + error = NULL; + } + } + + return NULL; +} diff --git a/shell/libslab-utils.h b/shell/libslab-utils.h new file mode 100644 index 00000000..069ff3c7 --- /dev/null +++ b/shell/libslab-utils.h @@ -0,0 +1,14 @@ +#ifndef __LIBSLAB_UTILS_H__ +#define __LIBSLAB_UTILS_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +MateDesktopItem *libslab_mate_desktop_item_new_from_unknown_id (const gchar *id); + +G_END_DECLS + +#endif /* __LIBSLAB_UTILS_H__ */ diff --git a/shell/mate-utils.c b/shell/mate-utils.c new file mode 100644 index 00000000..e42d02c4 --- /dev/null +++ b/shell/mate-utils.c @@ -0,0 +1,82 @@ +#include "mate-utils.h" + +#include + +gboolean +load_image_by_id (GtkImage *image, GtkIconSize size, const gchar *image_id) +{ + cairo_surface_t *surface; + gint width; + gint height; + gint scale_factor; + + GtkIconTheme *icon_theme; + + gchar *id; + + gboolean icon_exists; + + if (!image_id) + return FALSE; + + id = g_strdup (image_id); + scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (image)); + + gtk_icon_size_lookup (size, &width, &height); + gtk_image_set_pixel_size (image, width); + + if (g_path_is_absolute (id)) + { + GdkPixbuf *pixbuf; + + pixbuf = gdk_pixbuf_new_from_file_at_size (id, width * scale_factor, height * scale_factor, NULL); + + icon_exists = (pixbuf != NULL); + + if (icon_exists) + { + surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL); + gtk_image_set_from_surface (image, surface); + + cairo_surface_destroy (surface); + g_object_unref (pixbuf); + } + else + gtk_image_set_from_icon_name (image, "image-missing", size); + } + else + { + if ( /* file extensions are not copesetic with loading by "name" */ + g_str_has_suffix (id, ".png") || + g_str_has_suffix (id, ".svg") || + g_str_has_suffix (id, ".xpm") + ) + + id[strlen (id) - 4] = '\0'; + + if (gtk_widget_has_screen (GTK_WIDGET (image))) + icon_theme = + gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET + (image))); + else + icon_theme = gtk_icon_theme_get_default (); + + surface = gtk_icon_theme_load_surface (icon_theme, id, + width, scale_factor, + NULL, + GTK_ICON_LOOKUP_FORCE_SIZE, + NULL); + icon_exists = (surface != NULL); + if (icon_exists) { + gtk_image_set_from_surface (image, surface); + cairo_surface_destroy (surface); + } + else + gtk_image_set_from_icon_name (image, "image-missing", size); + + } + + g_free (id); + + return icon_exists; +} diff --git a/shell/mate-utils.h b/shell/mate-utils.h new file mode 100644 index 00000000..0fa4cd3f --- /dev/null +++ b/shell/mate-utils.h @@ -0,0 +1,34 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __MATE_UTILS_H__ +#define __MATE_UTILS_H__ + +#include +#include + +G_BEGIN_DECLS + +gboolean load_image_by_id (GtkImage * image, GtkIconSize size, + const gchar * image_id); + +G_END_DECLS + +#endif /* __MATE_UTILS_H__ */ diff --git a/shell/nameplate-tile.c b/shell/nameplate-tile.c new file mode 100644 index 00000000..7d14452c --- /dev/null +++ b/shell/nameplate-tile.c @@ -0,0 +1,274 @@ +/* + * This file is part of libtile. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libtile is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libtile 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "nameplate-tile.h" + +static void nameplate_tile_get_property (GObject *, guint, GValue *, GParamSpec *); +static void nameplate_tile_set_property (GObject *, guint, const GValue *, GParamSpec *); +static GObject *nameplate_tile_constructor (GType, guint, GObjectConstructParam *); + +static void nameplate_tile_drag_begin (GtkWidget *, GdkDragContext *); + +static void nameplate_tile_setup (NameplateTile *); + +typedef struct +{ + GtkContainer *image_ctnr; + GtkContainer *header_ctnr; + GtkContainer *subheader_ctnr; +} NameplateTilePrivate; + +enum +{ + PROP_0, + PROP_NAMEPLATE_IMAGE, + PROP_NAMEPLATE_HEADER, + PROP_NAMEPLATE_SUBHEADER, +}; + +G_DEFINE_TYPE_WITH_PRIVATE (NameplateTile, nameplate_tile, TILE_TYPE) + +GtkWidget *nameplate_tile_new (const gchar * uri, GtkWidget * image, GtkWidget * header, + GtkWidget * subheader) +{ + return GTK_WIDGET ( + g_object_new (NAMEPLATE_TILE_TYPE, + "tile-uri", uri, + "nameplate-image", image, + "nameplate-header", header, + "nameplate-subheader", subheader, + NULL)); +} + +static void +nameplate_tile_class_init (NameplateTileClass * this_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (this_class); + + g_obj_class->constructor = nameplate_tile_constructor; + g_obj_class->get_property = nameplate_tile_get_property; + g_obj_class->set_property = nameplate_tile_set_property; + + widget_class->drag_begin = nameplate_tile_drag_begin; + + g_object_class_install_property (g_obj_class, PROP_NAMEPLATE_IMAGE, + g_param_spec_object ("nameplate-image", "nameplate-image", "nameplate image", + GTK_TYPE_WIDGET, G_PARAM_READWRITE)); + + g_object_class_install_property (g_obj_class, PROP_NAMEPLATE_HEADER, + g_param_spec_object ("nameplate-header", "nameplate-header", "nameplate header", + GTK_TYPE_WIDGET, G_PARAM_READWRITE)); + + g_object_class_install_property (g_obj_class, PROP_NAMEPLATE_SUBHEADER, + g_param_spec_object ("nameplate-subheader", "nameplate-subheader", + "nameplate subheader", GTK_TYPE_WIDGET, G_PARAM_READWRITE)); +} + +static void +nameplate_tile_init (NameplateTile * this) +{ +} + +static GObject * +nameplate_tile_constructor (GType type, guint n_param, GObjectConstructParam * param) +{ + GObject *g_obj = + (*G_OBJECT_CLASS (nameplate_tile_parent_class)->constructor) (type, n_param, param); + + nameplate_tile_setup (NAMEPLATE_TILE (g_obj)); + + return g_obj; +} + +static void +nameplate_tile_get_property (GObject * g_object, guint prop_id, GValue * value, + GParamSpec * param_spec) +{ + NameplateTile *np_tile = NAMEPLATE_TILE (g_object); + + switch (prop_id) + { + case PROP_NAMEPLATE_IMAGE: + g_value_set_object (value, np_tile->image); + break; + + case PROP_NAMEPLATE_HEADER: + g_value_set_object (value, np_tile->header); + break; + + case PROP_NAMEPLATE_SUBHEADER: + g_value_set_object (value, np_tile->subheader); + break; + default: + break; + } +} + +static void +nameplate_tile_set_property (GObject * g_object, guint prop_id, const GValue * value, + GParamSpec * param_spec) +{ + NameplateTile *this = NAMEPLATE_TILE (g_object); + NameplateTilePrivate *priv = nameplate_tile_get_instance_private (this); + + GObject *widget_obj = NULL; + + switch (prop_id) { + case PROP_NAMEPLATE_IMAGE: + case PROP_NAMEPLATE_HEADER: + case PROP_NAMEPLATE_SUBHEADER: + widget_obj = g_value_get_object (value); + break; + default: + break; + } + + switch (prop_id) + { + case PROP_NAMEPLATE_IMAGE: + if (GTK_IS_WIDGET (widget_obj)) + { + if (GTK_IS_WIDGET (this->image)) + gtk_widget_destroy (this->image); + + this->image = GTK_WIDGET (widget_obj); + + gtk_container_add (priv->image_ctnr, this->image); + + gtk_widget_show_all (this->image); + } + else if (GTK_IS_WIDGET (this->image)) + gtk_widget_destroy (this->image); + + break; + + case PROP_NAMEPLATE_HEADER: + if (GTK_IS_WIDGET (widget_obj)) + { + if (GTK_IS_WIDGET (this->header)) + gtk_widget_destroy (this->header); + + this->header = GTK_WIDGET (widget_obj); + + gtk_container_add (priv->header_ctnr, this->header); + + gtk_widget_show_all (this->header); + } + else if (GTK_IS_WIDGET (this->header)) + gtk_widget_destroy (this->header); + + break; + + case PROP_NAMEPLATE_SUBHEADER: + if (GTK_IS_WIDGET (widget_obj)) + { + if (GTK_IS_WIDGET (this->subheader)) + gtk_widget_destroy (this->subheader); + + this->subheader = GTK_WIDGET (widget_obj); + + gtk_container_add (priv->subheader_ctnr, this->subheader); + + gtk_widget_show_all (this->subheader); + } + else if (GTK_IS_WIDGET (this->subheader)) + gtk_widget_destroy (this->subheader); + + break; + + default: + break; + } +} + +static void +nameplate_tile_setup (NameplateTile *this) +{ + NameplateTilePrivate *priv = nameplate_tile_get_instance_private (this); + + GtkWidget *hbox; + GtkWidget *vbox; + + priv->image_ctnr = GTK_CONTAINER (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); + gtk_widget_set_valign (GTK_WIDGET (priv->image_ctnr), GTK_ALIGN_CENTER); + + priv->header_ctnr = GTK_CONTAINER (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); + + priv->subheader_ctnr = GTK_CONTAINER (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); + gtk_widget_set_halign (GTK_WIDGET (priv->subheader_ctnr), GTK_ALIGN_START); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_halign (vbox, GTK_ALIGN_FILL); + gtk_widget_set_valign (vbox, GTK_ALIGN_CENTER); + + gtk_container_add (GTK_CONTAINER (this), hbox); + gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (priv->image_ctnr), FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (priv->header_ctnr), FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (priv->subheader_ctnr), FALSE, FALSE, 0); + + if (GTK_IS_WIDGET (this->image)) + gtk_container_add (priv->image_ctnr, this->image); + + if (GTK_IS_WIDGET (this->header)) + gtk_container_add (priv->header_ctnr, this->header); + + if (GTK_IS_WIDGET (this->subheader)) + gtk_container_add (priv->subheader_ctnr, this->subheader); + + gtk_widget_set_focus_on_click (GTK_WIDGET (this), FALSE); +} + +static void +nameplate_tile_drag_begin (GtkWidget * widget, GdkDragContext * context) +{ + NameplateTile *this = NAMEPLATE_TILE (widget); + GtkImage *image; + const gchar *name; + + (*GTK_WIDGET_CLASS (nameplate_tile_parent_class)->drag_begin) (widget, context); + + if (!this->image || !GTK_IS_IMAGE (this->image)) + return; + + image = GTK_IMAGE (this->image); + + switch (gtk_image_get_storage_type (image)) + { + case GTK_IMAGE_PIXBUF: + if (gtk_image_get_pixbuf (image)) + gtk_drag_set_icon_pixbuf (context, gtk_image_get_pixbuf (image), 0, 0); + + break; + + case GTK_IMAGE_ICON_NAME: + gtk_image_get_icon_name (image, &name, NULL); + if (name) + gtk_drag_set_icon_name (context, name, 0, 0); + + break; + + default: + break; + } +} diff --git a/shell/nameplate-tile.h b/shell/nameplate-tile.h new file mode 100644 index 00000000..d51ff40f --- /dev/null +++ b/shell/nameplate-tile.h @@ -0,0 +1,57 @@ +/* + * This file is part of libtile. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libtile is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libtile 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __NAMEPLATE_TILE_H__ +#define __NAMEPLATE_TILE_H__ + +#include "tile.h" + +#include +#include + +G_BEGIN_DECLS + +#define NAMEPLATE_TILE_TYPE (nameplate_tile_get_type ()) +#define NAMEPLATE_TILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NAMEPLATE_TILE_TYPE, NameplateTile)) +#define NAMEPLATE_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), NAMEPLATE_TILE_TYPE, NameplateTileClass)) +#define IS_NAMEPLATE_TILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NAMEPLATE_TILE_TYPE)) +#define IS_NAMEPLATE_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), NAMEPLATE_TILE_TYPE)) +#define NAMEPLATE_TILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NAMEPLATE_TILE_TYPE, NameplateTileClass)) + +typedef struct { + Tile tile; + + GtkWidget *image; + GtkWidget *header; + GtkWidget *subheader; +} NameplateTile; + +typedef struct { + TileClass tile_class; +} NameplateTileClass; + +GType nameplate_tile_get_type (void); + +GtkWidget *nameplate_tile_new (const gchar * uri, GtkWidget * image, GtkWidget * header, + GtkWidget * subheader); + +G_END_DECLS + +#endif /* __NAMEPLATE_TILE_H__ */ diff --git a/shell/nld-marshal.list b/shell/nld-marshal.list new file mode 100644 index 00000000..30ba5d8d --- /dev/null +++ b/shell/nld-marshal.list @@ -0,0 +1 @@ +VOID:STRING diff --git a/shell/search-bar.c b/shell/search-bar.c new file mode 100644 index 00000000..f560f649 --- /dev/null +++ b/shell/search-bar.c @@ -0,0 +1,238 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "search-bar.h" +#include "config.h" + +#include "nld-marshal.h" + +#include + +typedef struct +{ + GtkWidget *hbox; + GtkEntry *entry; + GtkWidget *button; + + int search_timeout; + guint timeout_id; + + gboolean block_signal; +} NldSearchBarPrivate; + +static void nld_search_bar_finalize (GObject *); + +static gboolean nld_search_bar_focus (GtkWidget *, GtkDirectionType); +static void nld_search_bar_grab_focus (GtkWidget *); + +enum +{ + SEARCH, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE_WITH_PRIVATE (NldSearchBar, nld_search_bar, GTK_TYPE_BOX) + +static void emit_search (NldSearchBar * search_bar); +static void emit_search_callback (GtkWidget * widget, gpointer search_bar); + +static void nld_search_bar_class_init (NldSearchBarClass * nld_search_bar_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (nld_search_bar_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (nld_search_bar_class); + + object_class->finalize = nld_search_bar_finalize; + widget_class->focus = nld_search_bar_focus; + widget_class->grab_focus = nld_search_bar_grab_focus; + + signals[SEARCH] = + g_signal_new ("search", G_TYPE_FROM_CLASS (nld_search_bar_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NldSearchBarClass, search), + NULL, NULL, nld_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); +} + +static void +nld_search_bar_init (NldSearchBar * search_bar) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + GtkWidget *entry; + + gtk_widget_set_can_focus (GTK_WIDGET (search_bar), TRUE); + gtk_orientable_set_orientation (GTK_ORIENTABLE (search_bar), GTK_ORIENTATION_VERTICAL); + + priv->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); + gtk_box_pack_start (GTK_BOX (search_bar), priv->hbox, TRUE, FALSE, 0); + + entry = gtk_search_entry_new (); + gtk_widget_set_halign (entry, GTK_ALIGN_START); + gtk_widget_set_valign (entry, GTK_ALIGN_CENTER); + priv->entry = GTK_ENTRY (entry); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (priv->hbox), entry, TRUE, TRUE, 0); + + g_signal_connect (entry, "activate", G_CALLBACK (emit_search_callback), search_bar); + + priv->search_timeout = -1; +} + +static void +nld_search_bar_finalize (GObject * object) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (NLD_SEARCH_BAR(object)); + + if (priv->timeout_id) + g_source_remove (priv->timeout_id); + + G_OBJECT_CLASS (nld_search_bar_parent_class)->finalize (object); +} + +static gboolean +nld_search_bar_focus (GtkWidget * widget, GtkDirectionType dir) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (NLD_SEARCH_BAR(widget)); + + return gtk_widget_child_focus (priv->hbox, dir); +} + +gboolean +nld_search_bar_has_focus (NldSearchBar * search_bar) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + + return gtk_widget_has_focus (GTK_WIDGET (priv->entry)); +} + +static void +nld_search_bar_grab_focus (GtkWidget * widget) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (NLD_SEARCH_BAR(widget)); + + gtk_widget_grab_focus (GTK_WIDGET (priv->entry)); +} + +GtkWidget * +nld_search_bar_new (void) +{ + return g_object_new (NLD_TYPE_SEARCH_BAR, NULL); +} + +void +nld_search_bar_clear (NldSearchBar * search_bar) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + + priv->block_signal = TRUE; + gtk_entry_set_text (priv->entry, ""); + priv->block_signal = FALSE; +} + +static void +emit_search (NldSearchBar * search_bar) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + + if (priv->block_signal) + return; + + if (priv->timeout_id) + { + g_source_remove (priv->timeout_id); + priv->timeout_id = 0; + } + + g_signal_emit (search_bar, signals[SEARCH], 0, + nld_search_bar_get_text (search_bar)); +} + +static void +emit_search_callback (GtkWidget * widget, gpointer search_bar) +{ + emit_search (search_bar); +} + +static gboolean +search_timeout (gpointer search_bar) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + + priv->timeout_id = 0; + emit_search (search_bar); + return FALSE; +} + +static void +entry_changed (GtkWidget * entry, gpointer search_bar) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + + if (priv->search_timeout == 0) + emit_search (search_bar); + else if (priv->search_timeout > 0) + { + if (priv->timeout_id != 0) + g_source_remove (priv->timeout_id); + priv->timeout_id = + g_timeout_add (priv->search_timeout * 1000, search_timeout, search_bar); + } +} + +int +nld_search_bar_get_search_timeout (NldSearchBar * search_bar) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + + return priv->search_timeout; +} + +void +nld_search_bar_set_search_timeout (NldSearchBar * search_bar, int search_timeout) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + + if (priv->search_timeout != -1 && search_timeout == -1) + g_signal_handlers_disconnect_by_func (priv->entry, entry_changed, search_bar); + else if (search_timeout != -1) + { + g_signal_connect (priv->entry, "changed", G_CALLBACK (entry_changed), search_bar); + } + + priv->search_timeout = search_timeout; +} + +const char * +nld_search_bar_get_text (NldSearchBar * search_bar) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + + return gtk_entry_get_text (priv->entry); +} + +void +nld_search_bar_set_text (NldSearchBar * search_bar, const char *text, gboolean activate) +{ + NldSearchBarPrivate *priv = nld_search_bar_get_instance_private (search_bar); + + gtk_entry_set_text (priv->entry, text); + if (activate) + emit_search (search_bar); +} + diff --git a/shell/search-bar.h b/shell/search-bar.h new file mode 100644 index 00000000..fca5216d --- /dev/null +++ b/shell/search-bar.h @@ -0,0 +1,66 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __NLD_SEARCH_BAR_H__ +#define __NLD_SEARCH_BAR_H__ + +#include +#include + +G_BEGIN_DECLS + +#define NLD_TYPE_SEARCH_BAR (nld_search_bar_get_type ()) +#define NLD_SEARCH_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NLD_TYPE_SEARCH_BAR, NldSearchBar)) +#define NLD_SEARCH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NLD_TYPE_SEARCH_BAR, NldSearchBarClass)) +#define NLD_IS_SEARCH_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NLD_TYPE_SEARCH_BAR)) +#define NLD_IS_SEARCH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NLD_TYPE_SEARCH_BAR)) +#define NLD_SEARCH_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NLD_TYPE_SEARCH_BAR, NldSearchBarClass)) + +typedef struct +{ + GtkBox parent; +} NldSearchBar; + +typedef struct +{ + GtkBoxClass parent_class; + + void (*search) (NldSearchBar *, const char *text); +} NldSearchBarClass; + +GType nld_search_bar_get_type (void); + +GtkWidget *nld_search_bar_new (void); + +void nld_search_bar_clear (NldSearchBar * search_bar); +gboolean nld_search_bar_has_focus (NldSearchBar * search_bar); + +gboolean nld_search_bar_get_show_button (NldSearchBar * search_bar); +void nld_search_bar_set_show_button (NldSearchBar * search_bar, gboolean show_button); + +int nld_search_bar_get_search_timeout (NldSearchBar * search_bar); +void nld_search_bar_set_search_timeout (NldSearchBar * search_bar, int search_timeout); + +const char *nld_search_bar_get_text (NldSearchBar * search_bar); +void nld_search_bar_set_text (NldSearchBar * search_bar, const char *text, gboolean activate); + +G_END_DECLS + +#endif /* __NLD_SEARCH_BAR_H__ */ diff --git a/shell/shell-window.c b/shell/shell-window.c new file mode 100644 index 00000000..19f3c5e8 --- /dev/null +++ b/shell/shell-window.c @@ -0,0 +1,83 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "shell-window.h" + +#include +#include + +#include "app-resizer.h" + +G_DEFINE_TYPE (ShellWindow, shell_window, GTK_TYPE_FRAME); + +static void +shell_window_class_init (ShellWindowClass * klass) +{ +} + +static void +shell_window_init (ShellWindow * window) +{ + window->_hbox = NULL; + window->_left_pane = NULL; + window->_right_pane = NULL; +} + +GtkWidget * +shell_window_new (AppShellData * app_data) +{ + ShellWindow *window = g_object_new (SHELL_WINDOW_TYPE, NULL); + + gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE); + gtk_frame_set_shadow_type(GTK_FRAME(window), GTK_SHADOW_NONE); + + window->_hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); + gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (window->_hbox)); + + return GTK_WIDGET (window); +} + +void +shell_window_clear_resize_handler (ShellWindow * win) +{ + if (win->resize_handler_id) + { + g_signal_handler_disconnect (win, win->resize_handler_id); + win->resize_handler_id = 0; + } +} + +void +shell_window_set_contents (ShellWindow * shell, GtkWidget * left_pane, GtkWidget * right_pane) +{ + shell->_left_pane = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_margin_top (GTK_WIDGET (shell->_left_pane), 15); + gtk_widget_set_margin_bottom (GTK_WIDGET (shell->_left_pane), 15); + gtk_widget_set_margin_start (GTK_WIDGET (shell->_left_pane), 15); + gtk_widget_set_margin_end (GTK_WIDGET (shell->_left_pane), 15); + + shell->_right_pane = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + + gtk_box_pack_start (shell->_hbox, shell->_left_pane, FALSE, FALSE, 0); + gtk_box_pack_start (shell->_hbox, shell->_right_pane, TRUE, TRUE, 0); /* this one takes any extra space */ + + gtk_container_add (GTK_CONTAINER (shell->_left_pane), left_pane); + gtk_container_add (GTK_CONTAINER (shell->_right_pane), right_pane); +} diff --git a/shell/shell-window.h b/shell/shell-window.h new file mode 100644 index 00000000..2aa51e3f --- /dev/null +++ b/shell/shell-window.h @@ -0,0 +1,65 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __SHELL_WINDOW_H__ +#define __SHELL_WINDOW_H__ + +#include +#include + +#include "app-shell.h" + +G_BEGIN_DECLS + +#define SHELL_WINDOW_TYPE (shell_window_get_type ()) +#define SHELL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_WINDOW_TYPE, ShellWindow)) +#define SHELL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_WINDOW_TYPE, ShellWindowClass)) +#define IS_SHELL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_WINDOW_TYPE)) +#define IS_SHELL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_WINDOW_TYPE)) +#define SHELL_WINDOW_GET_CLASS(obj) (G_TYPE_CHECK_GET_CLASS ((obj), SHELL_WINDOW_TYPE, ShellWindowClass)) + +typedef struct _ShellWindow ShellWindow; +typedef struct _ShellWindowClass ShellWindowClass; + +struct _ShellWindow +{ + GtkFrame frame; + + GtkBox *_hbox; + GtkWidget *_left_pane; + GtkWidget *_right_pane; + + gulong resize_handler_id; +}; + +struct _ShellWindowClass +{ + GtkFrameClass parent_class; +}; + +GType shell_window_get_type (void); +GtkWidget *shell_window_new (AppShellData * app_data); +void shell_window_set_contents (ShellWindow * window, GtkWidget * left_pane, + GtkWidget * right_pane); +void shell_window_clear_resize_handler (ShellWindow * win); + +G_END_DECLS + +#endif /* __SHELL_WINDOW_H__ */ diff --git a/shell/slab-mate-util.c b/shell/slab-mate-util.c new file mode 100644 index 00000000..b036de18 --- /dev/null +++ b/shell/slab-mate-util.c @@ -0,0 +1,160 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "slab-mate-util.h" +#include "libslab-utils.h" + +#include +#include + +MateDesktopItem * +load_desktop_item_from_unknown (const gchar *id) +{ + MateDesktopItem *item; + gchar *basename; + + GError *error = NULL; + + item = mate_desktop_item_new_from_uri (id, 0, &error); + + if (! error) + return item; + else { + g_error_free (error); + error = NULL; + } + + item = mate_desktop_item_new_from_file (id, 0, &error); + + if (! error) + return item; + else { + g_error_free (error); + error = NULL; + } + + item = mate_desktop_item_new_from_basename (id, 0, &error); + + if (! error) + return item; + else { + g_error_free (error); + error = NULL; + } + + basename = g_strrstr (id, "/"); + + if (basename) { + basename++; + + item = mate_desktop_item_new_from_basename (basename, 0, &error); + + if (! error) + return item; + else { + g_error_free (error); + error = NULL; + } + } + + return NULL; +} + +gboolean +open_desktop_item_exec (MateDesktopItem * desktop_item) +{ + GError *error = NULL; + + if (!desktop_item) + return FALSE; + + mate_desktop_item_launch (desktop_item, NULL, MATE_DESKTOP_ITEM_LAUNCH_ONLY_ONE | MATE_DESKTOP_ITEM_LAUNCH_DO_NOT_REAP_CHILD, &error); + + if (error) + { + g_warning ("error launching %s [%s]\n", + mate_desktop_item_get_location (desktop_item), error->message); + + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +gboolean +open_desktop_item_help (MateDesktopItem * desktop_item) +{ + const gchar *doc_path; + gchar *help_uri; + + GError *error; + + if (!desktop_item) + return FALSE; + + doc_path = mate_desktop_item_get_string (desktop_item, "DocPath"); + + if (doc_path) + { + help_uri = g_strdup_printf ("help:%s", doc_path); + + error = NULL; + if (!gtk_show_uri_on_window (NULL, help_uri, gtk_get_current_event_time (), &error)) + { + g_warning ("error opening %s [%s]\n", help_uri, error->message); + + g_free (help_uri); + g_error_free (error); + return FALSE; + } + + g_free (help_uri); + } + else + return FALSE; + + return TRUE; +} + +void +copy_file (const gchar * src_uri, const gchar * dst_uri) +{ + GFile *src; + GFile *dst; + GError *error = NULL; + gboolean res; + + src = g_file_new_for_uri (src_uri); + dst = g_file_new_for_uri (dst_uri); + + res = g_file_copy (src, dst, + G_FILE_COPY_NONE, + NULL, NULL, NULL, &error); + + if (!res) + { + g_warning ("error copying [%s] to [%s]: %s.", src_uri, dst_uri, error->message); + g_error_free (error); + } + + g_object_unref (src); + g_object_unref (dst); +} diff --git a/shell/slab-mate-util.h b/shell/slab-mate-util.h new file mode 100644 index 00000000..211e76c4 --- /dev/null +++ b/shell/slab-mate-util.h @@ -0,0 +1,39 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __SLAB_MATE_UTIL_H__ +#define __SLAB_MATE_UTIL_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +MateDesktopItem *load_desktop_item_from_unknown (const gchar * id); + +gboolean open_desktop_item_exec (MateDesktopItem * desktop_item); +gboolean open_desktop_item_help (MateDesktopItem * desktop_item); + +void copy_file (const gchar * src_uri, const gchar * dst_uri); + +G_END_DECLS + +#endif /* __SLAB_MATE_UTIL_H__ */ diff --git a/shell/slab-section.c b/shell/slab-section.c new file mode 100644 index 00000000..f86820cf --- /dev/null +++ b/shell/slab-section.c @@ -0,0 +1,233 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "slab-section.h" + +G_DEFINE_TYPE (SlabSection, slab_section, GTK_TYPE_BOX) + +static void slab_section_finalize (GObject *); + +static void slab_section_class_init (SlabSectionClass * slab_section_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (slab_section_class); + + g_obj_class->finalize = slab_section_finalize; +} + +static void +slab_section_init (SlabSection * section) +{ + section->title = NULL; + section->contents = NULL; +} + +static void +slab_section_finalize (GObject * obj) +{ + g_assert (IS_SLAB_SECTION (obj)); + (*G_OBJECT_CLASS (slab_section_parent_class)->finalize) (obj); +} + +static void +set_override_color (GtkWidget *widget, + GdkRGBA *rgba) +{ + gchar *css; + GtkCssProvider *provider; + + provider = gtk_css_provider_new (); + + css = g_strdup_printf ("* { color: %s;}", + gdk_rgba_to_string (rgba)); + gtk_css_provider_load_from_data (provider, css, -1, NULL); + g_free (css); + + gtk_style_context_add_provider (gtk_widget_get_style_context (widget), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref (provider); +} + +static void +slab_section_set_title_color (GtkWidget * widget) +{ + GtkStyleContext *context; + GdkRGBA *rgba = NULL; + + context = gtk_widget_get_style_context (widget); + + switch (SLAB_SECTION (widget)->style) + { + case Style1: + gtk_style_context_get (context, + GTK_STATE_FLAG_SELECTED, + "background-color", &rgba, + NULL); + set_override_color (SLAB_SECTION (widget)->title, rgba); + break; + case Style2: + if (SLAB_SECTION (widget)->selected) + { + gtk_style_context_get (context, + GTK_STATE_FLAG_SELECTED, + "background-color", &rgba, + NULL); + set_override_color (SLAB_SECTION (widget)->title, rgba); + } + else + { + gtk_style_context_get (context, + GTK_STATE_FLAG_INSENSITIVE, + "color", &rgba, + NULL); + set_override_color (SLAB_SECTION (widget)->title, rgba); + } + break; + default: + g_assert_not_reached (); + } +} + +static void +slab_section_style_set (GtkWidget * widget, GtkStyle * prev_style, gpointer user_data) +{ + static gboolean recursively_entered = FALSE; + if (!recursively_entered) + { + recursively_entered = TRUE; + + slab_section_set_title_color (widget); + + recursively_entered = FALSE; + } +} + +/* +gboolean +slab_section_expose_event (GtkWidget * widget, GdkEventExpose * event, gpointer data) +{ + gdk_draw_rectangle (widget->window, widget->style->light_gc[GTK_STATE_SELECTED], TRUE, + widget->allocation.x, widget->allocation.y, + widget->allocation.width + 40, widget->allocation.height); + + return FALSE; +} +*/ + +void +slab_section_set_selected (SlabSection * section, gboolean selected) +{ + if (selected == section->selected) + return; + section->selected = selected; + +/* + if(selected) + { + section->expose_handler_id = + g_signal_connect (section, "expose-event", + G_CALLBACK (slab_section_expose_event), + NULL); + } + else + { + g_signal_handler_disconnect(section, section->expose_handler_id); + } +*/ + + slab_section_set_title_color (GTK_WIDGET (section)); +} + +GtkWidget * +slab_section_new_with_markup (const gchar * title_markup, SlabStyle style) +{ + SlabSection *section; + gchar * widget_theming_name; + + section = g_object_new (SLAB_SECTION_TYPE, NULL); + gtk_orientable_set_orientation (GTK_ORIENTABLE (section), GTK_ORIENTATION_VERTICAL); + gtk_box_set_homogeneous (GTK_BOX (section), FALSE); + gtk_box_set_spacing (GTK_BOX (section), 0); + section->style = style; + section->selected = FALSE; + + section->childbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 10)); + switch (style) + { + case Style1: + widget_theming_name = "slab_section_style1"; + break; + case Style2: + gtk_widget_set_margin_top (GTK_WIDGET (section->childbox), SLAB_TOP_PADDING); + gtk_widget_set_margin_bottom (GTK_WIDGET (section->childbox), SLAB_BOTTOM_PADDING); + gtk_widget_set_margin_start (GTK_WIDGET (section->childbox), SLAB_LEFT_PADDING); + gtk_widget_set_margin_end (GTK_WIDGET (section->childbox), 0); + widget_theming_name = "slab_section_style2"; + break; + default: + g_assert_not_reached (); + } + gtk_box_pack_start (GTK_BOX (section), GTK_WIDGET (section->childbox), TRUE, TRUE, 0); + + section->title = gtk_label_new (title_markup); + gtk_label_set_use_markup (GTK_LABEL (section->title), TRUE); + gtk_label_set_xalign (GTK_LABEL (section->title), 0.0); + + gtk_widget_set_name (GTK_WIDGET (section), widget_theming_name); + g_signal_connect (section, "style-set", + G_CALLBACK (slab_section_style_set), + NULL); + + gtk_box_pack_start (section->childbox, section->title, FALSE, FALSE, 0); + + return GTK_WIDGET (section); +} + +GtkWidget * +slab_section_new (const gchar * title, SlabStyle style) +{ + GtkWidget *section; + gchar *markup; + + markup = g_strdup_printf ("%s", title); + section = slab_section_new_with_markup (markup, style); + + g_free (markup); + + return section; +} + +void +slab_section_set_title (SlabSection * section, const gchar * title) +{ + gchar *markup = g_strdup_printf ("%s", title); + + gtk_label_set_markup (GTK_LABEL (section->title), markup); + + g_free (markup); +} + +void +slab_section_set_contents (SlabSection * section, GtkWidget * contents) +{ + section->contents = contents; + + gtk_box_pack_start (section->childbox, contents, FALSE, FALSE, 0); +} diff --git a/shell/slab-section.h b/shell/slab-section.h new file mode 100644 index 00000000..04288a87 --- /dev/null +++ b/shell/slab-section.h @@ -0,0 +1,72 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __SLAB_SECTION_H__ +#define __SLAB_SECTION_H__ + +#include +#include + +G_BEGIN_DECLS + +#define SLAB_SECTION_TYPE (slab_section_get_type ()) +#define SLAB_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SLAB_SECTION_TYPE, SlabSection)) +#define SLAB_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SLAB_SECTION_TYPE, SlabSectionClass)) +#define IS_SLAB_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SLAB_SECTION_TYPE )) +#define IS_SLAB_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SLAB_SECTION_TYPE )) +#define SLAB_SECTION_GET_CLASS(obj) (G_TYPE_CHECK_GET_CLASS ((obj), SLAB_SECTION_TYPE, SlabSectionClass)) + +#define SLAB_TOP_PADDING 5 +#define SLAB_BOTTOM_PADDING 5 +#define SLAB_LEFT_PADDING 10 + +typedef enum +{ + Style1, /* SlabSections in left pane - no padding */ + Style2 /* SlabSections in right pane - padding, label text changes as group is selected */ +} SlabStyle; + +typedef struct +{ + GtkBox parent_vbox; + + GtkWidget *title; + GtkWidget *contents; + SlabStyle style; + gulong expose_handler_id; + GtkBox *childbox; + gboolean selected; +} SlabSection; + +typedef struct +{ + GtkBoxClass parent_class; +} SlabSectionClass; + +GType slab_section_get_type (void); +GtkWidget *slab_section_new (const gchar * title, SlabStyle style); +GtkWidget *slab_section_new_with_markup (const gchar * title_markup, SlabStyle style); +void slab_section_set_title (SlabSection * section, const gchar * title); +void slab_section_set_contents (SlabSection * section, GtkWidget * contents); +void slab_section_set_selected (SlabSection * section, gboolean selected); + +G_END_DECLS + +#endif /* __SLAB_SECTION_H__ */ diff --git a/shell/slab.h b/shell/slab.h new file mode 100644 index 00000000..721943a0 --- /dev/null +++ b/shell/slab.h @@ -0,0 +1,40 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef __SLAB_H__ +#define __SLAB_H__ + +#include "app-resizer.h" +#include "app-shell.h" +#include "application-tile.h" +#include "bookmark-agent.h" +#include "double-click-detector.h" +#include "mate-utils.h" +#include "libslab-utils.h" +#include "nameplate-tile.h" +#include "search-bar.h" +#include "shell-window.h" +#include "slab-mate-util.h" +#include "slab-section.h" +#include "tile.h" + +#endif /* __SLAB_H__ */ + diff --git a/shell/themed-icon.c b/shell/themed-icon.c new file mode 100644 index 00000000..aabf4b89 --- /dev/null +++ b/shell/themed-icon.c @@ -0,0 +1,159 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "themed-icon.h" + +#include "mate-utils.h" + +static void themed_icon_finalize (GObject *); +static void themed_icon_get_property (GObject *, guint, GValue *, GParamSpec *); +static void themed_icon_set_property (GObject *, guint, const GValue *, GParamSpec *); + +static void themed_icon_show (GtkWidget *); +static void themed_icon_style_updated (GtkWidget *); + +enum +{ + PROP_0, + PROP_ICON_ID, + PROP_ICON_SIZE +}; + +typedef struct +{ + gboolean icon_loaded; +} ThemedIconPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (ThemedIcon, themed_icon, GTK_TYPE_IMAGE) + +static void themed_icon_class_init (ThemedIconClass * themed_icon_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (themed_icon_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (themed_icon_class); + + g_obj_class->get_property = themed_icon_get_property; + g_obj_class->set_property = themed_icon_set_property; + g_obj_class->finalize = themed_icon_finalize; + + widget_class->show = themed_icon_show; + widget_class->style_updated = themed_icon_style_updated; + + g_object_class_install_property (g_obj_class, PROP_ICON_ID, g_param_spec_string ("icon-id", + "icon-id", "the identifier of the icon", NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (g_obj_class, PROP_ICON_SIZE, + g_param_spec_enum ("icon-size", "icon-size", "the size of the icon", + GTK_TYPE_ICON_SIZE, GTK_ICON_SIZE_BUTTON, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); +} + +static void +themed_icon_init (ThemedIcon * icon) +{ + ThemedIconPrivate *priv = themed_icon_get_instance_private (icon); + + priv->icon_loaded = FALSE; +} + +GtkWidget * +themed_icon_new (const gchar * id, GtkIconSize size) +{ + GtkWidget *icon = GTK_WIDGET (g_object_new ( + THEMED_ICON_TYPE, "icon-id", id, "icon-size", size, NULL)); + + return icon; +} + +static void +themed_icon_finalize (GObject * object) +{ + ThemedIcon *icon = THEMED_ICON (object); + if (icon->id) + g_free (icon->id); + (*G_OBJECT_CLASS (themed_icon_parent_class)->finalize) (object); +} + +static void +themed_icon_get_property (GObject * g_obj, guint prop_id, GValue * value, GParamSpec * param_spec) +{ + ThemedIcon *icon = THEMED_ICON (g_obj); + + switch (prop_id) + { + case PROP_ICON_ID: + g_value_set_string (value, icon->id); + break; + + case PROP_ICON_SIZE: + g_value_set_enum (value, icon->size); + break; + + default: + break; + } +} + +static void +themed_icon_set_property (GObject * g_obj, guint prop_id, const GValue * value, + GParamSpec * param_spec) +{ + ThemedIcon *icon = THEMED_ICON (g_obj); + + switch (prop_id) + { + case PROP_ICON_ID: + icon->id = g_strdup (g_value_get_string (value)); + +/* gtk_image_load_by_id (GTK_IMAGE (icon), icon->size, icon->id); */ + + break; + + case PROP_ICON_SIZE: + icon->size = g_value_get_enum (value); + +/* gtk_image_load_by_id (GTK_IMAGE (icon), icon->size, icon->id); */ + + break; + + default: + break; + } +} + +static void +themed_icon_show (GtkWidget * widget) +{ + ThemedIcon *icon = THEMED_ICON (widget); + ThemedIconPrivate *priv = themed_icon_get_instance_private (icon); + + if (!priv->icon_loaded) + priv->icon_loaded = load_image_by_id (GTK_IMAGE (icon), icon->size, icon->id); + + (*GTK_WIDGET_CLASS (themed_icon_parent_class)->show) (widget); +} + +static void +themed_icon_style_updated (GtkWidget * widget) +{ + ThemedIcon *icon = THEMED_ICON (widget); + + load_image_by_id (GTK_IMAGE (icon), icon->size, icon->id); +} diff --git a/shell/themed-icon.h b/shell/themed-icon.h new file mode 100644 index 00000000..d4604430 --- /dev/null +++ b/shell/themed-icon.h @@ -0,0 +1,54 @@ +/* + * This file is part of libslab. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libslab is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libslab 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __THEMED_ICON_H__ +#define __THEMED_ICON_H__ + +#include +#include + +G_BEGIN_DECLS + +#define THEMED_ICON_TYPE (themed_icon_get_type ()) +#define THEMED_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THEMED_ICON_TYPE, ThemedIcon)) +#define THEMED_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THEMED_ICON_TYPE, ThemedIconClass)) +#define IS_THEMED_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THEMED_ICON_TYPE)) +#define IS_THEMED_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THEMED_ICON_TYPE)) +#define THEMED_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THEMED_ICON_TYPE, ThemedIconClass)) + +typedef struct +{ + GtkImage parent; + + GtkIconSize size; + gchar *id; +} ThemedIcon; + +typedef struct +{ + GtkImageClass parent_class; +} ThemedIconClass; + +GType themed_icon_get_type (void); +GtkWidget *themed_icon_new (const gchar * id, GtkIconSize size); + +G_END_DECLS + +#endif /* __THEMED_ICON_H__ */ diff --git a/shell/tile-action.c b/shell/tile-action.c new file mode 100644 index 00000000..c1d5906c --- /dev/null +++ b/shell/tile-action.c @@ -0,0 +1,109 @@ +/* + * This file is part of libtile. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libtile is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libtile 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "tile.h" + +G_DEFINE_TYPE (TileAction, tile_action, G_TYPE_OBJECT) + +static void tile_action_finalize (GObject *); +static void tile_action_menu_item_activate_cb (GtkMenuItem *, gpointer); + +static void tile_action_class_init (TileActionClass * this_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); + + g_obj_class->finalize = tile_action_finalize; +} + +static void +tile_action_init (TileAction * this) +{ + this->tile = NULL; + this->func = 0; + this->menu_item = NULL; + this->flags = 0; +} + +static void +tile_action_finalize (GObject * g_object) +{ + TileAction *action = TILE_ACTION (g_object); + if (action->menu_item) + gtk_widget_destroy (GTK_WIDGET (action->menu_item)); + + (*G_OBJECT_CLASS (tile_action_parent_class)->finalize) (g_object); +} + +TileAction * +tile_action_new (Tile * tile, TileActionFunc func, const gchar * menu_item_markup, guint32 flags) +{ + TileAction *this = g_object_new (TILE_ACTION_TYPE, NULL); + + this->tile = tile; + this->func = func; + + if (menu_item_markup) + tile_action_set_menu_item_label (this, menu_item_markup); + else + this->menu_item = NULL; + + this->flags = flags; + + return this; +} + +void +tile_action_set_menu_item_label (TileAction * this, const gchar * markup) +{ + GtkWidget *label; + + if (this->menu_item) + { + label = gtk_bin_get_child (GTK_BIN (this->menu_item)); + gtk_label_set_markup (GTK_LABEL (label), markup); + } + else + { + label = gtk_label_new (markup); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + + this->menu_item = GTK_MENU_ITEM (gtk_menu_item_new ()); + gtk_container_add (GTK_CONTAINER (this->menu_item), label); + + g_signal_connect (this->menu_item, "activate", + G_CALLBACK (tile_action_menu_item_activate_cb), + this); + } +} + +GtkMenuItem * +tile_action_get_menu_item (TileAction * this) +{ + return this->menu_item; +} + +static void +tile_action_menu_item_activate_cb (GtkMenuItem * menu_item, gpointer user_data) +{ + TileAction *this = TILE_ACTION (user_data); + + tile_trigger_action (this->tile, this); +} diff --git a/shell/tile.c b/shell/tile.c new file mode 100644 index 00000000..96ff2120 --- /dev/null +++ b/shell/tile.c @@ -0,0 +1,529 @@ +/* + * This file is part of libtile. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libtile is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libtile 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "tile.h" + +#include +#include + +#include "double-click-detector.h" + +typedef struct +{ + DoubleClickDetector *double_click_detector; + + gboolean is_dragging; +} TilePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (Tile, tile, GTK_TYPE_BUTTON) + +static void tile_finalize (GObject *); +static void tile_dispose (GObject *); +static void tile_get_property (GObject *, guint, GValue *, GParamSpec *); +static void tile_set_property (GObject *, guint, const GValue *, GParamSpec *); +static GObject *tile_constructor (GType, guint, GObjectConstructParam *); + +static void tile_setup (Tile *); + +static void tile_enter (GtkButton * widget); +static void tile_leave (GtkButton * widget); +static void tile_clicked (GtkButton *widget); + +static gboolean tile_focus_in (GtkWidget *, GdkEventFocus *); +static gboolean tile_focus_out (GtkWidget *, GdkEventFocus *); +static gboolean tile_draw (GtkWidget *, cairo_t *); +static gboolean tile_button_release (GtkWidget *, GdkEventButton *); +static gboolean tile_key_release (GtkWidget *, GdkEventKey *); +static gboolean tile_popup_menu (GtkWidget *); + +static void tile_drag_begin (GtkWidget *, GdkDragContext *); +static void tile_drag_data_get (GtkWidget *, GdkDragContext *, GtkSelectionData *, guint, +guint); + +static void tile_tile_action_triggered (Tile *, TileEvent *, TileAction *); +static void tile_action_triggered_event_marshal (GClosure *, GValue *, guint, const GValue *, +gpointer, gpointer); + +typedef void (*marshal_func_VOID__POINTER_POINTER) (gpointer, gpointer, gpointer, gpointer); + +enum +{ + TILE_ACTIVATED_SIGNAL, + TILE_ACTION_TRIGGERED_SIGNAL, + LAST_SIGNAL +}; + +static guint tile_signals[LAST_SIGNAL] = { 0 }; + +enum +{ + PROP_0, + PROP_TILE_URI, + PROP_TILE_CONTEXT_MENU, + PROP_TILE_ACTIONS +}; + +static void +tile_class_init (TileClass * this_class) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (this_class); + GtkButtonClass *button_class = GTK_BUTTON_CLASS (this_class); + + g_obj_class->constructor = tile_constructor; + g_obj_class->get_property = tile_get_property; + g_obj_class->set_property = tile_set_property; + g_obj_class->finalize = tile_finalize; + g_obj_class->dispose = tile_dispose; + + widget_class->focus_in_event = tile_focus_in; + widget_class->focus_out_event = tile_focus_out; + widget_class->draw = tile_draw; + widget_class->button_release_event = tile_button_release; + widget_class->key_release_event = tile_key_release; + widget_class->drag_begin = tile_drag_begin; + widget_class->drag_data_get = tile_drag_data_get; + widget_class->popup_menu = tile_popup_menu; + + button_class->enter = tile_enter; + button_class->leave = tile_leave; + button_class->clicked = tile_clicked; + + this_class->tile_activated = NULL; + this_class->tile_action_triggered = tile_tile_action_triggered; + + g_object_class_install_property (g_obj_class, PROP_TILE_URI, + g_param_spec_string ("tile-uri", "tile-uri", "the uri of the tile", NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property (g_obj_class, PROP_TILE_CONTEXT_MENU, + g_param_spec_object ("context-menu", "context-menu", + "the context menu for the tile", GTK_TYPE_MENU, G_PARAM_READWRITE)); + + tile_signals[TILE_ACTIVATED_SIGNAL] = g_signal_new ("tile-activated", + G_TYPE_FROM_CLASS (this_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (TileClass, tile_activated), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + + tile_signals[TILE_ACTION_TRIGGERED_SIGNAL] = g_signal_new ("tile-action-triggered", + G_TYPE_FROM_CLASS (this_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (TileClass, tile_action_triggered), + NULL, NULL, tile_action_triggered_event_marshal, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); +} + +static GObject * +tile_constructor (GType type, guint n_param, GObjectConstructParam * param) +{ + GObject *g_obj; + TilePrivate *priv; + + g_obj = (*G_OBJECT_CLASS (tile_parent_class)->constructor) (type, n_param, param); + + priv = tile_get_instance_private (TILE(g_obj)); + priv->double_click_detector = double_click_detector_new (); + + tile_setup (TILE (g_obj)); + + return g_obj; +} + +static void +tile_init (Tile * tile) +{ + TilePrivate *priv = tile_get_instance_private (tile); + + tile->uri = NULL; + tile->context_menu = NULL; + tile->entered = FALSE; + tile->enabled = TRUE; + + tile->actions = NULL; + tile->n_actions = 0; + + tile->default_action = NULL; + + priv->double_click_detector = NULL; + priv->is_dragging = FALSE; +} + +static void +tile_finalize (GObject * g_object) +{ + Tile *tile = TILE (g_object); + TilePrivate *priv = tile_get_instance_private (TILE(tile)); + + if (tile->n_actions) /* this will also free "default_action" entry */ + { + g_free (tile->actions); + } + + if (tile->uri) + g_free (tile->uri); + + g_object_unref (priv->double_click_detector); + + (*G_OBJECT_CLASS (tile_parent_class)->finalize) (g_object); +} + +static void +tile_dispose (GObject * g_object) +{ + Tile *tile = TILE (g_object); + + /* free the TileAction object */ + if (tile->n_actions) + { + gint x; + for (x = 0; x < tile->n_actions; x++) + { + if (tile->actions[x] != NULL) { + g_object_unref (tile->actions[x]); + tile->actions[x] = NULL; + } + } + } + + /* free the GtkMenu object */ + if (tile->context_menu != NULL) { + gtk_widget_destroy (GTK_WIDGET (tile->context_menu)); + tile->context_menu = NULL; + } + + (*G_OBJECT_CLASS (tile_parent_class)->dispose) (g_object); +} + +static void +tile_get_property (GObject * g_obj, guint prop_id, GValue * value, GParamSpec * param_spec) +{ + if (!IS_TILE (g_obj)) + return; + + switch (prop_id) + { + case PROP_TILE_URI: + g_value_set_string (value, TILE (g_obj)->uri); + break; + + case PROP_TILE_CONTEXT_MENU: + g_value_set_object (value, TILE (g_obj)->context_menu); + break; + + default: + break; + } +} + +static void +tile_set_property (GObject * g_obj, guint prop_id, const GValue * value, GParamSpec * param_spec) +{ + Tile *tile; + GtkMenu *menu; + + if (!IS_TILE (g_obj)) + return; + + tile = TILE (g_obj); + + switch (prop_id) + { + case PROP_TILE_URI: + tile->uri = g_strdup (g_value_get_string (value)); + break; + + case PROP_TILE_CONTEXT_MENU: + menu = g_value_get_object (value); + + if (menu == tile->context_menu) + break; + + if (tile->context_menu) + gtk_menu_detach (tile->context_menu); + + tile->context_menu = menu; + + if (tile->context_menu) + gtk_menu_attach_to_widget (tile->context_menu, GTK_WIDGET (tile), NULL); + + break; + + default: + break; + } +} + +static void +tile_setup (Tile * tile) +{ + gtk_button_set_relief (GTK_BUTTON (tile), GTK_RELIEF_NONE); + + if (tile->uri) + { + gtk_drag_source_set (GTK_WIDGET (tile), GDK_BUTTON1_MASK, NULL, 0, + GDK_ACTION_COPY | GDK_ACTION_MOVE); + + gtk_drag_source_add_uri_targets (GTK_WIDGET (tile)); + } +} + +static void +tile_enter (GtkButton * widget) +{ + gtk_widget_set_state_flags (GTK_WIDGET (widget), TILE_STATE_ENTERED, TRUE); + + TILE (widget)->entered = TRUE; +} + +static void +tile_leave (GtkButton * widget) +{ + if (gtk_widget_has_focus (GTK_WIDGET (widget))) + gtk_widget_set_state_flags (GTK_WIDGET (widget), TILE_STATE_FOCUSED, TRUE); + else + gtk_widget_set_state_flags (GTK_WIDGET (widget), GTK_STATE_FLAG_NORMAL, TRUE); + + TILE (widget)->entered = FALSE; +} + +static void +tile_clicked (GtkButton * widget) +{ + TileEvent *tile_event; + GdkEvent *event; + gboolean handled; + + tile_event = g_new0 (TileEvent, 1); + tile_event->type = TILE_EVENT_ACTIVATED_DOUBLE_CLICK; + tile_event->time = gtk_get_current_event_time (); + + g_signal_emit (widget, tile_signals[TILE_ACTIVATED_SIGNAL], 0, tile_event); + g_signal_emit_by_name (widget, "button-release-event", &event, &handled); + + g_free (tile_event); +} + +static gboolean +tile_focus_in (GtkWidget * widget, GdkEventFocus * event) +{ + gtk_widget_set_state_flags (widget, TILE_STATE_FOCUSED, TRUE); + + return FALSE; +} + +static gboolean +tile_focus_out (GtkWidget * widget, GdkEventFocus * event) +{ + if (TILE (widget)->entered) + gtk_widget_set_state_flags (widget, TILE_STATE_ENTERED, TRUE); + else + gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_NORMAL, TRUE); + + return FALSE; +} + +static gboolean +tile_draw (GtkWidget * widget, cairo_t * cr) +{ + /* FIXME: there ought to be a better way to prevent the focus from being rendered. */ + + gboolean has_focus; + gboolean retval; + + if ((has_focus = gtk_widget_has_focus (widget))) + gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_FOCUSED); + + retval = (*GTK_WIDGET_CLASS (tile_parent_class)->draw) (widget, cr); + + if (has_focus) + gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_FOCUSED, TRUE); + + return retval; +} + +static gboolean +tile_button_release (GtkWidget * widget, GdkEventButton * event) +{ + Tile *tile = TILE (widget); + TilePrivate *priv = tile_get_instance_private (tile); + + TileEvent *tile_event; + gboolean handled; + + if (priv->is_dragging) + { + priv->is_dragging = FALSE; + + return TRUE; + } + + switch (event->button) + { + case 1: + tile_event = g_new0 (TileEvent, 1); + tile_event->time = event->time; + + if (double_click_detector_is_double_click (priv->double_click_detector, event->time, + TRUE)) + tile_event->type = TILE_EVENT_ACTIVATED_DOUBLE_CLICK; + else + tile_event->type = TILE_EVENT_ACTIVATED_SINGLE_CLICK; + + g_signal_emit (tile, tile_signals[TILE_ACTIVATED_SIGNAL], 0, tile_event); + g_signal_emit_by_name (GTK_BUTTON (widget), "button-release-event", &event, &handled); + + g_free (tile_event); + + break; + + case 3: + if (GTK_IS_MENU (tile->context_menu)) + gtk_menu_popup_at_widget (GTK_MENU (tile->context_menu), + widget, + GDK_GRAVITY_SOUTH_WEST, + GDK_GRAVITY_NORTH_WEST, + (const GdkEvent*) event); + + break; + + default: + break; + } + + return TRUE; +} + +static gboolean +tile_key_release (GtkWidget * widget, GdkEventKey * event) +{ + TileEvent *tile_event; + + if (event->keyval == GDK_KEY_Return) + { + tile_event = g_new0 (TileEvent, 1); + tile_event->type = TILE_EVENT_ACTIVATED_KEYBOARD; + tile_event->time = event->time; + + g_signal_emit (widget, tile_signals[TILE_ACTIVATED_SIGNAL], 0, tile_event); + + return TRUE; + } + + return FALSE; +} + +static gboolean +tile_popup_menu (GtkWidget * widget) +{ + Tile *tile = TILE (widget); + + if (GTK_IS_MENU (tile->context_menu)) + { + gtk_menu_popup_at_widget (GTK_MENU (tile->context_menu), + widget, + GDK_GRAVITY_SOUTH_WEST, + GDK_GRAVITY_NORTH_WEST, + NULL); + + return TRUE; + } + + else + return FALSE; +} + +static void +tile_drag_begin (GtkWidget * widget, GdkDragContext * context) +{ + TilePrivate *priv; + + priv = tile_get_instance_private (TILE(widget)); + priv->is_dragging = TRUE; +} + +static void +tile_drag_data_get (GtkWidget * widget, GdkDragContext * context, GtkSelectionData * data, + guint info, guint time) +{ + gchar *uris[2]; + + if (TILE (widget)->uri) + { + uris[0] = TILE (widget)->uri; + uris[1] = NULL; + + gtk_selection_data_set_uris (data, uris); + } +} + +static void +tile_tile_action_triggered (Tile * tile, TileEvent * event, TileAction * action) +{ + if (action && action->func) + (*action->func) (tile, event, action); +} + +void +tile_trigger_action (Tile * tile, TileAction * action) +{ + tile_trigger_action_with_time (tile, action, GDK_CURRENT_TIME); +} + +void +tile_trigger_action_with_time (Tile * tile, TileAction * action, guint32 time) +{ + TileEvent *event = g_new0 (TileEvent, 1); + + event->type = TILE_EVENT_ACTION_TRIGGERED; + event->time = time; + + g_signal_emit (tile, tile_signals[TILE_ACTION_TRIGGERED_SIGNAL], 0, event, action); + g_free (event); +} + +static void +tile_action_triggered_event_marshal (GClosure * closure, GValue * retval, guint n_param, + const GValue * param, gpointer invocation_hint, gpointer marshal_data) +{ + marshal_func_VOID__POINTER_POINTER callback; + GCClosure *cc = (GCClosure *) closure; + gpointer data_0, data_1; + + g_return_if_fail (n_param == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data_0 = closure->data; + data_1 = g_value_peek_pointer (param); + } + else + { + data_0 = g_value_peek_pointer (param); + data_1 = closure->data; + } + + if (marshal_data) + callback = (marshal_func_VOID__POINTER_POINTER) marshal_data; + else + callback = (marshal_func_VOID__POINTER_POINTER) cc->callback; + + callback (data_0, g_value_peek_pointer (param + 1), g_value_peek_pointer (param + 2), + data_1); +} diff --git a/shell/tile.h b/shell/tile.h new file mode 100644 index 00000000..9c8d3f2a --- /dev/null +++ b/shell/tile.h @@ -0,0 +1,127 @@ +/* + * This file is part of libtile. + * + * Copyright (c) 2006 Novell, Inc. + * + * Libtile is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Libtile 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 Lesser General Public License + * along with libslab; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __TILE_H__ +#define __TILE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define TILE_TYPE (tile_get_type ()) +#define TILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TILE_TYPE, Tile)) +#define TILE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TILE_TYPE, TileClass)) +#define IS_TILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TILE_TYPE)) +#define IS_TILE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TILE_TYPE)) +#define TILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TILE_TYPE, TileClass)) +#define TILE_ACTION_TYPE (tile_action_get_type ()) +#define TILE_ACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TILE_ACTION_TYPE, TileAction)) +#define TILE_ACTION_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TILE_ACTION_TYPE, TileActionClass)) +#define IS_TILE_ACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TILE_ACTION_TYPE)) +#define IS_TILE_ACTION_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TILE_ACTION_TYPE)) +#define TILE_ACTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TILE_ACTION_TYPE, TileActionClass)) +#define TILE_ACTION_CHECK_FLAG(action,flag) ((TILE_ACTION (action)->flags & (flag)) != 0) +#define TILE_STATE_ENTERED GTK_STATE_FLAG_PRELIGHT +#define TILE_STATE_FOCUSED GTK_STATE_FLAG_PRELIGHT + +typedef struct _Tile Tile; +typedef struct _TileClass TileClass; +typedef struct _TileAction TileAction; +typedef struct _TileActionClass TileActionClass; +typedef struct _TileEvent TileEvent; + +typedef void (*TileActionFunc) (Tile *, TileEvent *, TileAction *); + +typedef enum +{ + TILE_EVENT_ACTIVATED_SINGLE_CLICK, + TILE_EVENT_ACTIVATED_DOUBLE_CLICK, + TILE_EVENT_ACTIVATED_KEYBOARD, + TILE_EVENT_ACTION_TRIGGERED +} TileEventType; + +typedef enum +{ + TILE_ACTION_OPENS_NEW_WINDOW = 1 << 0, + TILE_ACTION_OPENS_HELP = 1 << 1 +} TileActionFlags; + +struct _Tile +{ + GtkButton gtk_button; + + gchar *uri; + GtkMenu *context_menu; + gboolean entered; + gboolean enabled; + + TileAction **actions; + gint n_actions; + + TileAction *default_action; +}; + +struct _TileClass +{ + GtkButtonClass gtk_button_class; + + void (*tile_activated) (Tile *, TileEvent *); + void (*tile_action_triggered) (Tile *, TileEvent *, TileAction *); +}; + +struct _TileAction +{ + GObject parent; + + Tile *tile; + + TileActionFunc func; + GtkMenuItem *menu_item; + + guint32 flags; +}; + +struct _TileActionClass +{ + GObjectClass parent_class; +}; + +struct _TileEvent +{ + TileEventType type; + guint32 time; +}; + +GType tile_get_type (void); +GType tile_action_get_type (void); + +void tile_trigger_action (Tile * tile, TileAction * action); +void tile_trigger_action_with_time (Tile * tile, TileAction * action, guint32 time); + +TileAction *tile_action_new (Tile * tile, TileActionFunc func, const gchar * menu_item_markup, + guint32 flags); + +void tile_action_set_menu_item_label (TileAction * action, const gchar * markup); +GtkMenuItem *tile_action_get_menu_item (TileAction * action); + +G_END_DECLS + +#endif /* __TILE_H__ */ -- cgit v1.2.1