[maemo-commits] [maemo-commits] r8258 - in projects/haf/branches/maemo-af-desktop/hildon-desktop: . libhildondesktop libhildonwm
From: moimart at stage.maemo.org moimart at stage.maemo.orgDate: Wed Nov 22 16:33:58 EET 2006
- Previous message: [maemo-commits] r8257 - projects/haf/branches/maemo-af-desktop/hildon-desktop
- Next message: [maemo-commits] r8259 - projects/connectivity/osso-bluez-compat/trunk/etc
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Author: moimart Date: 2006-11-22 16:33:55 +0200 (Wed, 22 Nov 2006) New Revision: 8258 Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-entry-info.c projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-entry-info.h projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-keys.c projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-keys.h projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-memory.c projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-memory.h projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-types.h projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watchable-app.c projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watchable-app.h projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window-view.c projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window-view.h projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window.c projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window.h projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm.c projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm.h projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/osso-manager.c projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/osso-manager.h Modified: projects/haf/branches/maemo-af-desktop/hildon-desktop/ChangeLog projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildondesktop/desktop-panel-window.c projects/haf/branches/maemo-af-desktop/hildon-desktop/window_management_dependencies Log: * libhildonwm/hd-*.[ch]: First import of window managemente code. - At this point the window management code is broken and there is no way of building yet. Many dependencies (AppSwitcher mostly) must be resolved. Basically, this new approach should support more than 1 AppSwitcher. * libhildondesktop/desktop-panel-window.c: Redraw and resize only when necessary (rotated). * window_management_dependencies updated. (Refers to old code) * ChangeLog updated. Modified: projects/haf/branches/maemo-af-desktop/hildon-desktop/ChangeLog =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/ChangeLog 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/ChangeLog 2006-11-22 14:33:55 UTC (rev 8258) @@ -1,5 +1,16 @@ -2006-11-21 Lucas Rocha <lucas.rocha at nokia.com> +2006-11-22 Moises Martinez <moises.martinzes at nokia.com> + * libhildonwm/hd-*.[ch]: First import of window managemente code. + - At this point the window management code is broken and there is no + way of building yet. Many dependencies (AppSwitcher mostly) must be + resolved. Basically, this new approach should support more than 1 + AppSwitcher. + * libhildondesktop/desktop-panel-window.c: Redraw and resize only when + necessary (rotated). + * window_management_dependencies updated. (Refers to old code) + +2006-11-22 Lucas Rocha <lucas.rocha at nokia.com> + * src/hd-desktop.c: desktop conf file and container conf file handling. For both: look for user conf file, if not found, fall to global configuration at sysconfdir (i.e /etc/hildon-desktop). Modified: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildondesktop/desktop-panel-window.c =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildondesktop/desktop-panel-window.c 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildondesktop/desktop-panel-window.c 2006-11-22 14:33:55 UTC (rev 8258) @@ -531,7 +531,8 @@ } - gtk_widget_queue_resize (GTK_WIDGET (window)); + if (rotate) + gtk_widget_queue_resize (GTK_WIDGET (window)); } static gboolean @@ -814,12 +815,17 @@ GtkRequisition *requisition) { DesktopPanelWindow *window; + GtkBin *bin; GdkRectangle old_geometry; gboolean position_changed = FALSE; gboolean size_changed = FALSE; window = DESKTOP_PANEL_WINDOW (widget); - + bin = GTK_BIN (widget); +/* + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + gtk_widget_size_request (bin->child, requisition); +*/ old_geometry = window->priv->geometry; desktop_panel_update_geometry (window,requisition); Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-entry-info.c =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-entry-info.c 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-entry-info.c 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,749 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* hn-entry-info.c + * This file is part of maemo-af-desktop + * + * Copyright (C) 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <string.h> +#include <stdlib.h> +#include <glib/gi18n.h> + +#include "hd-entry-info.h" + +#include "hd-wm-watchable-app.h" +#include "hd-wm-watched-window.h" +#include "hd-wm-watched-window-view.h" + +#include "hd-wm-util.h" + +typedef struct +{ + HDEntryInfoType type; + + /* parent, for child windows */ + HDEntryInfo *parent; + GList *children; + + union { + HDWMWatchableApp *app; + HDWMWatchedWindow *window; + HDWMWatchedWindowView *view; + } d; + + GHashTable *icon_cache; + + guint ignore_urgent : 1; +} RealEntryInfo; + +#define REAL_ENTRY_INFO(x) ((RealEntryInfo *) (x)) + +HDEntryInfo * +hd_entry_info_new (HDEntryInfoType type) +{ + RealEntryInfo *retval; + + g_return_val_if_fail (HD_ENTRY_INFO_IS_VALID_TYPE (type), NULL); + + retval = g_new (RealEntryInfo, 1); + retval->type = type; + retval->parent = NULL; + retval->children = NULL; + retval->ignore_urgent = FALSE; + retval->icon_cache = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + return (HDEntryInfo *) retval; +} + +HDEntryInfo * +hd_entry_info_new_from_app (HDWMWatchableApp *app) +{ + HDEntryInfo *retval; + + g_return_val_if_fail (app != NULL, NULL); + + retval = hd_entry_info_new (HD_ENTRY_WATCHED_APP); + hd_entry_info_set_app (retval, app); + + return retval; +} + +HDEntryInfo * +hd_entry_info_new_from_window (HDWMWatchedWindow *window) +{ + HDEntryInfo *retval; + + g_return_val_if_fail (window != NULL, NULL); + + retval = hd_entry_info_new (HD_ENTRY_WATCHED_WINDOW); + hd_entry_info_set_window (retval, window); + + return retval; +} + +HDEntryInfo * +hd_entry_info_new_from_view (HDWMWatchedWindowView *view) +{ + HDEntryInfo *retval; + + g_return_val_if_fail (view != NULL, NULL); + + retval = hd_entry_info_new (HD_ENTRY_WATCHED_VIEW); + hd_entry_info_set_view (retval, view); + + return retval; +} + +void +hd_entry_info_free (HDEntryInfo *entry_info) +{ + RealEntryInfo *real; + + if (!entry_info) + return; + + real = REAL_ENTRY_INFO (entry_info); + switch (real->type) + { + case HD_ENTRY_WATCHED_APP: + break; + case HD_ENTRY_WATCHED_WINDOW: + break; + case HD_ENTRY_WATCHED_VIEW: + break; + case HD_ENTRY_INVALID: + default: + g_assert_not_reached (); + return; + } + + g_list_free (real->children); + + g_hash_table_destroy (real->icon_cache); + + g_free (real); +} + +void +hd_entry_info_set_app (HDEntryInfo *entry_info, + HDWMWatchableApp *app) +{ + g_return_if_fail (entry_info != NULL); + g_return_if_fail (entry_info->type == HD_ENTRY_WATCHED_APP); + + REAL_ENTRY_INFO (entry_info)->d.app = app; +} + +HDWMWatchableApp * +hd_entry_info_get_app (HDEntryInfo *entry_info) +{ + RealEntryInfo *real = NULL; + HDWMWatchedWindow *win = NULL; + HDWMWatchedWindowView *view = NULL; + + g_return_val_if_fail (entry_info != NULL, 0); + real = REAL_ENTRY_INFO (entry_info); + + switch (real->type) + { + case HD_ENTRY_WATCHED_APP: + return REAL_ENTRY_INFO (entry_info)->d.app; + break; + case HD_ENTRY_WATCHED_WINDOW: + win = hd_entry_info_get_window(entry_info); + break; + case HD_ENTRY_WATCHED_VIEW: + view = hd_entry_info_get_view(entry_info); + win = hd_wm_watched_window_view_get_parent(view); + break; + case HD_ENTRY_INVALID: + default: + g_assert_not_reached (); + break; + } + + return hd_wm_watched_window_get_app(win); +} + +void +hd_entry_info_set_window (HDEntryInfo *entry_info, + HDWMWatchedWindow *window) +{ + g_return_if_fail (entry_info != NULL); + g_return_if_fail (entry_info->type == HD_ENTRY_WATCHED_WINDOW); + + REAL_ENTRY_INFO (entry_info)->d.window = window; +} + +HDWMWatchedWindow * +hd_entry_info_get_window (HDEntryInfo *entry_info) +{ + HDWMWatchedWindowView *view; + g_return_val_if_fail (entry_info != NULL, NULL); + + switch(entry_info->type) + { + case HD_ENTRY_WATCHED_WINDOW: + return REAL_ENTRY_INFO (entry_info)->d.window; + case HD_ENTRY_WATCHED_VIEW: + view = hd_entry_info_get_view(entry_info); + return hd_wm_watched_window_view_get_parent(view); + default: + return hd_wm_watchable_app_get_active_window( + hd_entry_info_get_app(entry_info)); + } +} + +void +hd_entry_info_set_view (HDEntryInfo *entry_info, + HDWMWatchedWindowView *view) +{ + g_return_if_fail (entry_info != NULL); + g_return_if_fail (entry_info->type == HD_ENTRY_WATCHED_VIEW); + + REAL_ENTRY_INFO (entry_info)->d.view = view; +} + +HDWMWatchedWindowView * +hd_entry_info_get_view (HDEntryInfo *entry_info) +{ + g_return_val_if_fail (entry_info != NULL, NULL); + g_return_val_if_fail (entry_info->type == HD_ENTRY_WATCHED_VIEW, NULL); + + return REAL_ENTRY_INFO (entry_info)->d.view; +} + +HDEntryInfo * +hd_entry_info_get_parent (HDEntryInfo *entry_info) +{ + RealEntryInfo *real; + + g_return_val_if_fail (entry_info != NULL, NULL); + real = REAL_ENTRY_INFO (entry_info); + + return real->parent; +} + +gint +hd_entry_info_get_n_children (HDEntryInfo *entry_info) +{ + RealEntryInfo *real; + + g_return_val_if_fail (entry_info != NULL, 0); + real = REAL_ENTRY_INFO (entry_info); + + if(!real->children) + return 0; + + return g_list_length(real->children); +} + +const gchar * +hd_entry_info_peek_app_name (HDEntryInfo *entry_info) +{ + RealEntryInfo *real; + const gchar *retval; + + g_return_val_if_fail (entry_info != NULL, NULL); + + real = REAL_ENTRY_INFO (entry_info); + switch (real->type) + { + case HD_ENTRY_WATCHED_APP: + retval = hd_wm_watchable_app_get_name (real->d.app); + break; + case HD_ENTRY_WATCHED_WINDOW: + retval = hd_wm_watched_window_get_name (real->d.window); + break; + case HD_ENTRY_WATCHED_VIEW: + retval = hd_wm_watched_window_view_get_name (real->d.view); + break; + case HD_ENTRY_DESKTOP: + retval = _("tana_fi_home"); + break; + case HD_ENTRY_INVALID: + default: + g_assert_not_reached (); + retval = NULL; + break; + } + + return retval; +} +const gchar * +hd_entry_info_peek_title (HDEntryInfo *entry_info) +{ + RealEntryInfo *real; + const gchar *retval; + + g_return_val_if_fail (entry_info != NULL, NULL); + + real = REAL_ENTRY_INFO (entry_info); + switch (real->type) + { + case HD_ENTRY_WATCHED_APP: + { + HDWMWatchedWindow *win; + + win = hd_wm_watchable_app_get_active_window (real->d.app); + if (win) + retval = hd_wm_watched_window_get_name (win); + else + retval = hd_wm_watchable_app_get_name (real->d.app); + } + break; + case HD_ENTRY_WATCHED_WINDOW: + retval = hd_wm_watched_window_get_name (real->d.window); + break; + case HD_ENTRY_WATCHED_VIEW: + retval = hd_wm_watched_window_view_get_name (real->d.view); + break; + case HD_ENTRY_DESKTOP: + retval = _("tana_fi_home"); + break; + case HD_ENTRY_INVALID: + default: + g_assert_not_reached (); + retval = NULL; + break; + } + + return retval; +} + +gchar * +hd_entry_info_get_title (HDEntryInfo *info) +{ + return g_strdup (hd_entry_info_peek_title (info)); +} + +gchar * +hd_entry_info_get_app_name (HDEntryInfo *info) +{ + gchar *title, *sep; + + g_return_val_if_fail (info != NULL, NULL); + + if (info->type == HD_ENTRY_DESKTOP) + return g_strdup (_("tana_fi_home")); + + title = hd_entry_info_get_title (info); + if (!title) + return NULL; + + sep = strstr (title, " - "); + if (sep) + { + gchar *retval; + + *sep = 0; + retval = g_strdup (title); + + g_free (title); + + return retval; + } + else + return title; +} + +gchar * +hd_entry_info_get_window_name (HDEntryInfo *info) +{ + gchar *title, *sep; + + g_return_val_if_fail (info != NULL, NULL); + + if (info->type == HD_ENTRY_DESKTOP) + return g_strdup (_("tana_fi_home_thumb")); + + title = hd_entry_info_get_title (info); + if (!title) + return NULL; + + sep = strstr (title, " - "); + if (sep) + { + gchar *retval; + + *sep = 0; + retval = g_strdup (sep + 3); + + g_free (title); + + return retval; + } + else + return NULL; +} + +void +hd_entry_info_set_title (HDEntryInfo *entry_info, + const gchar *title) +{ + RealEntryInfo *real; + + g_return_if_fail (entry_info != NULL); + + real = REAL_ENTRY_INFO (entry_info); + + switch (real->type) + { + case HD_ENTRY_WATCHED_APP: + /* TODO */ + break; + case HD_ENTRY_WATCHED_WINDOW: + hd_wm_watched_window_set_name (real->d.window, title); + break; + case HD_ENTRY_WATCHED_VIEW: + hd_wm_watched_window_view_set_name (real->d.view, title); + break; + case HD_ENTRY_INVALID: + default: + g_assert_not_reached (); + break; + } +} + +GdkPixbuf * +hd_entry_info_get_icon (HDEntryInfo *entry_info) +{ + RealEntryInfo *real; + GdkPixbuf *retval = NULL; + + g_return_val_if_fail (entry_info != NULL, NULL); + + real = REAL_ENTRY_INFO (entry_info); + + switch (real->type) + { + case HD_ENTRY_WATCHED_APP: + /* TODO */ + break; + case HD_ENTRY_WATCHED_WINDOW: + retval = hd_wm_watched_window_get_custom_icon (real->d.window); + break; + case HD_ENTRY_WATCHED_VIEW: + retval = hd_entry_info_get_icon (hd_entry_info_get_parent (entry_info)); + break; + case HD_ENTRY_DESKTOP: + retval = NULL; + break; + case HD_ENTRY_INVALID: + default: + g_assert_not_reached (); + break; + } + + return retval; +} + +void +hd_entry_info_set_icon (HDEntryInfo *entry_info, + GdkPixbuf *icon) +{ + RealEntryInfo *real; + + g_return_if_fail (entry_info != NULL); + + real = REAL_ENTRY_INFO (entry_info); + + switch (real->type) + { + case HD_ENTRY_WATCHED_APP: + /* TODO */ + break; + case HD_ENTRY_WATCHED_WINDOW: + break; + case HD_ENTRY_WATCHED_VIEW: + break; + case HD_ENTRY_INVALID: + default: + g_assert_not_reached (); + break; + } +} + +void +hd_entry_info_close (HDEntryInfo *info) +{ + RealEntryInfo *real; + + g_return_if_fail (info != NULL); + + real = REAL_ENTRY_INFO (info); + switch (real->type) + { + case HD_ENTRY_WATCHED_APP: + /* TODO */ + break; + case HD_ENTRY_WATCHED_WINDOW: + hd_wm_watched_window_close (real->d.window); + break; + case HD_ENTRY_WATCHED_VIEW: + hd_wm_watched_window_view_close_window (real->d.view); + break; + case HD_ENTRY_INVALID: + default: + g_assert_not_reached (); + break; + } +} + +const gchar * +hd_entry_info_get_app_icon_name (HDEntryInfo *info) +{ + RealEntryInfo *real; + HDWMWatchedWindow *win = NULL; + HDWMWatchableApp *app = NULL; + + g_return_val_if_fail (info != NULL, NULL); + + real = REAL_ENTRY_INFO (info); + switch (real->type) + { + case HD_ENTRY_WATCHED_APP: + app = hd_entry_info_get_app (info); + break; + case HD_ENTRY_WATCHED_WINDOW: + win = real->d.window; + break; + case HD_ENTRY_WATCHED_VIEW: + win = hd_wm_watched_window_view_get_parent (real->d.view); + break; + case HD_ENTRY_DESKTOP: + return "qgn_list_home"; + case HD_ENTRY_INVALID: + default: + g_assert_not_reached (); + break; + } + + if (!app) + { + if (!win) + return NULL; + + app = hd_wm_watched_window_get_app (win); + + if (!app) + return NULL; + } + + return hd_wm_watchable_app_get_icon_name (app); +} + +GdkPixbuf * +hd_entry_info_get_app_icon (HDEntryInfo *info, + gint size, + GError **error) +{ + const gchar *icon_name; + GdkPixbuf *retval; + GError *load_error; + RealEntryInfo *real_info; + + real_info = REAL_ENTRY_INFO (info); + + retval = g_hash_table_lookup (real_info->icon_cache, + GINT_TO_POINTER (size)); + if (retval) + return g_object_ref (retval); + + icon_name = hd_entry_info_get_app_icon_name (info); + if (!icon_name || icon_name[0] == '\0') + return NULL; + + load_error = NULL; + retval = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), + icon_name, + size, + GTK_ICON_LOOKUP_NO_SVG, + &load_error); + if (load_error) + { + g_propagate_error (error, load_error); + + return NULL; + } + + g_debug (G_STRLOC ": adding cache entry (size:%d)", size); + g_hash_table_insert (real_info->icon_cache, + GINT_TO_POINTER (size), + g_object_ref (retval)); + + return retval; +} + +void +hd_entry_info_add_child (HDEntryInfo *info, + HDEntryInfo *child) +{ + RealEntryInfo *real; + RealEntryInfo *real_child; + + g_return_if_fail (info && child); + + real = REAL_ENTRY_INFO (info); + real_child = REAL_ENTRY_INFO (child); + + real->children = g_list_prepend (real->children, child); + + real_child->parent = info; +} + +/* returns true if this parent has children left */ +gboolean +hd_entry_info_remove_child (HDEntryInfo *info, + HDEntryInfo *child) +{ + RealEntryInfo *real; + + g_return_val_if_fail (info && child, FALSE); + + real = REAL_ENTRY_INFO (info); + real->children = g_list_remove (real->children, child); + + return (real->children != NULL); +} + +const GList* +hd_entry_info_get_children (HDEntryInfo *info) +{ + RealEntryInfo *real; + + g_return_val_if_fail (info, NULL); + + real = REAL_ENTRY_INFO (info); + return real->children; +} + +gboolean +hd_entry_info_is_urgent (HDEntryInfo *info) +{ + HDWMWatchedWindow * win; + + g_return_val_if_fail(info, FALSE); + + if (info->type == HD_ENTRY_DESKTOP) + return FALSE; + + win = hd_entry_info_get_window (info); + + if (win) + return hd_wm_watched_window_is_urgent(win); + + return FALSE; +} + +gboolean +hd_entry_info_get_ignore_urgent (HDEntryInfo *info) +{ + RealEntryInfo *real; + g_return_val_if_fail (info, FALSE); + + real = REAL_ENTRY_INFO (info); + return real->ignore_urgent; +} + +void +hd_entry_info_set_ignore_urgent (HDEntryInfo *info, gboolean ignore) +{ + RealEntryInfo *real; + g_return_if_fail (info); + + real = REAL_ENTRY_INFO (info); + real->ignore_urgent = ignore; +} + +gboolean +hd_entry_info_is_active (HDEntryInfo *info) +{ + RealEntryInfo *real; + + g_return_val_if_fail (info, FALSE); + + real = REAL_ENTRY_INFO (info); + switch (info->type) + { + case HD_ENTRY_WATCHED_APP: + { + GList *l; + + for (l = real->children; l != NULL; l = l->next) + if (hd_entry_info_is_active (l->data)) + return TRUE; + } + return FALSE; + case HD_ENTRY_WATCHED_WINDOW: + return hd_wm_watched_window_is_active(real->d.window); + case HD_ENTRY_WATCHED_VIEW: + return hd_wm_watched_window_view_is_active(real->d.view); + case HD_ENTRY_DESKTOP: + return TRUE; + case HD_ENTRY_INVALID: + default: + g_critical("Invalid Entry type"); + } + + return FALSE; +} + +gboolean +hd_entry_info_is_hibernating (HDEntryInfo *info) +{ + g_return_val_if_fail (info != NULL, FALSE); + + if (info->type == HD_ENTRY_DESKTOP) + return FALSE; + + return hd_wm_watchable_app_is_hibernating (hd_entry_info_get_app (info)); +} + +const gchar * +hd_entry_info_get_extra_icon (HDEntryInfo *info) +{ + g_return_val_if_fail (info, NULL); + + switch (info->type) + { + case HD_ENTRY_WATCHED_APP: + return hd_wm_watchable_app_get_extra_icon(hd_entry_info_get_app(info)); + + case HD_ENTRY_WATCHED_WINDOW: + case HD_ENTRY_WATCHED_VIEW: + case HD_ENTRY_INVALID: + default: + g_critical("Invalid Entry type"); + } + + return NULL; +} + +gboolean +hd_entry_info_has_extra_icon (HDEntryInfo *info) +{ + g_return_val_if_fail (info != NULL, FALSE); + + return (NULL != hd_entry_info_get_extra_icon (info)); +} Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-entry-info.h =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-entry-info.h 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-entry-info.h 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,116 @@ +/* hn-entry-info.h + * This file is part of maemo-af-desktop + * + * Copyright (C) 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __HD_ENTRY_INFO_H__ +#define __HD_ENTRY_INFO_H__ + +#include <glib-object.h> +#include <gdk/gdkpixbuf.h> + +#include "hd-wm-types.h" + +G_BEGIN_DECLS + +/* HDEntryInfo - opaque wrapper type for watchable applications + * + * This object is used to be passed around between the WM and + * the AS, providing a commodity API for accessing common meta-data + * about the windows without having the AS to know the subtleties + * of the actual window types. + */ + +typedef enum { + HD_ENTRY_INVALID, /* only used for debugging */ + + HD_ENTRY_DESKTOP, + + HD_ENTRY_WATCHED_APP, + HD_ENTRY_WATCHED_WINDOW, + HD_ENTRY_WATCHED_VIEW +} HDEntryInfoType; + +#define HD_ENTRY_INFO_IS_VALID_TYPE(x) (((x) > HD_ENTRY_INVALID) && ((x) <= HD_ENTRY_WATCHED_VIEW)) + +struct _HDEntryInfo +{ + HDEntryInfoType type; +}; + +HDEntryInfo *hd_entry_info_new (HDEntryInfoType type); +HDEntryInfo *hd_entry_info_new_from_app (HDWMWatchableApp *app); +HDEntryInfo *hd_entry_info_new_from_window (HDWMWatchedWindow *window); +HDEntryInfo *hd_entry_info_new_from_view (HDWMWatchedWindowView *view); +void hd_entry_info_free (HDEntryInfo *info); + +void hd_entry_info_set_app (HDEntryInfo *info, + HDWMWatchableApp *app); +HDWMWatchableApp * hd_entry_info_get_app (HDEntryInfo *info); +void hd_entry_info_set_window (HDEntryInfo *info, + HDWMWatchedWindow *window); +HDWMWatchedWindow * hd_entry_info_get_window (HDEntryInfo *info); +void hd_entry_info_set_view (HDEntryInfo *info, + HDWMWatchedWindowView *view); +HDWMWatchedWindowView *hd_entry_info_get_view (HDEntryInfo *info); + +HDEntryInfo *hd_entry_info_get_parent (HDEntryInfo *info); + +void hd_entry_info_add_child (HDEntryInfo *info, + HDEntryInfo *child); +gboolean hd_entry_info_remove_child (HDEntryInfo *info, + HDEntryInfo *child); +const GList* hd_entry_info_get_children (HDEntryInfo *info); +gint hd_entry_info_get_n_children (HDEntryInfo *info); + +const gchar *hd_entry_info_peek_app_name (HDEntryInfo *info); +const gchar *hd_entry_info_peek_title (HDEntryInfo *info); +gchar * hd_entry_info_get_title (HDEntryInfo *info); +void hd_entry_info_set_title (HDEntryInfo *info, + const gchar *title); +gchar * hd_entry_info_get_app_name (HDEntryInfo *info); +gchar * hd_entry_info_get_window_name (HDEntryInfo *info); +GdkPixbuf * hd_entry_info_get_icon (HDEntryInfo *info); +void hd_entry_info_set_icon (HDEntryInfo *info, + GdkPixbuf *icon); + +const gchar *hd_entry_info_get_app_icon_name (HDEntryInfo *info); +GdkPixbuf * hd_entry_info_get_app_icon (HDEntryInfo *info, + gint size, + GError **error); + +void hd_entry_info_close (HDEntryInfo *info); + +gboolean hd_entry_info_is_urgent (HDEntryInfo *info); +gboolean hd_entry_info_get_ignore_urgent (HDEntryInfo *info); +void hd_entry_info_set_ignore_urgent (HDEntryInfo *info, + gboolean ignore); + +gboolean hd_entry_info_is_active (HDEntryInfo *info); + +gboolean hd_entry_info_is_hibernating (HDEntryInfo *info); + +gboolean hd_entry_info_has_extra_icon (HDEntryInfo *info); +const gchar *hd_entry_info_get_extra_icon (HDEntryInfo *info); + +G_END_DECLS + +#endif /*__HD_ENTRY_INFO_H__*/ Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-keys.c =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-keys.c 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-keys.c 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,701 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "hd-keys.h" +#include "hd-wm.h" +#include "hd-wm-watched-window.h" +#include "osso-manager.h" + +#include <X11/keysymdef.h> +#include <X11/keysym.h> +#include <X11/extensions/XTest.h> +#include <glib.h> + +/** The MCE DBus service */ +#define MCE_SERVICE "com.nokia.mce" + +/** The MCE DBus Request interface */ +#define MCE_REQUEST_IF "com.nokia.mce.request" +/** The MCE DBus Request path */ +#define MCE_REQUEST_PATH "/com/nokia/mce/request" +/** The MCE DBus Signal path */ +#define MCE_SIGNAL_PATH "/com/nokia/mce/signal" + +#define MCE_TRIGGER_POWERKEY_EVENT_REQ "req_trigger_powerkey_event" + +static void +hd_keys_action_send_key (HDKeysConfig *keys, + gpointer *user_data) +{ + KeyCode keycode = 0; + KeySym keysym = (KeySym)user_data; + + HN_DBG("Faking keysym %li", keysym); + + if ((keycode = XKeysymToKeycode (GDK_DISPLAY(), keysym)) != 0) + { + XTestFakeKeyEvent (GDK_DISPLAY(), keycode, TRUE, CurrentTime); + XTestFakeKeyEvent (GDK_DISPLAY(), keycode, FALSE, CurrentTime); + + XSync(GDK_DISPLAY(), False); + } +} + +static void +hd_keys_action_close (HDKeysConfig *keys, + gpointer *user_data) +{ + HNWMWatchedWindow * win = hd_wm_get_active_window(); + + if (win) + { + hd_wm_watched_window_close (win); + } + else + { + g_warning ("No active window set"); + } +} + +static void +hd_keys_action_minimize (HDKeysConfig *keys, + gpointer *user_data) +{ + /* Get topped app, call XIconise on its win */ + HNWMWatchedWindow * win = hd_wm_get_active_window(); + + if (win) + { + XWindowAttributes attrs; + Window xid = hd_wm_watched_window_get_x_win (win); + XGetWindowAttributes (GDK_DISPLAY(), xid, &attrs); + + XIconifyWindow (GDK_DISPLAY(), xid, + XScreenNumberOfScreen (attrs.screen)); + } + else + { + g_warning ("No active window set"); + } +} + +static void +hd_keys_action_tn_activate (HDKeysConfig *keys, + gpointer *user_data) +{ + hd_wm_activate(GPOINTER_TO_INT (user_data)); +} + +static void +hd_keys_action_home (HDKeysConfig *keys, + gpointer *user_data) +{ + /* Desktop toggle */ + hd_wm_toggle_desktop(); +} + +static void +hd_keys_action_power (HDKeysConfig *keys, + gpointer *user_data) +{ + osso_rpc_t retval; + osso_context_t * osso_context + = get_context(osso_manager_singleton_get_instance()); + gboolean long_press = GPOINTER_TO_INT(user_data); + + if (!osso_context || + OSSO_OK != osso_rpc_run_system (osso_context, + MCE_SERVICE, + MCE_REQUEST_PATH, + MCE_REQUEST_IF, + MCE_TRIGGER_POWERKEY_EVENT_REQ, + &retval, + DBUS_TYPE_BOOLEAN, long_press, + DBUS_TYPE_INVALID)) + { + g_warning("Unable to toggle Power menu"); + } +} + +/* ==================================================================== */ + +struct +{ + char *gkey; + HDKeyAction action; + HDKeysActionFunc action_func; + gpointer action_func_data; +} +HDKeysActionConfLookup[] = +{ + { HN_KEYS_GCONF_PATH "/window_close", HN_KEY_ACTION_CLOSE, + hd_keys_action_close, NULL}, + { HN_KEYS_GCONF_PATH "/window_minimize", HN_KEY_ACTION_MINIMIZE , + hd_keys_action_minimize, NULL}, + { HN_KEYS_GCONF_PATH "/task_switcher", HN_KEY_ACTION_TASK_SWITCHER, + hd_keys_action_tn_activate, GINT_TO_POINTER (HN_TN_ACTIVATE_MAIN_MENU) }, + { HN_KEYS_GCONF_PATH "/task_launcher", HN_KEY_ACTION_TASK_LAUNCHER, + hd_keys_action_tn_activate, GINT_TO_POINTER (HN_TN_ACTIVATE_OTHERS_MENU)}, + { HN_KEYS_GCONF_PATH "/power", HN_KEY_ACTION_POWER, + hd_keys_action_power, GINT_TO_POINTER(FALSE) }, + { HN_KEYS_GCONF_PATH "/home", HN_KEY_ACTION_HOME, + hd_keys_action_home, NULL }, + { HN_KEYS_GCONF_PATH "/menu", HN_KEY_ACTION_MENU, + hd_keys_action_send_key, (gpointer)XK_F4 }, + { HN_KEYS_GCONF_PATH "/fullscreen", HN_KEY_ACTION_FULLSCREEN, + hd_keys_action_send_key, (gpointer)XK_F6 }, + { HN_KEYS_GCONF_PATH "/zoom_in", HN_KEY_ACTION_ZOOM_IN, + hd_keys_action_send_key, (gpointer)XK_F7 }, + { HN_KEYS_GCONF_PATH "/zoom_out", HN_KEY_ACTION_ZOOM_OUT, + hd_keys_action_send_key, (gpointer)XK_F8 }, + { NULL, 0, NULL, NULL } +}; + + +static gboolean +hd_keys_keysym_needs_shift (KeySym keysym) +{ + int min_kc, max_kc, col, keycode; + KeySym k; + + XDisplayKeycodes (GDK_DISPLAY(), &min_kc, &max_kc); + + for (keycode = min_kc; keycode <= max_kc; keycode++) + { + for (col = 0; + (k = XKeycodeToKeysym (GDK_DISPLAY(), keycode, col)) != NoSymbol; + col++) + { + if (k == keysym && col == 1) + return TRUE; + + if (k == keysym) + break; + } + + } + + return FALSE; +} + +static KeySym +hd_keys_keysym_get_shifted (KeySym keysym) +{ + int min_kc, max_kc, keycode; + KeySym k; + + XDisplayKeycodes (GDK_DISPLAY(), &min_kc, &max_kc); + + for (keycode = min_kc; keycode <= max_kc; keycode++) + if ((k = XKeycodeToKeysym (GDK_DISPLAY(), keycode, 0)) == keysym) + return XKeycodeToKeysym (GDK_DISPLAY(), keycode, 1); + + return NoSymbol; +} + +static void +hd_keys_set_modifiers (HDKeysConfig *keys) +{ + gint mod_idx, mod_key, col, kpm; + XModifierKeymap *mod_map; + + mod_map = XGetModifierMapping(GDK_DISPLAY()); + + /* Reset all masks, a keyboard remap may have changed */ + keys->meta_mask = 0; + keys->hyper_mask = 0; + keys->super_mask = 0; + keys->alt_mask = 0; + keys->mode_mask = 0; + keys->numlock_mask = 0; + keys->scrolllock_mask = 0; + keys->lock_mask = 0; + + kpm = mod_map->max_keypermod; + + for (mod_idx = 0; mod_idx < 8; mod_idx++) + for (mod_key = 0; mod_key < kpm; mod_key++) + { + KeySym last_sym = 0; + for (col = 0; col < 4; col += 2) + { + KeyCode code = mod_map->modifiermap[mod_idx * kpm + mod_key]; + KeySym sym = (code ? XKeycodeToKeysym(GDK_DISPLAY(), code, col) : 0); + + if (sym == last_sym) continue; + last_sym = sym; + + switch (sym) + { + case XK_Meta_L: + case XK_Meta_R: + keys->meta_mask |= (1 << mod_idx); + break; + case XK_Super_L: + case XK_Super_R: + keys->super_mask |= (1 << mod_idx); + break; + case XK_Hyper_L: + case XK_Hyper_R: + keys->hyper_mask |= (1 << mod_idx); + break; + case XK_Alt_L: + case XK_Alt_R: + keys->alt_mask |= (1 << mod_idx); + break; + case XK_Num_Lock: + keys->numlock_mask |= (1 << mod_idx); + break; + case XK_Scroll_Lock: + keys->scrolllock_mask |= (1 << mod_idx); + break; + } + } + } + + /* Assume alt <=> meta if only either set */ + if (!keys->alt_mask) keys->alt_mask = keys->meta_mask; + if (!keys->meta_mask) keys->meta_mask = keys->alt_mask; + + keys->lock_mask = keys->scrolllock_mask | keys->numlock_mask | LockMask; + + if (mod_map) XFreeModifiermap(mod_map); +} + + +static HDKeyShortcut* +hd_keys_shortcut_new (HDKeysConfig *keys, + const gchar *keystr, + guint conf_index) +{ + HDKeyShortcut *shortcut = NULL; + + gchar *p = (gchar*)keystr, *q; + gint32 i = 0, mask = 0; + gchar *keydef = NULL; + gboolean want_shift = False; + KeySym ks; + gint index = 0; + + struct { gchar *def; gint32 mask; } mod_lookup[] = { + { "ctrl", ControlMask }, + { "alt", keys->alt_mask }, + { "meta", keys->meta_mask }, + { "super", keys->super_mask }, + { "hyper", keys->hyper_mask }, + { "mod1", Mod1Mask }, + { "mod2", Mod2Mask }, + { "mod3", Mod3Mask }, + { "mod4", Mod4Mask }, + { "mod5", Mod5Mask }, + { NULL, 0 } + }; + + while (*p != '\0') + { + Bool found = False; + + /* Parse <modifier> and look up its mask + */ + if (*p == '<' && *(p+1) != '\0') + { + q = ++p; + while (*q != '\0' && *q != '>') q++; + if (*q == '\0') + return NULL; + + i = 0; + + while (mod_lookup[i].def != NULL && !found) + { + if (!g_ascii_strncasecmp (p, mod_lookup[i].def, q-p)) + { + if (mod_lookup[i].mask) + { + mask |= mod_lookup[i].mask; + found = True; + } + } + i++; + } + + if (found) + { + p = q; /* found the modifier skip index over tag */ + } + else + { + /* Check if its <shift> */ + if (!g_ascii_strncasecmp (p, "shift", 5)) + { + want_shift = True; + p = q; + } + else return NULL; /* Unknown modifier string */ + } + + } + /* Now parse the actual Key */ + else if (!g_ascii_isspace(*p)) + { + keydef = p; + break; + } + p++; + } + + if (!keydef) + return NULL; + + if ((ks = XStringToKeysym(keydef)) == (KeySym)NULL) + { + if ( g_ascii_islower(keydef[0])) /* Try again, changing case */ + keydef[0] = g_ascii_toupper(keydef[0]); + else + keydef[0] = g_ascii_tolower(keydef[0]); + + if ((ks = XStringToKeysym(keydef)) == (KeySym)NULL) + return NULL; /* Couldn't find a keysym */ + } + + /* Cannot install grab for keys that we are supposed to fake */ + switch (ks) + { + case XK_F4: + case XK_F6: + case XK_F7: + case XK_F8: + HN_DBG ("Illegal shortcut symbol -- ignoring"); + return NULL; + + default: + ; + } + + if (hd_keys_keysym_needs_shift(ks)) + { + mask |= ShiftMask; + index = 1; + } + else if (want_shift) + { + KeySym shifted; + + /* Change the keysym for case of '<shift>lowerchar' where we + * actually want to grab the shifted version of the keysym. + */ + if ((shifted = hd_keys_keysym_get_shifted (ks)) != NoSymbol) + { + ks = shifted; + index = 1; + } + + /* Set the mask even if no shifted version - <shift>up key for + * example. + */ + mask |= ShiftMask; + } + + /* If F5 is assigned to "Home", don't do anything or we will be + * conflicting with MCE's handling of the key */ + if (ks == XK_F5 && + HDKeysActionConfLookup[conf_index].action == HN_KEY_ACTION_HOME) + return NULL; + + /* If we grab keycode 0, we end up grabbing the entire keyboard :\ */ + if (XKeysymToKeycode(GDK_DISPLAY(), ks) == 0) + return NULL; + + shortcut = g_new0(HDKeyShortcut, 1); + shortcut->action + = HDKeysActionConfLookup[conf_index].action; + shortcut->action_func + = HDKeysActionConfLookup[conf_index].action_func; + shortcut->action_func_data + = HDKeysActionConfLookup[conf_index].action_func_data; + shortcut->mod_mask = mask; + shortcut->keysym = ks; + shortcut->keycode = XKeysymToKeycode(GDK_DISPLAY(), ks); + shortcut->index = index; + + HN_DBG("'%s' to new shortcut with ks:%li, mask:%i", + keystr, ks, mask); + + return shortcut; +} + + +static gboolean +hn_key_shortcut_grab (HDKeysConfig *keys, + HDKeyShortcut *shortcut, + gboolean ungrab) +{ + int ignored_mask = 0; + + /* Needed to grab all ignored combo's too if num of scroll lock are on */ + while (ignored_mask < (int) keys->lock_mask) + { + if (ignored_mask & ~(keys->lock_mask)) + { + ++ignored_mask; + continue; + } + + if (ungrab) + { + XUngrabKey(GDK_DISPLAY(), + shortcut->keycode, + shortcut->mod_mask | ignored_mask, + GDK_ROOT_WINDOW()); + } + else + { + int result; + + gdk_error_trap_push(); + + XGrabKey (GDK_DISPLAY(), + shortcut->keycode, + shortcut->mod_mask | ignored_mask, + GDK_ROOT_WINDOW(), + False, + GrabModeAsync, + GrabModeAsync); + + XSync(GDK_DISPLAY(), False); + result = gdk_error_trap_pop(); + + if (result) + { + /* FIXME: Log below somewhere */ + if (result == BadAccess) + { + fprintf(stderr, + "Some other program is already using the key %s " + "with modifiers %x as a binding\n", + (XKeysymToString (shortcut->keysym)) ? + XKeysymToString (shortcut->keysym) : "unknown", + shortcut->mod_mask | ignored_mask ); + } + else + { + fprintf(stderr, + "Unable to grab the key %s with modifiers %x" + "as a binding\n", + (XKeysymToString (shortcut->keysym)) ? + XKeysymToString (shortcut->keysym) : "unknown", + shortcut->mod_mask | ignored_mask ); + } + } + } + ++ignored_mask; + } + + return TRUE; +} + +static void +hd_keys_load_and_grab_all_shortcuts (HDKeysConfig *keys) +{ + gint i = 0; + char *key_def_str = NULL; + + while (HDKeysActionConfLookup[i].gkey != NULL) + { + key_def_str = gconf_client_get_string(keys->gconf_client, + HDKeysActionConfLookup[i].gkey, + NULL); + + if (key_def_str && g_ascii_strncasecmp(key_def_str, "disabled", 8)) + { + HDKeyShortcut *shortcut; + + if ((shortcut = hd_keys_shortcut_new (keys, key_def_str, i)) != NULL) + { + HN_DBG("Grabbing '%s'", key_def_str); + hn_key_shortcut_grab (keys, shortcut, FALSE); + keys->shortcuts = g_slist_append (keys->shortcuts, shortcut); + } + } + + i++; + } +} + +static void +gconf_key_changed_callback (GConfClient *client, + guint connection_id, + GConfEntry *entry, + gpointer user_data) +{ + HDKeysConfig *keys = (HDKeysConfig *)user_data; + GConfValue *gvalue = NULL; + + gvalue = gconf_entry_get_value(entry); + + HN_DBG("called"); + + if (gconf_entry_get_key(entry)) + { + /* Parse, find entry, ungrab, replace, regrab */ + HDKeyShortcut *shortcut; + gint i = 0; + GSList *item; + const gchar *value; + + HN_DBG("Looking up '%s'", gconf_entry_get_key(entry)); + + /* Find what this keys matches in lookup */ + while (HDKeysActionConfLookup[i].gkey != NULL) + { + if (g_str_equal(gconf_entry_get_key(entry), + HDKeysActionConfLookup[i].gkey)) + break; + i++; + } + + if (HDKeysActionConfLookup[i].gkey == NULL) + { + HN_DBG("Unable to find '%s'", gconf_entry_get_key(entry)); + return; /* key not found */ + } + + item = keys->shortcuts; + + /* Remove a potential existing grab and shortcut for this action */ + while (item) + { + HDKeyShortcut *sc = (HDKeyShortcut *)item->data; + + if (sc->action == HDKeysActionConfLookup[i].action) + { + HN_DBG("removing exisiting action %i", sc->action); + hn_key_shortcut_grab (keys, sc, TRUE); + keys->shortcuts = g_slist_remove (keys->shortcuts, item->data); + g_free (sc); + break; + } + item = g_slist_next(item); + } + + /* If value is not NULL to handle removing of key */ + if (gvalue && gvalue->type == GCONF_VALUE_STRING) + { + value = gconf_value_get_string (gvalue); + + HN_DBG("attempting to grab '%s'", value); + + /* Grab the new shortcut and addd to our list */ + if (value && g_ascii_strncasecmp(value, "disabled", 8)) + if ((shortcut = hd_keys_shortcut_new (keys, value, i)) != NULL) + { + HN_DBG("now grabbing '%s'", value); + hn_key_shortcut_grab (keys, shortcut, FALSE); + keys->shortcuts = g_slist_append (keys->shortcuts, shortcut); + } + } + } +} + +HDKeysConfig* +hd_keys_init (void) +{ + HDKeysConfig *keys; + + keys = g_new0 (HDKeysConfig, 1); + + keys->gconf_client = gconf_client_get_default(); + + gconf_client_add_dir (keys->gconf_client, + HN_KEYS_GCONF_PATH, + GCONF_CLIENT_PRELOAD_NONE, + NULL); + + gconf_client_notify_add (keys->gconf_client, + HN_KEYS_GCONF_PATH, + gconf_key_changed_callback, + keys, + NULL, + NULL); + + hd_keys_set_modifiers (keys); + + hd_keys_load_and_grab_all_shortcuts (keys); + + HN_DBG("**** Shortcuts loaded and grabbed ****"); + + return keys; +} + +void +hd_keys_reload (GdkKeymap *keymap, HDKeysConfig *keys) +{ + GSList *shortcut; + + shortcut = keys->shortcuts; + + while (shortcut != NULL) + { + gpointer data = shortcut->data; + hn_key_shortcut_grab (keys, shortcut->data, TRUE); + shortcut = g_slist_remove (shortcut, shortcut->data); + g_free (data); + } + + keys->shortcuts = NULL; + + hd_keys_set_modifiers (keys); + hd_keys_load_and_grab_all_shortcuts (keys); +} + +HDKeyShortcut * +hd_keys_handle_keypress (HDKeysConfig *keys, + KeyCode keycode, + guint32 mod_mask) +{ + GSList *item; + + item = keys->shortcuts; + + while (item) + { + HDKeyShortcut *shortcut = (HDKeyShortcut *)item->data; + + HN_DBG("%i vs %i, %li vs %li", + shortcut->mod_mask, mod_mask, + shortcut->keysym, XKeycodeToKeysym(GDK_DISPLAY(), keycode, 0)); + + if (shortcut->mod_mask == mod_mask && + shortcut->keysym == XKeycodeToKeysym(GDK_DISPLAY(), + keycode, + shortcut->index)) + { + return shortcut; + } + item = g_slist_next(item); + } + + return NULL; +} + Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-keys.h =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-keys.h 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-keys.h 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,86 @@ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include "hd-wm.h" + +#ifndef __HD_KEYS_H__ +#define __HD_KEYS_H__ + +#include <gconf/gconf-client.h> +#include <gdk/gdkx.h> + +typedef enum HDKeyAction +{ + HD_KEY_ACTION_UNKOWN = 0, + HD_KEY_ACTION_CLOSE, + HD_KEY_ACTION_MINIMIZE, + HD_KEY_ACTION_TASK_SWITCHER, + HD_KEY_ACTION_TASK_LAUNCHER, + HD_KEY_ACTION_POWER, + HD_KEY_ACTION_HOME, /* Desktop Toggle */ + HD_KEY_ACTION_MENU, + HD_KEY_ACTION_FULLSCREEN, + HD_KEY_ACTION_ZOOM_IN, + HD_KEY_ACTION_ZOOM_OUT, +} +HDKeyAction; + +typedef struct HDKeysConfig +{ + GConfClient *gconf_client; + gint32 meta_mask, hyper_mask, super_mask, alt_mask, + mode_mask, numlock_mask, scrolllock_mask, lock_mask; + + GSList *shortcuts; +} +HDKeysConfig; + +typedef void (*HDKeysActionFunc) (HDKeysConfig *keys, gpointer *user_data); + +typedef struct HDKeyShortcut +{ + HDKeyAction action; + KeySym keysym; + KeyCode keycode; + gint mod_mask; + gint index; + HDKeysActionFunc action_func; + gpointer action_func_data; +} +HDKeyShortcut; + +#define HD_KEYS_GCONF_PATH "/system/osso/af/keybindings" + +HDKeysConfig* +hd_keys_init (void); + +void +hd_keys_reload (GdkKeymap *keymap, HDKeysConfig *keys); + +HDKeyShortcut * +hd_keys_handle_keypress (HDKeysConfig *keys, + KeyCode keycode, + guint32 mod_mask); +#endif/*__HD_KEYS_H__*/ + Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-memory.c =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-memory.c 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-memory.c 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,306 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <signal.h> +#include <libosso.h> +#include <log-functions.h> +#include <X11/Xatom.h> +#include <gdk/gdkx.h> +#include <hildon-widgets/hildon-defines.h> +#include <hildon-widgets/hildon-banner.h> +#include <hildon-widgets/hildon-note.h> + +#include "hd-wm-types.h" +#include "hd-wm-memory.h" +#include "hd-wm-watched-window.h" +#include "hd-wm-watchable-app.h" + +gboolean +hd_wm_memory_get_limits (guint *pages_used, + guint *pages_available) +{ + guint lowmem_allowed; + gboolean result; + FILE *lowmem_allowed_f, *pages_used_f; + + result = FALSE; + + lowmem_allowed_f = fopen(LOWMEM_PROC_ALLOWED, "r"); + pages_used_f = fopen(LOWMEM_PROC_USED, "r"); + + if (lowmem_allowed_f != NULL && pages_used_f != NULL) + { + fscanf(lowmem_allowed_f, "%u", &lowmem_allowed); + fscanf(pages_used_f, "%u", pages_used); + + if (*pages_used < lowmem_allowed) + *pages_available = lowmem_allowed - *pages_used; + else + *pages_available = 0; + + result = TRUE; + } + else + { + osso_log(LOG_ERR, "We could not read lowmem page stats.\n"); + } + + if (lowmem_allowed_f) + fclose(lowmem_allowed_f); + + if (pages_used_f) + fclose(pages_used_f); + + return result; +} + +/* helper struct to hold things we need to pass to + * hd_wm_memory_kill_all_watched_foreach_func () below + */ +typedef struct +{ + gboolean only_able_to_hibernate; + HNWMWatchableApp * top_app; +} _memory_foreach_data; + + +static void +hd_wm_memory_kill_all_watched_foreach_func (gpointer key, + gpointer value, + gpointer userdata) +{ + HNWMWatchableApp * app; + HNWMWatchedWindow * win; + _memory_foreach_data * d; + + HN_DBG("### enter ###"); + + d = (_memory_foreach_data*) userdata; + win = (HNWMWatchedWindow *)value; + app = hd_wm_watched_window_get_app(win); + + if (d->only_able_to_hibernate) + { + HN_DBG("'%s' able_to_hibernate? '%s' , hiberanting? '%s'", + hd_wm_watched_window_get_name (win), + hd_wm_watchable_app_is_able_to_hibernate(app) ? "yes" : "no", + hd_wm_watchable_app_is_hibernating (app) ? "yes" : "no"); + + if (app != d->top_app && + hd_wm_watchable_app_is_able_to_hibernate(app) && + !hd_wm_watchable_app_is_hibernating (app)) + { + HN_DBG("hd_wm_watched_window_attempt_pid_kill() for '%s'", + hd_wm_watched_window_get_name (win)); + + /* mark the application as hibernating -- we do not know how many + * more windows it might have, so we need to set this on each one + * of them + * + * we have to do this unconditionally before sending SIGTERM to the + * app otherwise if the app exits very quickly, the client window + * list is updated before we have chance to mark the app as + * hibernating (NB, we cannot reset the hibernation flag here if the + * SIGTERM fails because there is still the SIGKILL in the pipeline. + */ + hd_wm_watchable_app_set_hibernate (app, TRUE); + + if (!hd_wm_watched_window_attempt_signal_kill (win, SIGTERM, TRUE)) + { + osso_log(LOG_ERR, "sigterm failed"); + } + } + } + else + { + /* Totally kill everything */ + HN_DBG("killing everything, currently '%s'", + hd_wm_watched_window_get_name (win)); + hd_wm_watched_window_attempt_signal_kill (win, SIGTERM, FALSE); + } + + HN_DBG("### leave ###"); +} + +/* FIXME: rename kill to hibernate - kill is misleading */ +int +hd_wm_memory_kill_all_watched (gboolean only_kill_able_to_hibernate) +{ + _memory_foreach_data d; + HNWMWatchedWindow * top_win = NULL; + Window * top_xwin; + + /* init the foreach data */ + d.only_able_to_hibernate = only_kill_able_to_hibernate; + d.top_app = NULL; + + /* locate the application associated with the top-level window + * we pass this into the foreach function, to avoid doing the lookup on + * each iteration + * + * Get the xid of the top level window + */ + top_xwin + = hd_wm_util_get_win_prop_data_and_validate (GDK_ROOT_WINDOW(), + hd_wm_get_atom(HN_ATOM_MB_CURRENT_APP_WINDOW), + XA_WINDOW, + 32, + 0, + NULL); + + /* see if we have a matching watched window */ + if (top_xwin) + { + top_win = g_hash_table_lookup (hd_wm_get_watched_windows(), + (gconstpointer) top_xwin); + + XFree (top_xwin); + top_xwin = NULL; + } + + /* if so, get the corresponding application */ + if (top_win) + { + d.top_app = hd_wm_watched_window_get_app (top_win); + HN_DBG ("Top level application [%s]", + hd_wm_watchable_app_get_name (d.top_app)); + } + + /* now hibernate our applications */ + g_hash_table_foreach ( hd_wm_get_watched_windows(), + hd_wm_memory_kill_all_watched_foreach_func, + (gpointer)&d); + + hd_wm_memory_update_lowmem_ui(hd_wm_is_lowmem_situation()); + + return 0; +} + +void /* NOTE: callback from app switcher */ +hd_wm_memory_bgkill_func(gboolean is_on) +{ + if (!config_do_bgkill) /* NOTE: var extern in hildon-navigator-main.h */ + return; + + hd_wm_set_bg_kill_situation(is_on); + + if (is_on == TRUE) + { + hd_wm_memory_kill_all_watched(TRUE); + } +} + + void /* NOTE: callback from app switcher */ +hd_wm_memory_lowmem_func(gboolean is_on) +{ + if (hd_wm_is_lowmem_situation() != is_on) + { + hd_wm_set_lowmem_situation(is_on); + + /* The 'lowmem' situation always includes the 'bgkill' situation, + but the 'bgkill' signal is not generated in all configurations. + So we just call the bgkill_handler here. */ + hd_wm_memory_bgkill_func(is_on); + + hd_wm_memory_update_lowmem_ui(is_on); + + /* NOTE: config_lowmem_notify_enter extern in hildon-navigator-main.h */ + if (is_on && config_lowmem_notify_enter) + { + /* NOTE: again in hildon-navigator-main.h + if (config_lowmem_pavlov_dialog) + { + tm_wm_memory_show_pavlov_dialog(); + } + */ + } + } +} + +/* FIXME: This is defined in maemo-af-desktop-main.c and we shouldn't + be using it of course. Cleaning this up can be done when nothing + else is left to clean up... */ + + void +hd_wm_memory_update_lowmem_ui (gboolean lowmem) +{ + /* If dimming is disabled, we don't do anything here. Also see + APPLICATION_SWITCHER_UPDATE_LOWMEM_SITUATION. */ + if (!config_lowmem_dim) + return; + + g_debug ("We have to set sensitiveness of others menu here!"); +/* + gtk_widget_set_sensitive(hn_window_get_others_menu(tasknav),!lowmem); +*/ +#if 0 + /* the new AS listens directly to the dbus signals */ + application_switcher_update_lowmem_situation(tasknav.app_switcher, lowmem); +#endif +} + +int /* FIXME: What does this do, does anything use it ? */ +hd_wm_memory_kill_lru( void ) +{ +#if 0 + menuitem_comp_t menu_comp; + GtkWidget *widgetptr = NULL; + + HN_MARK(); + + widgetptr = application_switcher_get_killable_item(hd_wm_get_app_switcher()); + + if (widgetptr == NULL) { + return 1; + } + + menu_comp.menu_ptr = widgetptr; + menu_comp.wm_class = NULL; + + /* FIXME: what does this do ? + gtk_tree_model_foreach (Callbacks.model, + menuitem_match_helper, + &menu_comp); + */ + + if (menu_comp.wm_class != NULL) + { + HNWMWatchedWindow *win = NULL; + + + win = hd_wm_lookup_watched_window_via_service (menu_comp.wm_class); + + if (win) + { + HNWMWatchableApp *app; + + app = hd_wm_watched_window_get_app (win); + + if (hd_wm_watchable_app_is_able_to_hibernate (app)) + hd_wm_watched_window_attempt_signal_kill (win, SIGTERM); + } + } +#endif + return 0; +} Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-memory.h =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-memory.h 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-memory.h 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,62 @@ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** +* @file windowmanager.h +*/ + +#ifndef __HD_WM_MEMORY_H__ +#define __HD_WM_MEMORY_H__ + +#include "hd-wm.h" + +gboolean +hd_wm_memory_get_limits (guint *pages_used, + guint *pages_available); + +int +hd_wm_memory_kill_all_watched (gboolean only_kill_able_to_hibernate); + +/* Convenience function to get lowmem state */ +gboolean hd_wm_in_lowmem(void); + +void +hd_wm_memory_bgkill_func(gboolean is_on) ; + +void +hd_wm_memory_lowmem_func(gboolean is_on); + +void +hd_wm_memory_explain_lowmem (void); + +void +hd_wm_memory_connect_lowmem_explain(GtkWidget *widget); + +void +hd_wm_memory_update_lowmem_ui (gboolean lowmem); + +int +hd_wm_memory_kill_lru (void); + +#endif/*__HD_WM_MEMORT_H__*/ + Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-types.h =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-types.h 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-types.h 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,122 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** +* @file windowmanager.h +*/ + +#ifndef __HD_WM_TYPES_H__ +#define __HD_WM_TYPES_H__ + +enum +{ + HD_ATOM_WM_CLASS, + HD_ATOM_WM_NAME, + HD_ATOM_WM_STATE, + HD_ATOM_WM_TRANSIENT_FOR, + HD_ATOM_WM_HINTS, + HD_ATOM_WM_WINDOW_ROLE, + + HD_ATOM_NET_WM_WINDOW_TYPE, + HD_ATOM_NET_WM_WINDOW_TYPE_MENU, + HD_ATOM_NET_WM_WINDOW_TYPE_NORMAL, + HD_ATOM_NET_WM_WINDOW_TYPE_DIALOG, + HD_ATOM_NET_WM_WINDOW_TYPE_DESKTOP, + HD_ATOM_NET_WM_STATE, + HD_ATOM_NET_WM_STATE_MODAL, + HD_ATOM_NET_SHOWING_DESKTOP, + HD_ATOM_NET_WM_PID, + HD_ATOM_NET_ACTIVE_WINDOW, + HD_ATOM_NET_CLIENT_LIST, + HD_ATOM_NET_WM_ICON, + HD_ATOM_NET_WM_USER_TIME, + HD_ATOM_NET_WM_NAME, + HD_ATOM_NET_CLOSE_WINDOW, + HD_ATOM_NET_WM_STATE_FULLSCREEN, + + HD_ATOM_HILDON_APP_KILLABLE, + HD_ATOM_HILDON_ABLE_TO_HIBERNATE, + HD_ATOM_HILDON_VIEW_LIST, + HD_ATOM_HILDON_VIEW_ACTIVE, + HD_ATOM_HILDON_FROZEN_WINDOW, + HD_ATOM_HILDON_TN_ACTIVATE, + + HD_ATOM_MB_WIN_SUB_NAME, + HD_ATOM_MB_COMMAND, + HD_ATOM_MB_CURRENT_APP_WINDOW, + HD_ATOM_MB_APP_WINDOW_LIST_STACKING, + HD_ATOM_MB_NUM_MODAL_WINDOWS_PRESENT, + + HD_ATOM_UTF8_STRING, + + HD_ATOM_COUNT +}; + +enum +{ + HD_TN_ACTIVATE_KEY_FOCUS = 0, + HD_TN_ACTIVATE_MAIN_MENU = 1, + HD_TN_ACTIVATE_OTHERS_MENU = 2, + HD_TN_ACTIVATE_PLUGIN1_MENU = 3, + HD_TN_ACTIVATE_PLUGIN2_MENU = 4, + HD_TN_ACTIVATE_LAST_APP_WINDOW = 5, + HD_TN_DEACTIVATE_KEY_FOCUS = 6, + + HD_TN_ACTIVATE_LAST = 7 +}; + + +/* + * HDWMWatchableApp instances are created from .desktop files and through + * key values represent windows that are valid for watching/tracking via + * the HN. + */ +typedef struct HDWMWatchableApp HDWMWatchableApp; + +/* A HDWMWatchedWindow is a running watched / tracked instance of a window + * that references a valid HDWMWatchableApp. A watched window *may* contain + * a list of views ( see below ). + */ +typedef struct HDWMWatchedWindow HDWMWatchedWindow; + +/* A HDWMWatchedWindowView is a window in a window of a watched window, + * but to WM it appears as a *single* window, yet to HN as multiples via + * having a _NET_CLIENT_LIST and _NET_ACTIVE_ID set on *it* rather than + * the usual root window. + */ +typedef struct HDWMWatchedWindowView HDWMWatchedWindowView; + +/* callbacks for external application switch code - actual menu updates */ +typedef struct HDWMCallbacks HDWMCallbacks; + +/* Used to pass data to launch banner timeout callback */ +typedef struct HDWMLaunchBannerInfo HDWMLaunchBannerInfo; + +typedef struct _HDAppSwitcher HDAppSwitcher; + +typedef struct _HDEntryInfo HDEntryInfo; + +#endif/*__HD_WM_TYPES_H__*/ + Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watchable-app.c =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watchable-app.c 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watchable-app.c 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,759 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include <string.h> +#include <libosso.h> +#include <log-functions.h> + +#include <hildon-widgets/hildon-defines.h> +#include <hildon-widgets/hildon-banner.h> +#include <hildon-widgets/hildon-note.h> + +#include "hd-wm.h" +#include "hd-wm-watchable-app.h" +#include "hd-wm-watched-window.h" +#include "hd-entry-info.h" +#include "hd-app-switcher.h" +#include "osso-manager.h" +#include "hildon-navigator.h" + +typedef char HDWMWatchableAppFlags; + +typedef enum +{ + HDWM_APP_CAN_HIBERNATE = 1 << 0, + HDWM_APP_HIBERNATING = 1 << 1, + HDWM_APP_MINIMISED = 1 << 2, + HDWM_APP_STARTUP_NOTIFY = 1 << 3, + HDWM_APP_DUMMY = 1 << 4, + HDWM_APP_LAUNCHING = 1 << 5, + /* + Last dummy value for compile time check. + If you need values > HDWM_APP_LAST, you have to change the + definition of HDWMWatchableAppFlags to get more space. + */ + HDWM_APP_LAST = 1 << 7 +}HDWMWatchableAppFlagsEnum; + + +/* + compile time assert making sure that the storage space for our flags is + big enough +*/ +typedef char __app_compile_time_check_for_flags_size[ + (guint)(1<<(sizeof(HDWMWatchableAppFlags)*8))>(guint)HDWM_APP_LAST ? 1:-1 + ]; + +#define HDWM_APP_SET_FLAG(a,f) ((a)->flags |= (f)) +#define HDWM_APP_UNSET_FLAG(a,f) ((a)->flags &= ~(f)) +#define HDWM_APP_IS_SET_FLAG(a,f) ((a)->flags & (f)) + +/* watchable apps */ + +struct HDWMWatchableApp +{ + gchar *icon_name; + gchar *extra_icon; + gchar *service; + gchar *app_name; /* window title */ + gchar *exec_name; /* class || exec field ? */ + gchar *class_name; + gchar *text_domain; + GtkWidget *ping_timeout_note; /* The note that is shown when the app quits responding */ + HDWMWatchedWindow *active_window; + HDWMWatchableAppFlags flags; + HNEntryInfo *info; +}; + + + +static gboolean +hd_wm_watchable_app_has_windows_find_func (gpointer key, + gpointer value, + gpointer user_data); + +static void +hd_wm_launch_banner_info_free (HDWMLaunchBannerInfo* info) +{ + g_return_if_fail(info); + + g_free(info->msg); + g_free(info); +} + +HDWMWatchableApp* +hd_wm_watchable_app_new_dummy (void) +{ + HDWMWatchableApp *app; + + app = g_new0 (HDWMWatchableApp, 1); + + if (!app) + { + return NULL; + } + + app->icon_name = g_strdup("qgn_list_gene_default_app"); + app->app_name = g_strdup("?"); + app->class_name = g_strdup("?"); + + HDWM_APP_SET_FLAG (app, HDWM_APP_DUMMY); + + HN_DBG("Registered new non-watchable app\n\tapp_name: " + "%s\n\tclass name: %s\n\texec name (service): %s", + app->app_name, app->class_name, app->service); + + return app; +} + +HDWMWatchableApp* +hd_wm_watchable_app_new (const char * file) +{ + HDWMWatchableApp *app = NULL; + gchar *service, *icon_name, *startup_notify; + gchar *startup_wmclass, *exec_name, *app_name, *text_domain; + GKeyFile *key_file; + + g_return_val_if_fail(file,NULL); + + key_file = g_key_file_new(); + + if (!key_file) return NULL; + + if (!g_key_file_load_from_file (key_file, file, G_KEY_FILE_NONE, NULL)) + { + g_warning ("Could not load keyfile [%s]", file); + g_key_file_free(key_file); + return NULL; + } + + app_name = g_key_file_get_value(key_file, + "Desktop Entry", + DESKTOP_VISIBLE_FIELD, + NULL); + + startup_wmclass = g_key_file_get_value(key_file, + "Desktop Entry", + DESKTOP_SUP_WMCLASS, + NULL); + + exec_name = g_key_file_get_value(key_file, + "Desktop Entry", + DESKTOP_EXEC_FIELD, + NULL); + + if (app_name == NULL || (exec_name == NULL && startup_wmclass == NULL)) + { + osso_log(LOG_ERR, "HN: Desktop file has invalid fields"); + g_free(app_name); + g_free(exec_name); + g_free(startup_wmclass); + return NULL; + } + + /* DESKTOP_LAUNCH_FIELD maps to X-Osso-Service */ + service = g_key_file_get_value(key_file, + "Desktop Entry", + DESKTOP_LAUNCH_FIELD, + NULL); + + if (service && !strchr (service, '.')) + { + /* unqualified service name; prefix com.nokia. */ + gchar * s = g_strconcat (SERVICE_PREFIX, service, NULL); + g_free (service); + service = s; + } + + icon_name = g_key_file_get_value(key_file, + "Desktop Entry", + DESKTOP_ICON_FIELD, + NULL); + + startup_notify = g_key_file_get_value(key_file, + "Desktop Entry", + DESKTOP_STARTUPNOTIFY, + NULL); + + text_domain = g_key_file_get_value(key_file, + "Desktop Entry", + DESKTOP_TEXT_DOMAIN_FIELD, + NULL); + + app = g_new0 (HDWMWatchableApp, 1); + + if (!app) + { + g_free(app_name); + g_free(startup_wmclass); + g_free(exec_name); + g_free(service); + g_free(icon_name); + g_free(startup_notify); + g_free(text_domain); + goto out; + } + + /* translate the application name as appropriate */ + if (app_name) + { + app->app_name = g_strdup ((text_domain && *text_domain) ? + dgettext(text_domain, app_name): _(app_name)); + + g_free (app_name); + } + + app->icon_name = icon_name; + app->service = service; + app->exec_name = exec_name; + app->text_domain = text_domain; + + HDWM_APP_SET_FLAG (app, HDWM_APP_STARTUP_NOTIFY); /* Default */ + + if (startup_notify) + { + if(!g_ascii_strcasecmp(startup_notify, "false")) + HDWM_APP_UNSET_FLAG (app, HDWM_APP_STARTUP_NOTIFY); + + g_free(startup_notify); + } + + if (startup_wmclass != NULL) + app->class_name = startup_wmclass; + else + app->class_name = g_path_get_basename(exec_name); + + app->active_window = NULL; + HN_DBG("Registered new watchable app\n" + "\texec name: %s\n" + "\tapp name: %s\n" + "\tclass name: %s\n" + "\tservice: %s", + app->exec_name, app->app_name, app->class_name, app->service); + + out: + g_key_file_free(key_file); + return app; +} + +gboolean +hd_wm_watchable_app_update (HDWMWatchableApp *app, HDWMWatchableApp *update) +{ + gboolean retval = FALSE; + + /* can only update if the two represent the same application */ + g_return_val_if_fail(app && update && + app->class_name && update->class_name && + !strcmp(app->class_name, update->class_name), + FALSE); + + /* + * we only update fields that make sense to update -- update should not be + * running application, so we do not update flags, etc + */ + if((!update->icon_name && app->icon_name) || + (update->icon_name && !app->icon_name) || + (update->icon_name && app->icon_name && strcmp(update->icon_name, + app->icon_name))) + { + HN_DBG("changing %s -> %s", app->icon_name, update->icon_name); + + if(app->icon_name) + g_free(app->icon_name); + + app->icon_name = g_strdup(update->icon_name); + retval = TRUE; + } + + if((!update->service && app->service) || + (update->service && !app->service) || + (update->service && app->service && strcmp(update->service, + app->service))) + { + HN_DBG("changing %s -> %s", app->service, update->service); + if(app->service) + g_free(app->service); + + app->service = g_strdup(update->service); + retval = TRUE; + } + + if((!update->app_name && app->app_name) || + (update->app_name && !app->app_name) || + (update->app_name && app->app_name && strcmp(update->app_name, + app->app_name))) + { + HN_DBG("changing %s -> %s", app->app_name, update->app_name); + if(app->app_name) + g_free(app->app_name); + + app->app_name = g_strdup(update->app_name); + retval = TRUE; + } + + if((!update->exec_name && app->exec_name) || + (update->exec_name && !app->exec_name) || + (update->exec_name && app->exec_name && strcmp(update->exec_name, + app->exec_name))) + { + HN_DBG("changing %s -> %s", app->exec_name, update->exec_name); + if(app->exec_name) + g_free(app->exec_name); + + app->exec_name = g_strdup(update->exec_name); + retval = TRUE; + } + + return retval; +} + + + + +static gboolean +hd_wm_watchable_app_has_windows_find_func (gpointer key, + gpointer value, + gpointer user_data) +{ + HDWMWatchedWindow *win; + + win = (HDWMWatchedWindow*)value; + + HN_DBG("Checking %p vs %p", + hd_wm_watched_window_get_app(win), + (HDWMWatchableApp *)user_data); + + if (hd_wm_watched_window_get_app(win) == (HDWMWatchableApp *)user_data) + return TRUE; + + return FALSE; +} + +gboolean +hd_wm_watchable_app_has_windows (HDWMWatchableApp *app) +{ + return (g_hash_table_find (hd_wm_get_watched_windows(), + hd_wm_watchable_app_has_windows_find_func, + (gpointer)app) != NULL); +} + +gboolean +hd_wm_watchable_app_has_hibernating_windows (HDWMWatchableApp *app) +{ + return (g_hash_table_find (hd_wm_get_hibernating_windows(), + hd_wm_watchable_app_has_windows_find_func, + (gpointer)app) != NULL); +} + +gboolean +hd_wm_watchable_app_has_any_windows (HDWMWatchableApp *app) +{ + g_return_val_if_fail(app, FALSE); + GHashTable * ht = hd_wm_watchable_app_is_hibernating (app) ? + hd_wm_get_hibernating_windows() : + hd_wm_get_watched_windows(); + + g_return_val_if_fail(ht, FALSE); + + return (g_hash_table_find (ht, + hd_wm_watchable_app_has_windows_find_func, + (gpointer)app) != NULL); +} + +gboolean +hd_wm_watchable_app_is_hibernating (HDWMWatchableApp *app) +{ + return HDWM_APP_IS_SET_FLAG(app, HDWM_APP_HIBERNATING); +} + +void +hd_wm_watchable_app_set_hibernate (HDWMWatchableApp *app, + gboolean hibernate) +{ + HN_MARK(); + if(hibernate) + HDWM_APP_SET_FLAG(app, HDWM_APP_HIBERNATING); + else + HDWM_APP_UNSET_FLAG(app, HDWM_APP_HIBERNATING); +} + + +gboolean +hd_wm_watchable_app_is_able_to_hibernate (HDWMWatchableApp *app) +{ + if (hd_wm_watchable_app_is_dummy (app)) + return FALSE; + + return HDWM_APP_IS_SET_FLAG(app, HDWM_APP_CAN_HIBERNATE); +} + +void +hd_wm_watchable_app_set_able_to_hibernate (HDWMWatchableApp *app, + gboolean hibernate) +{ + if(hibernate) + HDWM_APP_SET_FLAG(app, HDWM_APP_CAN_HIBERNATE); + else + HDWM_APP_UNSET_FLAG(app, HDWM_APP_CAN_HIBERNATE); +} + + +const gchar* +hd_wm_watchable_app_get_service (HDWMWatchableApp *app) +{ + return app->service; +} + +const gchar* +hd_wm_watchable_app_get_exec (HDWMWatchableApp *app) +{ + return app->exec_name; +} + +const gchar* +hd_wm_watchable_app_get_name (HDWMWatchableApp *app) +{ + return app->app_name; +} + +const gchar* +hd_wm_watchable_app_get_icon_name (HDWMWatchableApp *app) +{ + return app->icon_name; +} + +const gchar* +hd_wm_watchable_app_get_class_name (HDWMWatchableApp *app) +{ + return app->class_name; +} + + +gboolean +hd_wm_watchable_app_is_minimised (HDWMWatchableApp *app) +{ + return HDWM_APP_IS_SET_FLAG(app, HDWM_APP_MINIMISED); +} + +gboolean +hd_wm_watchable_app_has_startup_notify (HDWMWatchableApp *app) +{ + return HDWM_APP_IS_SET_FLAG(app, HDWM_APP_STARTUP_NOTIFY); +} + + +void +hd_wm_watchable_app_set_minimised (HDWMWatchableApp *app, + gboolean minimised) +{ + if(minimised) + HDWM_APP_SET_FLAG(app, HDWM_APP_MINIMISED); + else + HDWM_APP_UNSET_FLAG(app, HDWM_APP_MINIMISED); +} + +void +hd_wm_watchable_app_destroy (HDWMWatchableApp *app) +{ + g_return_if_fail(app); + + if (app->icon_name) + g_free(app->icon_name); + + if (app->service) + g_free(app->service); + + if (app->app_name) + g_free(app->app_name); + + if (app->exec_name) + g_free(app->exec_name); + + if (app->class_name) + g_free(app->class_name); + + if (app->extra_icon) + g_free(app->extra_icon); + + if (app->text_domain) + g_free(app->text_domain); + + if (app->info) + hn_entry_info_free (app->info); + + g_free(app); +} + +void +hd_wm_watchable_app_died_dialog_show(HDWMWatchableApp *app) +{ + GtkWidget *dialog; + gchar *text; + text = g_strdup_printf(dgettext("ke-recv", "memr_ni_application_closed_no_resources"), + app->app_name ? _(app->app_name) : ""); + dialog = hildon_note_new_information(NULL, text); + gtk_widget_show_all(dialog); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + g_free(text); +} + +/* Launch Banner Dialog */ + +/* FIXME: rename namespace to watched app */ +void +hd_wm_watchable_app_launch_banner_show (HDWMWatchableApp *app) +{ + HDWMLaunchBannerInfo *info; + guint interval; + gchar *lapp_name; + + g_return_if_fail(app); + + interval = APP_LAUNCH_BANNER_CHECK_INTERVAL * 1000; + + info = g_new0(HDWMLaunchBannerInfo, 1); + + info->app = app; + + gettimeofday( &info->launch_time, NULL ); + + gdk_error_trap_push(); /* Needed ? */ + + lapp_name = (app->text_domain?dgettext(app->text_domain,app->app_name): + gettext(app->app_name)); + + info->msg = g_strdup_printf(_(hd_wm_watchable_app_is_hibernating(app) ? + APP_LAUNCH_BANNER_MSG_RESUMING : + APP_LAUNCH_BANNER_MSG_LOADING ), + lapp_name ? _(lapp_name) : "" ); + + info->banner = GTK_WIDGET(hildon_banner_show_animation(NULL, NULL, info->msg)); + gdk_error_trap_pop(); + + g_timeout_add(interval, hd_wm_watchable_app_launch_banner_timeout, info); + +} + +void +hd_wm_watchable_app_launch_banner_close (GtkWidget *parent, + HDWMLaunchBannerInfo *info) +{ + if (!(info && info->msg)) + return; + + if(info->banner) + gtk_widget_destroy(info->banner); + + hd_wm_launch_banner_info_free(info); +} + +gboolean +hd_wm_watchable_app_launch_banner_timeout (gpointer data) +{ + HDWMLaunchBannerInfo *info = data; + struct timeval current_time; + long unsigned int t1, t2; + guint time_left; + gulong current_banner_timeout = 0; + + /* Added by Karoliina Salminen 26092005 + * Addition to low memory situation awareness, the following + * multiplies the launch banner timeout with the timeout + * multiplier found from environment variable + */ + if(hd_wm_is_lowmem_situation()) + current_banner_timeout + = hd_wm_get_lowmem_banner_timeout()*hd_wm_get_lowmem_timeout_multiplier(); + + else + current_banner_timeout = hd_wm_get_lowmem_banner_timeout(); + + /* End of addition 26092005 */ + +#if 0 // needed ??? + if ( find_service_from_tree( hnwm->callbacks.model, + &iter, + info->service_name ) > 0) + { + } else { + /* This should never happen. Bail out! */ + return FALSE; + } +#endif + + gettimeofday( ¤t_time, NULL ); + + t1 = (long unsigned int) info->launch_time.tv_sec; + t2 = (long unsigned int) current_time.tv_sec; + time_left = (guint) (t2 - t1); + + /* The following uses now current_banner_timeout instead of + * lowmem_banner_timeout, changed by + * Karoliina Salminen 26092005 + */ + if (time_left >= current_banner_timeout + || hd_wm_watchable_app_has_windows (info->app)) + { + /* Close the banner */ + hd_wm_watchable_app_launch_banner_close( NULL, info ); + + return FALSE; + } + + return TRUE; +} + +void +hd_wm_watchable_app_set_ping_timeout_note(HDWMWatchableApp *app, GtkWidget *note) +{ + app->ping_timeout_note = note; +} + +GtkWidget* +hd_wm_watchable_app_get_ping_timeout_note(HDWMWatchableApp *app) +{ + return app->ping_timeout_note; +} + +HDWMWatchedWindow * +hd_wm_watchable_app_get_active_window (HDWMWatchableApp *app) +{ + return app->active_window; +} + +void +hd_wm_watchable_app_set_active_window (HDWMWatchableApp *app, HDWMWatchedWindow * win) +{ + app->active_window = win; +} + +gboolean +hd_wm_watchable_app_is_dummy(HDWMWatchableApp *app) +{ + g_return_val_if_fail(app, TRUE); + return HDWM_APP_IS_SET_FLAG(app, HDWM_APP_DUMMY); +} + +gboolean +hd_wm_watchable_app_is_launching (HDWMWatchableApp *app) +{ + return HDWM_APP_IS_SET_FLAG(app, HDWM_APP_LAUNCHING); +} + +void +hd_wm_watchable_app_set_launching (HDWMWatchableApp *app, + gboolean launching) +{ + if(launching) + HDWM_APP_SET_FLAG(app, HDWM_APP_LAUNCHING); + else + HDWM_APP_UNSET_FLAG(app, HDWM_APP_LAUNCHING); +} + +HNEntryInfo * +hd_wm_watchable_app_get_info (HDWMWatchableApp *app) +{ + if (!app->info) + app->info = hn_entry_info_new_from_app (app); + + return app->info; +} + +#if 0 +/* TODO -- remove me if not needed in the end */ +struct _app_windows_count_data +{ + HDWMWatchableApp * app; + guint count; +}; + +static void +hd_wm_watchable_app_my_window_foreach_func (gpointer key, + gpointer value, + gpointer user_data) +{ + HDWMWatchedWindow *win; + win = (HDWMWatchedWindow*)value; + + struct _app_windows_count_data * wcd + = (struct _app_windows_count_data *) user_data; + + if (hd_wm_watched_window_get_app(win) == wcd->app) + wcd->count++; +} + +gint +hd_wm_watchable_app_n_windows (HDWMWatchableApp *app) +{ + struct _app_windows_count_data wcd; + GHashTable * ht; + + g_return_val_if_fail(app, 0); + + ht = hd_wm_watchable_app_is_hibernating (app) ? + hd_wm_get_hibernating_windows() : + hd_wm_get_watched_windows(); + + g_return_val_if_fail(ht, 0); + + wcd.app = app; + wcd.count = 0; + + g_hash_table_foreach(ht, hd_wm_watchable_app_my_window_foreach_func, &wcd); + + return wcd.count; +} + +#endif + +gboolean +hd_wm_watchable_app_is_active (HDWMWatchableApp *app) +{ + g_return_val_if_fail(app && app->active_window, FALSE); + + if(hd_wm_get_active_window() == app->active_window) + return TRUE; + + return FALSE; +} + +const gchar * +hd_wm_watchable_app_get_extra_icon (HDWMWatchableApp *app) +{ + g_return_val_if_fail(app, NULL); + + return app->extra_icon; +} + +void +hd_wm_watchable_app_set_extra_icon (HDWMWatchableApp *app, const gchar *icon) +{ + g_return_if_fail(app); + + g_free(app->extra_icon); + + app->extra_icon = g_strdup(icon); +} Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watchable-app.h =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watchable-app.h 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watchable-app.h 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,304 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** +* @file hn-wm-watchable-app.h +*/ + +#ifndef __HD_WM_WATCHABLE_APP_H__ +#define __HD_WM_WATCHABLE_APP_H__ + +#include "hd-wm.h" + +/** + * Create a new watchable app instance from a MBDotDesktop + * + * @param desktop MBDotDesktop .desktop file representation + * + * @return pointer to HDWMWatchableApp instance, NULL if missing fields + */ +HDWMWatchableApp* +hd_wm_watchable_app_new (const char * file); + +/** + * Create a new watchable app instance for applications without + * .desktop file + * + * @return pointer to HDWMWatchableApp instance, NULL if missing fields + */ +HDWMWatchableApp* +hd_wm_watchable_app_new_dummy (void); + +/** + * Updates fields of the application represented by app to those represented + * by update. + * + * NB: this function is intended for use by the hd_wm_dnotify_cb() handler + * and should be used only with great caution anywhere else. + * + * @return TRUE if app was modified, FALSE otherwise + */ +gboolean +hd_wm_watchable_app_update (HDWMWatchableApp *app, HDWMWatchableApp *update); + +/** + * Get the X-Osso-Service field set via .desktop file of an + * HDWMWatchableApp instance. + * You should not free the result. + * + * @param app HDWMWatchableApp instance + * + * @return exec field value + */ +const gchar* +hd_wm_watchable_app_get_service (HDWMWatchableApp *app); +const gchar* +hd_wm_watchable_app_get_exec (HDWMWatchableApp *app); + +/** + * Get the name field set via .desktop file of an HDWMWatchableApp instance. + * You should not free the result. + * + * @param app HDWMWatchableApp instance + * + * @return name field value + */ +const gchar* +hd_wm_watchable_app_get_name (HDWMWatchableApp *app); + +/** + * Get the icon field set via .desktop file of an HDWMWatchableApp instance. + * You should not free the result. + * + * @param app HDWMWatchableApp instance + * + * @return icon field value + */ +const gchar* +hd_wm_watchable_app_get_icon_name (HDWMWatchableApp *app); + +/** + * Get the class field set via .desktop file of an HDWMWatchableApp instance. + * You should not free the result. + * + * @param app HDWMWatchableApp instance + * + * @return class field value + */ +const gchar* +hd_wm_watchable_app_get_class_name (HDWMWatchableApp *app); + +/** + * Check if app needs startup banner. + * + * @param app HDWMWatchableApp instance + * + * @return TRUE if app requires banner when starting, FALSE if not + */ +gboolean +hd_wm_watchable_app_has_startup_notify (HDWMWatchableApp *app); + +/** + * Check if app window(s) are minimised. + * FIXME: may break with windows as views + * + * @param app HDWMWatchableApp instance + * + * @return TRUE if minimised, FALSE if not. + */ +gboolean +hd_wm_watchable_app_is_minimised (HDWMWatchableApp *app); + +/** + * Sets minimised state of app. + * + * @param app HDWMWatchableApp instance + * @param minimised TRUE if app minimised, FALSE if not. + */ +void +hd_wm_watchable_app_set_minimised (HDWMWatchableApp *app, + gboolean minimised); + +/** + * Check if windows exist referencing this app instance + * + * @param app HDWMWatchableApp instance + * + * @return TRUE if windows exist for this app instance, FALSE if not + */ +gboolean +hd_wm_watchable_app_has_windows (HDWMWatchableApp *app); + +/** + * Check if hibernating windows exist referencing this app instance + * + * @param app HDWMWatchableApp instance + * + * @return TRUE if windows exist for this app instance, FALSE if not + */ +gboolean +hd_wm_watchable_app_has_hibernating_windows (HDWMWatchableApp *app); + +/** + * Check if windows (live or hibernating) exist referencing this app instance + * + * @param app HDWMWatchableApp instance + * + * @return TRUE if windows exist for this app instance, FALSE if not + */ +gboolean +hd_wm_watchable_app_has_any_windows (HDWMWatchableApp *app); + +/** + * Check if application is in hibernation state - i.e not actually + * running but item exists for it in application switcher. + * + * @param app HDWMWatchableApp instance + * + * @return TRUE is application is hibernating, False if not. + */ +gboolean +hd_wm_watchable_app_is_hibernating (HDWMWatchableApp *app); + +/** + * Sets the hibernation flag of the app. Does not actually + * hibernate however. + * + * FIXME: this is confusing and should somehow be removed. + * + * @param app HDWMWatchableApp instance + * @param hibernate TRUE if hibernating, FALSE if not + */ +void +hd_wm_watchable_app_set_hibernate (HDWMWatchableApp *app, + gboolean hibernate); + +/** + * Checks if the app is able to hibernate + * + * @param app HDWMWatchableApp instance + * + * @return TRUE if able to hibernate, FALSE if not. + */ +gboolean +hd_wm_watchable_app_is_able_to_hibernate (HDWMWatchableApp *app); + +/** + * Sets if the application can hibernate. + * + * FIXME: should probably be static + * @param app HDWMWatchableApp instance + * @param hibernate TRUE if hibernation possible, FALSE otherwise. + */ +void +hd_wm_watchable_app_set_able_to_hibernate (HDWMWatchableApp *app, + gboolean hibernate); + +/** + * Destroys an application instance and frees all associated memory. + * + * @param app HDWMWatchableApp instance + */ +void +hd_wm_watchable_app_destroy (HDWMWatchableApp *app); + +/** + * Shows application died dialog + * + * @param app HDWMWatchableApp instance + */ +void +hd_wm_watchable_app_died_dialog_show (HDWMWatchableApp *app); + +/** + * FIXME: CAn be static ? + * Shows launch banner for app + * + * @param parent + * @param app HDWMWatchableApp instance + */ +void +hd_wm_watchable_app_launch_banner_show (HDWMWatchableApp *app); + +/** + * FIXME: Can be static ? + * + * @param parent + */ +void +hd_wm_watchable_app_launch_banner_close (GtkWidget *parent, + HDWMLaunchBannerInfo *info); + +/** + * FIXME: this can be static + * + * @param data + * + * @return + */ +gboolean +hd_wm_watchable_app_launch_banner_timeout (gpointer data); + +void +hd_wm_watchable_app_set_ping_timeout_note (HDWMWatchableApp *app, GtkWidget *note); + +GtkWidget* +hd_wm_watchable_app_get_ping_timeout_note (HDWMWatchableApp *app); + +HDWMWatchedWindow * +hd_wm_watchable_app_get_active_window (HDWMWatchableApp *app); + +void +hd_wm_watchable_app_set_active_window (HDWMWatchableApp *app, + HDWMWatchedWindow * win); + +gboolean +hd_wm_watchable_app_is_dummy(HDWMWatchableApp *app); + +gboolean +hd_wm_watchable_app_is_launching (HDWMWatchableApp *app); + +void +hd_wm_watchable_app_set_launching (HDWMWatchableApp *app, + gboolean launching); + +HNEntryInfo * +hd_wm_watchable_app_get_info (HDWMWatchableApp *app); + +#if 0 +gint +hd_wm_watchable_app_n_windows (HDWMWatchableApp *app); +#endif + +gboolean +hd_wm_watchable_app_is_active (HDWMWatchableApp *app); + +const gchar * +hd_wm_watchable_app_get_extra_icon (HDWMWatchableApp *app); + +void +hd_wm_watchable_app_set_extra_icon (HDWMWatchableApp *app, const gchar *icon); + +#endif Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window-view.c =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window-view.c 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window-view.c 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,180 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "hd-wm-watched-window-view.h" +#include "hd-wm-watched-window.h" +#include "hd-wm-watchable-app.h" +#include "hd-entry-info.h" +#include "hn-app-switcher.h" + +/* Watched Window views */ + +struct HDWMWatchedWindowView +{ + GtkWidget *menu_widget; + int id; + HDWMWatchedWindow *win_parent; + char *name; + HDEntryInfo *info; +}; + +HDWMWatchedWindowView* +hd_wm_watched_window_view_new (HDWMWatchedWindow *win, + int view_id) +{ + HDWMWatchedWindowView *view; + + view = g_new0 (HDWMWatchedWindowView, 1); + + if (!view) /* FIXME: Handle OOM */ + return NULL; + + view->id = view_id; + view->win_parent = win; + + return view; +} + +HDWMWatchedWindow* +hd_wm_watched_window_view_get_parent (HDWMWatchedWindowView *view) +{ + return view->win_parent; +} + +gint +hd_wm_watched_window_view_get_id (HDWMWatchedWindowView *view) +{ + return view->id; +} + +GtkWidget* +hd_wm_watched_window_view_get_menu (HDWMWatchedWindowView *view) +{ + return view->menu_widget; +} + +void +hd_wm_watched_window_view_set_name (HDWMWatchedWindowView *view, + const gchar *name) +{ + if (name == NULL) + return; + + if (view->name) + g_free(view->name); + + view->name = g_strdup(name); +} + +const gchar* +hd_wm_watched_window_view_get_name (HDWMWatchedWindowView *view) +{ + if (view->name != NULL) + return view->name; + + if (view->win_parent && hd_wm_watched_window_get_name (view->win_parent)) + return hd_wm_watched_window_get_name (view->win_parent); + + return "unknown"; +} + +void +hd_wm_watched_window_view_destroy (HDWMWatchedWindowView *view) +{ + HDWMWatchableApp *app; + + app = hd_wm_watched_window_get_app(view->win_parent); + + /* Only remove the widget if the app is *really* killed */ + if (app && hd_wm_watchable_app_is_hibernating(app)) + { + HN_DBG("### Aborting destroying view '%s' as hibernating ###", + view->name); + return; + } + + + if (hd_wm_watched_window_get_active_view(view->win_parent) == view) + hd_wm_watched_window_set_active_view(view->win_parent, NULL); + + if (view->name) + g_free(view->name); + + /* + * NB -- this info might have been removed earlier if views are being removed + * because the whole app is shutting down; make sure AS can handle this + */ + HN_DBG("removing view info from AS"); + + g_debug ("Here remove an entry from application switcher"); + /* + hn_app_switcher_remove (hd_wm_get_app_switcher (), view->info); + */ + hn_entry_info_free (view->info); + + g_free (view); +} + +void +hd_wm_watched_window_view_close_window (HDWMWatchedWindowView *view) +{ + g_return_if_fail(view); + hd_wm_watched_window_close(hd_wm_watched_window_view_get_parent (view)); +} + +void +hd_wm_watched_window_view_set_info (HDWMWatchedWindowView *view, + HNEntryInfo *info) +{ + g_return_if_fail (view); + + if (view->info) + hn_entry_info_free (view->info); + + view->info = info; +} + +HNEntryInfo * +hd_wm_watched_window_view_get_info (HDWMWatchedWindowView *view) +{ + g_return_val_if_fail (view != NULL, NULL); + + if (!view->info) + view->info = hn_entry_info_new_from_view (view); + + return view->info; +} + +gboolean +hd_wm_watched_window_view_is_active (HDWMWatchedWindowView *view) +{ + g_return_val_if_fail(view, FALSE); + + if(hd_wm_watched_window_is_active(view->win_parent) && + view == hd_wm_watched_window_get_active_view (view->win_parent)) + return TRUE; + + return FALSE; +} + Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window-view.h =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window-view.h 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window-view.h 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,68 @@ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** +* @file windowmanager.h +*/ + +#ifndef __HD_WM_WATCHED_WINDOW_VIEW_H__ +#define __HD_WM_WATCHED_WINDOW_VIEW_H__ + +#include "hd-wm.h" + +HDWMWatchedWindowView* +hd_wm_watched_window_view_new (HDWMWatchedWindow *win, + int view_id); + +HDWMWatchedWindow* +hd_wm_watched_window_view_get_parent (HDWMWatchedWindowView *view); + +gint +hd_wm_watched_window_view_get_id (HDWMWatchedWindowView *view); + +GtkWidget* +hd_wm_watched_window_view_get_menu (HDWMWatchedWindowView *view); + +const gchar* +hd_wm_watched_window_view_get_name (HDWMWatchedWindowView *view); + +void +hd_wm_watched_window_view_set_name (HDWMWatchedWindowView *view, + const gchar *name); +void +hd_wm_watched_window_view_destroy (HDWMWatchedWindowView *view); + +void +hd_wm_watched_window_view_close_window (HDWMWatchedWindowView *view); + +void +hd_wm_watched_window_view_set_info (HDWMWatchedWindowView *view, + HNEntryInfo *info); + +HNEntryInfo * +hd_wm_watched_window_view_get_info (HDWMWatchedWindowView *view); + +gboolean +hd_wm_watched_window_view_is_active (HDWMWatchedWindowView *view); + +#endif/* HD_WM_WATCHED_WINDOW_VIEW_H */ Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window.c =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window.c 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window.c 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,1384 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <sys/types.h> +#include <signal.h> +#include <string.h> +#include <X11/Xutil.h> /* For WMHints */ +#include <X11/Xatom.h> +#include <gdk/gdkx.h> +#include <gtk/gtk.h> /* needed by hildon-navigator-main.h */ +#include <libosso.h> +#include <log-functions.h> +#include <hildon-widgets/hildon-defines.h> +#include <hildon-widgets/hildon-banner.h> +#include <hildon-widgets/hildon-note.h> +#include "hildon-navigator-window.h" +#include "hd-wm-watched-window.h" +#include "hd-wm-watched-window-view.h" +#include "hd-wm-watchable-app.h" +#include "hd-entry-info.h" +#include "hd-app-switcher.h" +#include "osso-manager.h" + +#define PING_TIMEOUT_MESSAGE_STRING _( "qgn_nc_apkil_notresponding" ) +#define PING_TIMEOUT_RESPONSE_STRING _( "qgn_ib_apkil_responded" ) +#define PING_TIMEOUT_KILL_FAILURE_STRING _( "" ) + +#define PING_TIMEOUT_BUTTON_OK_STRING _( "qgn_bd_apkil_ok" ) +#define PING_TIMEOUT_BUTTON_CANCEL_STRING _( "qgn_bd_apkil_cancel" ) + +#define HIBERNATION_TIMEMOUT 3000 /* as suggested by 31410#10 */ + +extern HildonNavigatorWindow *tasknav; +/* +extern Navigator * task_nav; + +extern Navigator * task_nav; +*/ +typedef char HDWMWatchedWindowFlags; + +typedef enum +{ + HDWM_WIN_URGENT = 1 << 0, + HDWM_WIN_NO_INITIAL_FOCUS = 1 << 1, + + /* + * Last dummy value for compile time check. + * If you need values > HDWM_WIN_LAST, you have to change the + * definition of HDWMWatchedWindowFlags to get more space. + */ + HDWM_WIN_LAST = 1 << 7 +}HDWMWatchedWindowFlagsEnum; + + +/* + * compile time assert making sure that the storage space for our flags is + * big enough +*/ +typedef char __window_compile_time_check_for_flags_size[ + (guint)(1<<(sizeof(HDWMWatchedWindowFlags)*8))>(guint)HDWM_WIN_LAST ? 1:-1 + ]; + +#define HDWM_WIN_SET_FLAG(a,f) ((a)->flags |= (f)) +#define HDWM_WIN_UNSET_FLAG(a,f) ((a)->flags &= ~(f)) +#define HDWM_WIN_IS_SET_FLAG(a,f) ((a)->flags & (f)) + +struct HDWMWatchedWindow +{ + Window xwin; + gchar *name; + gchar *subname; + GtkWidget *menu_widget; /* Active if no views */ + HDWMWatchableApp *app_parent; + GList *views; + HDWMWatchedWindowView *view_active; + GdkPixbuf *pixb_icon; + Window xwin_group; + gchar *hibernation_key; + HDWMWatchedWindowFlags flags; + HNEntryInfo *info; + GdkWindow *gdk_wrapper_win; +}; + +struct xwinv +{ + Window *wins; + gint n_wins; +}; + +/* NOTE: for below caller traps x errors */ +static void +hd_wm_watched_window_process_wm_state (HDWMWatchedWindow *win); + +static void +hd_wm_watched_window_process_hildon_view_list (HDWMWatchedWindow *win); + +static void +hd_wm_watched_window_process_wm_name (HDWMWatchedWindow *win); + +static void +hd_wm_watched_window_process_hibernation_prop (HDWMWatchedWindow *win); + +static void +hd_wm_watched_window_process_wm_hints (HDWMWatchedWindow *win); + +static void +hd_wm_watched_window_process_net_wm_icon (HDWMWatchedWindow *win); + +static void +hd_wm_watched_window_process_net_wm_user_time (HDWMWatchedWindow *win); + +static void +hd_wm_watched_window_process_wm_window_role (HDWMWatchedWindow *win); + +static void +pixbuf_destroy (guchar *pixels, gpointer data) +{ + /* For hd_wm_watched_window_process_net_wm_icon */ + g_free(pixels); +} + +static void +hd_wm_watched_window_process_net_wm_icon (HDWMWatchedWindow *win) +{ + gulong *data; + gint len = 0, offset, w, h, i; + guchar *rgba_data, *p; + HNEntryInfo *info; + + rgba_data = p = NULL; + + data = hd_wm_util_get_win_prop_data_and_validate + (hd_wm_watched_window_get_x_win (win), + hd_wm_get_atom(HN_ATOM_NET_WM_ICON), + XA_CARDINAL, + 0, + 0, + &len); + + HN_DBG("#### grabbing NET icon ####"); + + if (data == NULL || len < 2) + goto out; + + offset = 0; + + /* Do we have an icon of required size ? + * NOTE: ICON_SIZE set in application-switcher.h, defaults to 26 + * FIXME: figure out best way to handle scaling here + */ + do + { + w = data[offset]; + h = data[offset+1]; + + HN_DBG("got w:%i, h:%im offset is %i\n", w, h, offset); + + if (w == 26 && h == 26) + break; + + offset += ((w*h) + 2); + } + while (offset < len); + + if (offset >= len) + { + HN_DBG("w,h not found"); + goto out; + } + + HN_DBG("#### w,h ok ####"); + + p = rgba_data = g_new (guchar, w * h * 4); + + i = offset+2; + + while (i < (w*h + offset + 2)) + { + *p++ = (data[i] >> 16) & 0xff; + *p++ = (data[i] >> 8) & 0xff; + *p++ = data[i] & 0xff; + *p++ = data[i] >> 24; + i++; + } + + if (win->pixb_icon) + g_object_unref(win->pixb_icon); + + win->pixb_icon = gdk_pixbuf_new_from_data (rgba_data, + GDK_COLORSPACE_RGB, + TRUE, + 8, + w, h, w * 4, + pixbuf_destroy, + NULL); + + if (win->pixb_icon == NULL) + { + HN_DBG("#### win->pixb_icon == NULL ####"); + g_free(rgba_data); + goto out; + } + + /* FIXME: need to just update icon, also could be broke for views */ + info = hd_wm_watched_window_peek_info (win); + + if (info) + g_debug ("Here we notify changes to appswitcher"); + /* + hn_app_switcher_changed (hd_wm_get_app_switcher(), info); + */ +out: + if (data) + XFree(data); +} + +static void +hd_wm_watched_window_process_hildon_view_active (HDWMWatchedWindow *win) +{ + Window *new_active_view_id; + HDWMWatchedWindowView *current_active_view; + GList *iter = NULL; + HDWMWatchableApp *app = NULL; + + if (hd_wm_watched_window_get_views (win) == NULL) + return; + + app = hd_wm_watched_window_get_app (win); + + if (!app) + return; + + new_active_view_id = hd_wm_util_get_win_prop_data_and_validate + (hd_wm_watched_window_get_x_win (win), + hd_wm_get_atom(HN_ATOM_HILDON_VIEW_ACTIVE), + XA_WINDOW, + 32, + 0, + NULL); + + if (!new_active_view_id) + return; + + current_active_view = hd_wm_watched_window_get_active_view (win); + + /* Check the prop value is valid and not alreday active */ + + if (current_active_view + && hd_wm_watched_window_view_get_id (current_active_view) + == *new_active_view_id) + goto out; + + iter = hd_wm_watched_window_get_views (win); + + /* Find what the view id matches for this window's views and + * update. + */ + while (iter != NULL) + { + HDWMWatchedWindowView *view; + + view = (HDWMWatchedWindowView *)iter->data; + + if (hd_wm_watched_window_view_get_id (view) == *new_active_view_id) + { + HNEntryInfo *info; + + info = hd_wm_watched_window_view_get_info (view); + hd_wm_watched_window_set_active_view (win, view); + g_debug ("Here we notify stack changes to appswitcher"); + /* + hn_app_switcher_changed_stack (hd_wm_get_app_switcher (), info); + */ + goto out; + } + iter = g_list_next(iter); + } + + out: + + if (new_active_view_id) + XFree(new_active_view_id); + + return; +} + +static void +hd_wm_watched_window_process_wm_name (HDWMWatchedWindow *win) +{ + HDWMWatchedWindowView *view; + int n_items = 0; + + if (win->name) + XFree(win->name); + + win->name = NULL; + + /* Attempt to get UTF8 name */ + win->name = hd_wm_util_get_win_prop_data_and_validate + (win->xwin, + hd_wm_get_atom(HN_ATOM_NET_WM_NAME), + hd_wm_get_atom(HN_ATOM_UTF8_STRING), + 8, + 0, + &n_items); + + /* If that fails grab it basic way */ + if (win->name == NULL || n_items == 0 + || !g_utf8_validate (win->name, n_items, NULL)) + XFetchName(GDK_DISPLAY(), win->xwin, &win->name); + + if (win->name == NULL) + win->name = g_strdup("unknown"); + + /* Handle sub naming */ + + if (win->subname) + XFree(win->subname); + + win->subname = NULL; + + win->subname = hd_wm_util_get_win_prop_data_and_validate + (win->xwin, + hd_wm_get_atom(HN_ATOM_MB_WIN_SUB_NAME), + XA_STRING, + 8, + 0, + NULL); + + view = hd_wm_watched_window_get_active_view(win); + + /* Duplicate to topped view also */ + if (view) + hd_wm_watched_window_view_set_name (view, win->name); + + if (win->info) + g_debug ("Here we notify changes to appswitcher 2"); + /*hn_app_switcher_changed (hd_wm_get_app_switcher (), win->info);*/ +} + +static void +hd_wm_watched_window_process_wm_window_role (HDWMWatchedWindow *win) +{ + gchar *new_key = NULL; + + g_return_if_fail(win); + + new_key = hd_wm_compute_watched_window_hibernation_key + (win->xwin, + hd_wm_watched_window_get_app (win)); + + if (new_key) + { + if (win->hibernation_key) + g_free(win->hibernation_key); + win->hibernation_key = new_key; + } +} + + +static void +hd_wm_watched_window_process_hibernation_prop (HDWMWatchedWindow *win) +{ + Atom *foo = NULL; + HDWMWatchableApp *app; + + app = hd_wm_watched_window_get_app (win); + + if (!app) + return; + + /* NOTE: foo has no 'value' if set the app is killable (hibernatable), + * deletes to unset + */ + foo = hd_wm_util_get_win_prop_data_and_validate + (win->xwin, + hd_wm_get_atom(HN_ATOM_HILDON_APP_KILLABLE), + XA_STRING, + 8, + 0, + NULL); + + if (!foo) + { + /*try the alias*/ + foo = hd_wm_util_get_win_prop_data_and_validate + (win->xwin, + hd_wm_get_atom(HN_ATOM_HILDON_ABLE_TO_HIBERNATE), + XA_STRING, + 8, + 0, + NULL); + } + + hd_wm_watchable_app_set_able_to_hibernate (app, + (foo != NULL) ? TRUE : FALSE ); + if (foo) + XFree(foo); +} + +static void +hd_wm_watched_window_process_wm_state (HDWMWatchedWindow *win) +{ + HDWMWatchableApp *app; + Atom *state = NULL; + + app = hd_wm_watched_window_get_app (win); + + state = hd_wm_util_get_win_prop_data_and_validate + (win->xwin, + hd_wm_get_atom(HN_ATOM_WM_STATE), + hd_wm_get_atom(HN_ATOM_WM_STATE), + 0, /* FIXME: format */ + 0, + NULL); + + if (!state + || (hd_wm_watchable_app_is_minimised(app) && state[0] == IconicState) ) + goto out; + + if (state[0] == IconicState) + { + hd_wm_watchable_app_set_minimised (app, TRUE); + } + else /* Assume non minimised state */ + { + hd_wm_watchable_app_set_minimised (app, FALSE); + } + + out: + + if (state) + XFree(state); +} + +static void +hd_wm_watched_window_process_wm_hints (HDWMWatchedWindow *win) +{ + HDWMWatchableApp *app; + XWMHints *wm_hints; + gboolean need_icon_sync = FALSE; + + app = hd_wm_watched_window_get_app (win); + + wm_hints = XGetWMHints (GDK_DISPLAY(), win->xwin); + + if (!wm_hints) + return; + + win->xwin_group = wm_hints->window_group; + + if (HDWM_WIN_IS_SET_FLAG(win,HDWM_WIN_URGENT) + != (wm_hints->flags & XUrgencyHint)) + need_icon_sync = TRUE; + + if(wm_hints->flags & XUrgencyHint) + { + HDWM_WIN_SET_FLAG(win,HDWM_WIN_URGENT); + } + else + { + HDWM_WIN_UNSET_FLAG(win,HDWM_WIN_URGENT); + } + + if (need_icon_sync) + { + HNEntryInfo *info = hd_wm_watched_window_peek_info (win); + + if(info) + hn_app_switcher_changed (hd_wm_get_app_switcher (), info); + } + + XFree(wm_hints); +} + +static void +hd_wm_watched_window_process_net_wm_user_time (HDWMWatchedWindow *win) +{ + gulong *data; + + data = hd_wm_util_get_win_prop_data_and_validate + (hd_wm_watched_window_get_x_win (win), + hd_wm_get_atom(HN_ATOM_NET_WM_USER_TIME), + XA_CARDINAL, + 0, + 0, + NULL); + + HN_DBG("#### processing _NET_WM_USER_TIME ####"); + + if (data == NULL) + return; + + if (*data == 0) + { + HDWM_WIN_SET_FLAG(win,HDWM_WIN_NO_INITIAL_FOCUS); + } + + if (data) + XFree(data); +} + +static void +hd_wm_watched_window_process_hildon_view_list (HDWMWatchedWindow *win) +{ + struct xwinv xwins; + int i; + GList *iter = NULL, *next_iter; + HNEntryInfo *info; + + if (hd_wm_watched_window_is_hibernating(win)) + return; + + xwins.wins = hd_wm_util_get_win_prop_data_and_validate + (win->xwin, + hd_wm_get_atom(HN_ATOM_HILDON_VIEW_LIST), + XA_WINDOW, + 32, + 0, + &xwins.n_wins); + + if (G_UNLIKELY(xwins.wins == NULL)) + return; + + HN_DBG("_HILDON_VIEW_LIST change with %i wins", xwins.n_wins); + + iter = hd_wm_watched_window_get_views (win); + + /* Delete an views we have listed, but are not listed in prop */ + + while (iter != NULL) + { + HDWMWatchedWindowView *view; + gboolean view_found; + + view = (HDWMWatchedWindowView *)iter->data; + view_found = FALSE; + + next_iter = g_list_next(iter); + + for (i=0; i < xwins.n_wins; i++) + if (xwins.wins[i] == hd_wm_watched_window_view_get_id (view)) + { + view_found = TRUE; + break; + } + + if (!view_found) + { + /* view is not listed on client - delete the list entry */ + hd_wm_watched_window_remove_view (win, view); + hd_wm_watched_window_view_destroy (view); + } + + iter = next_iter; + } + + /* Now add any new views in prop that we dont have listed */ + + for (i=0; i < xwins.n_wins; i++) + { + gboolean view_found; + + iter = hd_wm_watched_window_get_views (win); + view_found = FALSE; + + while (iter != NULL) + { + HDWMWatchedWindowView *view; + + view = (HDWMWatchedWindowView *)iter->data; + + if (hd_wm_watched_window_view_get_id (view) == xwins.wins[i]) + { + view_found = TRUE; + break; + } + iter = g_list_next(iter); + } + + if (!view_found) + { + HDWMWatchedWindowView *new_view; + + /* Not in internal list so its new, add it */ + new_view = hd_wm_watched_window_view_new (win, xwins.wins[i]); + + if (new_view) + hd_wm_watched_window_add_view (win, new_view); + + HN_DBG("adding view info to AS"); + info = hd_wm_watched_window_view_get_info (new_view); + hn_app_switcher_add (hd_wm_get_app_switcher (), info); + + /* The window may have been 'viewless' before this + * view was created to we need to remove the widget + * ref for a viewless window + */ + if (hd_wm_watched_window_peek_info (win)) + { + HN_DBG("adding first view; removing window info from AS"); + + hn_app_switcher_remove(hd_wm_get_app_switcher (), + hd_wm_watched_window_peek_info (win)); + + /* + * since the window of multiviewed app does not figure in the AS, + * tell it to get rid of the info + */ + hd_wm_watched_window_destroy_info (win); + } + } + } + + if (xwins.wins) + XFree(xwins.wins); +} + +HDWMWatchedWindow* +hd_wm_watched_window_new (Window xid, + HDWMWatchableApp *app) +{ + HDWMWatchedWindow *win = NULL; + gchar *hkey; + gboolean win_found = FALSE; + gpointer win_ptr = NULL; + gpointer orig_key_ptr = NULL; + + + /* Check if this window is actually one coming out + * of 'hibernation', we use its WM_CLASS[+WM_WINDOW_ROLE] + * to identify. + * + * WM_WINDOW_ROLE should be unique for grouped/HildonProgram + * windows. + * + */ + hkey = hd_wm_compute_watched_window_hibernation_key(xid, app); + + HN_DBG("^^^^ new watched window, key %s ^^^^", hkey); + + g_return_val_if_fail(hkey, NULL); + + win_found = g_hash_table_lookup_extended (hd_wm_get_hibernating_windows(), + (gconstpointer)hkey, + & orig_key_ptr, + & win_ptr); + + HN_DBG("^^^^ win 0x%x ^^^^", (int)win); + + if (win_found) + { + HNEntryInfo *info = NULL; + + HN_DBG("New Window is from hibernation"); + + win = (HDWMWatchedWindow*)win_ptr; + + /* Window already exists in our hibernating window hash. + * There for we can reuse by just updating its var with + * new window values + */ + g_hash_table_steal(hd_wm_get_hibernating_windows(), + hkey); + + /* We already have this value */ + g_free(hkey); + hkey = NULL; + + /* free the hash key */ + g_free(orig_key_ptr); + + /* mark the application as no longer hibernating */ + hd_wm_watchable_app_set_hibernate (app, FALSE); + + /* As window has come out of hibernation and we still have all + * resources ( views etc ) view creation etc wont fire + * needed app_switcher updates. Therefore explicitly push + * window up our selves. + * Note, win->view_active will be NULL for viewless windows. + * + * We have to use a view from the list here, as the active view is + * not set for single-view apps, and does not have to be valid for + * multi-view apps that just woken up. + */ + if (win->views) + info = hd_wm_watched_window_view_get_info (win->views->data); + else + info = hd_wm_watched_window_peek_info (win); + + if (info) + hn_app_switcher_changed_stack (hd_wm_get_app_switcher(), info); + } + else + win = g_new0 (HDWMWatchedWindow, 1); + + if (!win) + { + if (hkey) + g_free(hkey); + return NULL; + } + + win->xwin = xid; + win->app_parent = app; + + if(hkey) + win->hibernation_key = hkey; + + /* Grab some initial props */ + hd_wm_watched_window_props_sync (win, + HD_WM_SYNC_NAME + |HD_WM_SYNC_WMHINTS + |HD_WM_SYNC_ICON + |HD_WM_SYNC_HILDON_APP_KILLABLE + |HD_WM_SYNC_USER_TIME); + return win; +} + + +HDWMWatchableApp* +hd_wm_watched_window_get_app (HDWMWatchedWindow *win) +{ + return win->app_parent; +} + +Window +hd_wm_watched_window_get_x_win (HDWMWatchedWindow *win) +{ + return win->xwin; +} + +gboolean +hd_wm_watched_window_is_urgent (HDWMWatchedWindow *win) +{ + return HDWM_WIN_IS_SET_FLAG(win,HDWM_WIN_URGENT); + +} + +gboolean +hd_wm_watched_window_wants_no_initial_focus (HDWMWatchedWindow *win) +{ + return HDWM_WIN_IS_SET_FLAG(win,HDWM_WIN_NO_INITIAL_FOCUS); +} + +const gchar* +hd_wm_watched_window_get_name (HDWMWatchedWindow *win) +{ + return win->name; +} + +const gchar* +hd_wm_watched_window_get_sub_name (HDWMWatchedWindow *win) +{ + return win->subname; +} + +const gchar* +hd_wm_watched_window_get_hibernation_key (HDWMWatchedWindow *win) +{ + return win->hibernation_key; +} + +void +hd_wm_watched_window_set_name (HDWMWatchedWindow *win, + const gchar *name) +{ + if (win->name) g_free(win->name); + win->name = g_strdup(name); +} + +void +hd_wm_watched_window_set_gdk_wrapper_win (HDWMWatchedWindow *win, + GdkWindow *wrapper_win) +{ + if (win->gdk_wrapper_win) g_object_unref (win->gdk_wrapper_win); + win->gdk_wrapper_win = wrapper_win; +} + +GdkWindow * +hd_wm_watched_window_get_gdk_wrapper_win (HDWMWatchedWindow *win) +{ + return win->gdk_wrapper_win; +} + +GtkWidget* +hd_wm_watched_window_get_menu (HDWMWatchedWindow *win) +{ + return win->menu_widget; +} + +GdkPixbuf* +hd_wm_watched_window_get_custom_icon (HDWMWatchedWindow *win) +{ + if (win->pixb_icon == NULL) + return NULL; + + return gdk_pixbuf_copy(win->pixb_icon); +} + +void +hd_wm_watched_window_set_menu (HDWMWatchedWindow *win, + GtkWidget *menu) +{ + win->menu_widget = menu; +} + +GList* +hd_wm_watched_window_get_views (HDWMWatchedWindow *win) +{ + g_return_val_if_fail (win != NULL, NULL); + + return win->views; +} + +gint +hd_wm_watched_window_get_n_views (HDWMWatchedWindow *win) +{ + g_return_val_if_fail (win != NULL, 0); + + return g_list_length (win->views); +} + +void +hd_wm_watched_window_add_view (HDWMWatchedWindow *win, + HDWMWatchedWindowView *view) +{ + win->views = g_list_append(win->views, view); +} + +void +hd_wm_watched_window_remove_view (HDWMWatchedWindow *win, + HDWMWatchedWindowView *view) +{ + GList *view_link; + + view_link = g_list_find (win->views, view); + + if (view_link) + win->views = g_list_delete_link(win->views, view_link); +} + +void +hd_wm_watched_window_set_active_view (HDWMWatchedWindow *win, + HDWMWatchedWindowView *view) +{ + win->view_active = view; +} + +HDWMWatchedWindowView* +hd_wm_watched_window_get_active_view (HDWMWatchedWindow *win) +{ + g_return_val_if_fail (win, NULL); + + if (win->view_active) + return win->view_active; + + /* We have no active view set atm so just return the first one. + * Works around some issues with hildon_app_new_with_view() not + * dispatching VIEW_ACTIVE + */ + if (win->views) + return g_list_first(win->views)->data; + + return NULL; +} + +static gboolean +hd_wm_watched_window_sigterm_timeout_cb (gpointer data) +{ + pid_t pid; + + g_return_val_if_fail (data, FALSE); + + pid = (pid_t) GPOINTER_TO_INT (data); + + + HN_DBG ("Checking if pid %d is still around", pid); + + if(pid && !kill (pid, 0)) + { + /* app did not exit in response to SIGTERM, kill it */ + HN_DBG ("App still around, sending SIGKILL"); + + if(kill (pid, SIGKILL)) + { + /* Something went wrong, perhaps we do not have sufficient + * permissions to kill this process + */ + HN_DBG ("SIGKILL failed"); + } + } + + return FALSE; +} + +gboolean +hd_wm_watched_window_attempt_signal_kill (HDWMWatchedWindow *win, + int sig, + gboolean ensure) +{ + guint32 *pid_result = NULL; + + pid_result = hd_wm_util_get_win_prop_data_and_validate + (win->xwin, + hd_wm_get_atom(HN_ATOM_NET_WM_PID), + XA_CARDINAL, + 32, + 0, + NULL); + + if (pid_result == NULL) + return FALSE; + + if(!pid_result[0]) + { + g_warning("PID was 0"); + XFree(pid_result); + return FALSE; + } + + HN_DBG("Attempting to kill pid %d with signal %d", + pid_result[0], sig); + + if (sig == SIGTERM && ensure) + { + /* install timeout to check that the SIGTERM was handled */ + g_timeout_add (HIBERNATION_TIMEMOUT, + (GSourceFunc)hd_wm_watched_window_sigterm_timeout_cb, + GINT_TO_POINTER (pid_result[0])); + } + + /* we would like to use -1 to indicate that children should be + * killed too, but it does not work for some reason + */ + if(kill((pid_t)(pid_result[0]), sig) != 0) + { + HN_DBG("... failed."); + + osso_log(LOG_ERR, "Failed to kill pid %d with signal %d", + pid_result[0], sig); + + XFree(pid_result); + return FALSE; + } + + XFree(pid_result); + return TRUE; +} + +gboolean +hd_wm_watched_window_is_hibernating (HDWMWatchedWindow *win) +{ + HDWMWatchableApp *app; + + app = hd_wm_watched_window_get_app(win); + + if (app && hd_wm_watchable_app_is_hibernating(app)) + return TRUE; + + return FALSE; +} + +void +hd_wm_watched_window_awake (HDWMWatchedWindow *win) +{ + HDWMWatchableApp *app; + osso_manager_t *osso_man; + + app = hd_wm_watched_window_get_app(win); + + if (app) + { + /* Relaunch it with RESTORED */ + hd_wm_watchable_app_set_launching (app, TRUE); + osso_man = osso_manager_singleton_get_instance(); + osso_manager_launch(osso_man, hd_wm_watchable_app_get_service (app), + RESTORED); + + /* do not reset the hibernating flag yet -- we will do that when the app + * creates its first window + */ + } +} + +void +hd_wm_watched_window_destroy (HDWMWatchedWindow *win) +{ + HDWMWatchedWindowView *view; + GtkWidget *note; + + HN_DBG("Removing '%s'", win->name); + + /* Dont destroy windows that are hiberating */ + if (hd_wm_watched_window_is_hibernating(win)) + { + HN_DBG("### Aborting destroying '%s' as hibernating ###", win->name); + return; + } + + /* If ping timeout note is displayed.. */ + note = hd_wm_watchable_app_get_ping_timeout_note (win->app_parent); + + if (note) + { + /* Show infobanner */ + gchar *response_message + = g_strdup_printf (PING_TIMEOUT_RESPONSE_STRING, + win->name ); + + /* Show the infoprint */ + hildon_banner_show_information (NULL, NULL, response_message ); + + g_free (response_message); + + /* .. destroy the infonote */ + gtk_widget_destroy( note ); + hd_wm_watchable_app_set_ping_timeout_note (win->app_parent, NULL); + } + + if(win->info) + { + /* only windows of multiwindow apps have their own info */ + HN_DBG("a window of multiwindow application; removing info from AS"); + hn_app_switcher_remove(hd_wm_get_app_switcher(), + win->info); + hn_entry_info_free (win->info); + win->info = NULL; + } + + /* Destroy the views too */ + while (win->views) + { + view = (HDWMWatchedWindowView *)win->views->data; + + hd_wm_watched_window_view_destroy (view); + + win->views = g_list_delete_link(win->views, win->views); + } + + if (win->name) + XFree(win->name); + + if (win->subname) + XFree(win->subname); + + if (win->hibernation_key) + g_free(win->hibernation_key); + + if (win->pixb_icon) + g_object_unref(win->pixb_icon); + + if(win->app_parent && + win == hd_wm_watchable_app_get_active_window(win->app_parent)) + { + hd_wm_watchable_app_set_active_window(win->app_parent, NULL); + } + + if(hd_wm_get_active_window() == win) + hd_wm_reset_active_window(); + + if(hd_wm_get_last_active_window() == win) + hd_wm_reset_last_active_window(); + + if(win->gdk_wrapper_win) + g_object_unref (win->gdk_wrapper_win); + + g_free(win); +} + +gboolean +hd_wm_watched_window_props_sync (HDWMWatchedWindow *win, gulong props) +{ + gdk_error_trap_push(); + + if (props & HD_WM_SYNC_NAME) + { + hd_wm_watched_window_process_wm_name (win); + } + + if (props & HD_WM_SYNC_HILDON_APP_KILLABLE) + { + hd_wm_watched_window_process_hibernation_prop (win); + } + + if (props & HD_WM_SYNC_WM_STATE) + { + hd_wm_watched_window_process_wm_state (win); + } + + if (props & HD_WM_SYNC_HILDON_VIEW_LIST) + { + hd_wm_watched_window_process_hildon_view_list (win); + } + + if (props & HD_WM_SYNC_HILDON_VIEW_ACTIVE) + { + hd_wm_watched_window_process_hildon_view_active (win); + } + + if (props & HD_WM_SYNC_WMHINTS) + { + hd_wm_watched_window_process_wm_hints (win); + } + + if (props & HD_WM_SYNC_ICON) + { + hd_wm_watched_window_process_net_wm_icon (win); + } + + if (props & HD_WM_SYNC_USER_TIME) + { + hd_wm_watched_window_process_net_wm_user_time (win); + } + + if (props & HD_WM_SYNC_WINDOW_ROLE) + { + hd_wm_watched_window_process_wm_window_role (win); + } + + gdk_error_trap_pop(); + + return TRUE; +} + +void +hd_wm_watched_window_reset_x_win (HDWMWatchedWindow * win) +{ + g_return_if_fail (win); + win->xwin = None; +} + +static void +hd_wm_ping_timeout_dialog_response (GtkDialog *note, gint ret, gpointer data) +{ + HDWMWatchedWindow *win = (HDWMWatchedWindow *)data; + HDWMWatchableApp *app = hd_wm_watched_window_get_app (win); + + gtk_widget_destroy (GTK_WIDGET(note)); + hd_wm_watchable_app_set_ping_timeout_note (app, NULL); + + if (ret == GTK_RESPONSE_OK) + { + /* Kill the app */ + if (!hd_wm_watched_window_attempt_signal_kill (win, SIGKILL, FALSE)) + { + HN_DBG ("hd_wm_ping_timeout: " + "failed to kill application '%s'.", + win->name); + } + } +} + +void +hd_wm_ping_timeout (HDWMWatchedWindow *win) +{ + GtkWidget *note; + + HDWMWatchableApp *app = hd_wm_watched_window_get_app (win); + + gchar *timeout_message + = g_strdup_printf (PING_TIMEOUT_MESSAGE_STRING, win->name ); + + /* FIXME: Do we need to check if the note already exists? */ + note = hd_wm_watchable_app_get_ping_timeout_note( app ); + + if (note && GTK_IS_WIDGET(note)) + { + HN_DBG( "hd_wm_ping_timeout: " + "the note already exists. "); + + goto cleanup_and_exit; + } + + note = hildon_note_new_confirmation (NULL, timeout_message); + + hd_wm_watchable_app_set_ping_timeout_note (app, note); + + hildon_note_set_button_texts (HILDON_NOTE(note), + PING_TIMEOUT_BUTTON_OK_STRING, + PING_TIMEOUT_BUTTON_CANCEL_STRING); + + g_signal_connect (G_OBJECT (note), + "response", + G_CALLBACK (hd_wm_ping_timeout_dialog_response), + win); + + gtk_widget_show_all (note); + +cleanup_and_exit: + + g_free( timeout_message ); +} + + +void +hd_wm_ping_timeout_cancel (HDWMWatchedWindow *win) +{ + HDWMWatchableApp *app = hd_wm_watched_window_get_app( win ); + + GtkWidget *note = hd_wm_watchable_app_get_ping_timeout_note(app); + + gchar *response_message + = g_strdup_printf (PING_TIMEOUT_RESPONSE_STRING, + win->name ); + + if (note && GTK_IS_WIDGET (note)) { + gtk_dialog_response (GTK_DIALOG(note), GTK_RESPONSE_CANCEL); + } + + /* Show the infoprint */ + hildon_banner_show_information (NULL, NULL, response_message ); + + g_free (response_message); +} + + +/* + * Closes window and associated views (if any), handling hibernated + * applications according to the UI spec. +*/ +void +hd_wm_watched_window_close (HDWMWatchedWindow *win) +{ + XEvent ev; + + g_return_if_fail(win); + + if(!hd_wm_watched_window_is_hibernating(win)) + { + /* + * To close the window, we dispatch _NET_CLOSE_WINDOW event to Matchbox. + * This will simulate the pressing of the close button on the app window, + * the app will do its thing, and in turn we will be notified about + * changed client list, triggering the necessary updates of AS, etc. + */ + memset(&ev, 0, sizeof(ev)); + + ev.xclient.type = ClientMessage; + ev.xclient.window = hd_wm_watched_window_get_x_win (win); + ev.xclient.message_type = hd_wm_get_atom(HN_ATOM_NET_CLOSE_WINDOW); + ev.xclient.format = 32; + ev.xclient.data.l[0] = CurrentTime; + ev.xclient.data.l[1] = GDK_WINDOW_XID(gtk_widget_get_parent_window (GTK_WIDGET (tasknav))); + + gdk_error_trap_push(); + XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False, + SubstructureRedirectMask, &ev); + + XSync(GDK_DISPLAY(),FALSE); + gdk_error_trap_pop(); + } +#if 0 + /* + * Disabled util the infrastructure outside of TN for handling this is in + * place + */ + else if(/*have_dirty_data test comes here */) + { + /* + * If the window is hibernating and has dirty data, we need to remove the + * appropriate items from the AS, but we leave the window in our hash, to + * allow for the data to be recovered, and to comply with UI spec 1.0, + * paragraph 6.3 + */ + GList * views = hd_wm_watched_window_get_views (win); + + if(views) + { + while(views) + { + app_switcher_remove_item(hd_wm_get_app_switcher(), + hd_wm_watched_window_view_get_menu( + (HDWMWatchedWindowView*)views->data)); + + views = g_list_next(views); + } + } + else + { + app_switcher_remove_item(hd_wm_get_app_switcher(), + hd_wm_watched_window_get_menu (win)); + } + } +#endif + else /* hibernating window with no dirty data */ + { + /* turn off the hibernation flag in our app to force full destruction */ + HDWMWatchableApp * app = hd_wm_watched_window_get_app (win); + + g_return_if_fail(app); + + /* Set hibernate to FALSE and remove from hibernation hash as not + * hibernating anymore. Note g_hash_table_remove will call + * hd_wm_watched_window_destroy() + */ + hd_wm_watchable_app_set_hibernate(app, FALSE); + + g_hash_table_remove (hd_wm_get_hibernating_windows(), + hd_wm_watched_window_get_hibernation_key(win)); + + /* If the app has any windows left, we need to reset the hibernation + * flag back to TRUE + */ + if(hd_wm_watchable_app_has_hibernating_windows (app)) + hd_wm_watchable_app_set_hibernate(app, TRUE); + } +} + +void +hd_wm_watched_window_set_info (HDWMWatchedWindow *win, + HNEntryInfo *info) +{ + if (win->info) + hn_entry_info_free (win->info); + + win->info = info; +} + +HNEntryInfo * +hd_wm_watched_window_peek_info (HDWMWatchedWindow *win) +{ + return win->info; +} + +HNEntryInfo * +hd_wm_watched_window_create_new_info (HDWMWatchedWindow *win) +{ + if(win->info) + { + /* + * refuse to creat a new info, in case the old one is already referenced + * by AS + */ + g_warning("Window info alread exists"); + } + else + { + win->info = hn_entry_info_new_from_window (win); + } + + return win->info; +} + +void +hd_wm_watched_window_destroy_info (HDWMWatchedWindow *win) +{ + if(win->info) + { + hn_entry_info_free (win->info); + win->info = NULL; + } +} + +gboolean +hd_wm_watched_window_is_active (HDWMWatchedWindow *win) +{ + if(win && win == hd_wm_get_active_window()) + return TRUE; + + return FALSE; +} + Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window.h =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window.h 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm-watched-window.h 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,167 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** +* @file windowmanager.h +*/ + +#ifndef HAVE_HD_WM_WATCHED_WINDOW_H +#define HAVE_HD_WM_WATCHED_WINDOW_H + +#include "hd-wm.h" +#include "hd-wm-util.h" +#include "hd-wm-types.h" + +/* For watched_window_sync(), should go in enum */ + +#define HD_WM_SYNC_NAME (1<<1) +#define HD_WM_SYNC_BIN_NAME (1<<2) +#define HD_WM_SYNC_WMHINTS (1<<3) +#define HD_WM_SYNC_TRANSIANT (1<<4) +#define HD_WM_SYNC_HILDON_APP_KILLABLE (1<<5) +#define HD_WM_SYNC_WM_STATE (1<<6) +#define HD_WM_SYNC_HILDON_VIEW_LIST (1<<7) +#define HD_WM_SYNC_HILDON_VIEW_ACTIVE (1<<8) +#define HD_WM_SYNC_ICON (1<<9) +#define HD_WM_SYNC_USER_TIME (1<<10) +#define HD_WM_SYNC_WINDOW_ROLE (1<<11) +#define HD_WM_SYNC_ALL (G_MAXULONG) + +/* Application relaunch indicator data*/ +#define RESTORED "restored" + +HDWMWatchedWindow* +hd_wm_watched_window_new (Window xid, + HDWMWatchableApp *app); +gboolean +hd_wm_watched_window_props_sync (HDWMWatchedWindow *win, gulong props); + +HDWMWatchableApp* +hd_wm_watched_window_get_app (HDWMWatchedWindow *win); + +Window +hd_wm_watched_window_get_x_win (HDWMWatchedWindow *win); + +void +hd_wm_watched_window_reset_x_win (HDWMWatchedWindow * win); + +gboolean +hd_wm_watched_window_is_urgent (HDWMWatchedWindow *win); + +gboolean +hd_wm_watched_window_wants_no_initial_focus (HDWMWatchedWindow *win); + +const gchar* +hd_wm_watched_window_get_name (HDWMWatchedWindow *win); + +const gchar* +hd_wm_watched_window_get_sub_name (HDWMWatchedWindow *win); + +void +hd_wm_watched_window_set_name (HDWMWatchedWindow *win, + const gchar *name); + +void +hd_wm_watched_window_set_gdk_wrapper_win (HDWMWatchedWindow *win, + GdkWindow *wrapper_win); + +GdkWindow * +hd_wm_watched_window_get_gdk_wrapper_win (HDWMWatchedWindow *win); + +const gchar* +hd_wm_watched_window_get_hibernation_key (HDWMWatchedWindow *win); + + +GtkWidget* +hd_wm_watched_window_get_menu (HDWMWatchedWindow *win); + +void +hd_wm_watched_window_set_menu (HDWMWatchedWindow *win, + GtkWidget *menu); + +/* Note, returns a copy of pixbuf will need freeing */ +GdkPixbuf* +hd_wm_watched_window_get_custom_icon (HDWMWatchedWindow *win); + +GList* +hd_wm_watched_window_get_views (HDWMWatchedWindow *win); + +gint +hd_wm_watched_window_get_n_views (HDWMWatchedWindow *win); + +void +hd_wm_watched_window_add_view (HDWMWatchedWindow *win, + HDWMWatchedWindowView *view); + +void +hd_wm_watched_window_remove_view (HDWMWatchedWindow *win, + HDWMWatchedWindowView *view); +void +hd_wm_watched_window_set_active_view (HDWMWatchedWindow *win, + HDWMWatchedWindowView *view); + +HDWMWatchedWindowView* +hd_wm_watched_window_get_active_view (HDWMWatchedWindow *win); + +gboolean +hd_wm_watched_window_attempt_signal_kill (HDWMWatchedWindow *win, + int sig, + gboolean ensure); + +gboolean +hd_wm_watched_window_is_hibernating (HDWMWatchedWindow *win); + +void +hd_wm_watched_window_awake (HDWMWatchedWindow *win); + +void +hd_wm_watched_window_destroy (HDWMWatchedWindow *win); + +void +hd_wm_ping_timeout( HDWMWatchedWindow *win ); + +void +hd_wm_ping_timeout_cancel( HDWMWatchedWindow *win ); + +void +hd_wm_watched_window_close (HDWMWatchedWindow *win); + +void +hd_wm_watched_window_set_info (HDWMWatchedWindow *win, + HDEntryInfo *info); + +HNEntryInfo * +hd_wm_watched_window_peek_info (HDWMWatchedWindow *win); + +HNEntryInfo * +hd_wm_watched_window_create_new_info (HDWMWatchedWindow *win); + +void +hd_wm_watched_window_destroy_info (HDWMWatchedWindow *win); + +gboolean +hd_wm_watched_window_is_active (HDWMWatchedWindow *win); + +#endif Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm.c =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm.c 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm.c 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,2374 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +#include <string.h> +#include <sys/types.h> +#include <signal.h> +#include <dirent.h> +#include <X11/Xatom.h> + +#include <gdk/gdk.h> +#include <gdk/gdkx.h> +#include <gdk/gdkevents.h> + +#include <hildon-widgets/hildon-defines.h> +#include <hildon-widgets/hildon-banner.h> +#include <hildon-widgets/hildon-note.h> +#include <hildon-widgets/hildon-window.h> + +#include <hildon-base-lib/hildon-base-dnotify.h> + +#include <libosso.h> +#include <log-functions.h> + +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus.h> + +#include "hn-wm.h" +#include "hn-wm-watched-window.h" +#include "hn-wm-watchable-app.h" +#include "hn-wm-watched-window-view.h" +#include "hn-wm-memory.h" +#include "hn-entry-info.h" +#include "hn-app-switcher.h" +#include "osso-manager.h" +#include "hildon-navigator-window.h" +#include "close-application-dialog.h" +#include "hn-keys.h" + +#define SAVE_METHOD "save" +#define KILL_APPS_METHOD "kill_app" +#define TASKNAV_GENERAL_PATH "/com/nokia/tasknav" +#define TASKNAV_SERVICE_NAME "com.nokia.tasknav" +#define TASKNAV_INSENSITIVE_INTERFACE "com.nokia.tasknav.tasknav_insensitive" +#define TASKNAV_SENSITIVE_INTERFACE "com.nokia.tasknav.tasknav_sensitive" + +#define LAUNCH_SUCCESS_TIMEOUT 20 + + +static GdkFilterReturn +hd_wm_x_event_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data); + +static GHashTable* +hd_wm_watchable_apps_init (void); + +static HDWMWatchableApp* +hd_wm_x_window_is_watchable (Window xid); + +static void +hd_wm_reset_focus (void); + +static void +hd_wm_process_x_client_list (void); + +static gboolean +hd_wm_relaunch_timeout(gpointer data); + +struct xwinv +{ + Window *wins; + gint n_wins; +}; + +typedef struct HDWM HDWM; + +struct HDWM /* Our main struct */ +{ + + Atom atoms[HN_ATOM_COUNT]; + + /* WatchedWindows is a hash of watched windows hashed via in X window ID. + * As most lookups happen via window ID's makes sense to hash on this, + */ + GHashTable *watched_windows; + + /* watched windows that are 'hibernating' - i.e there actually not + * running any more but still appear in HN as if they are ( for memory ). + * Split into seperate hash for efficiency reasons. + */ + GHashTable *watched_windows_hibernating; + + /* curretnly active app window */ + HDWMWatchedWindow *active_window; + + /* used to toggle between home and application */ + HDWMWatchedWindow *last_active_window; + + /* A hash of valid watchable apps ( hashed on class name ). This is built + * on startup by slurping in /usr/share/applications/hildon .desktop's + * NOTE: previous code used service/exec/class to refer to class name so + * quite confusing. + */ + GHashTable *watched_apps; + + GList *app_switchers; + + /* stack for the launch banner messages. + * Needed to work round gtk(hindon)_infoprint issues. + */ + GList *banner_stack; + + /* Key bindings and shortcuts */ + HNKeysConfig *keys; + HNKeyShortcut *shortcut; + gulong power_key_timeout; + + /* FIXME: Below memory management related not 100% sure what they do */ + + gulong lowmem_banner_timeout; + gulong lowmem_min_distance; + gulong lowmem_timeout_multiplier; + gboolean lowmem_situation; + + gboolean bg_kill_situation; + gint timer_id; + gboolean about_to_shutdown; + gboolean has_focus; + guint dnotify_timeout_id; + gboolean modal_windows; +}; + +static HDWM hdwm; /* Singleton instance */ + +static gboolean +hd_wm_add_watched_window (HDWMWatchedWindow *win); + + +void +hd_wm_top_item (HNEntryInfo *info) +{ + HDWMWatchedWindow *win = NULL; + HDWMWatchableApp *app; + gboolean single_view = FALSE; + + hd_wm_reset_focus(); + + if (info->type == HN_ENTRY_WATCHED_APP) + { + app = hn_entry_info_get_app (info); + + HN_DBG ("Found app: '%s'", + hd_wm_watchable_app_get_name (app)); + + hd_wm_top_service (hd_wm_watchable_app_get_service (app)); + return; + } + + if (info->type == HN_ENTRY_WATCHED_VIEW) + { + HDWMWatchedWindowView *view = hn_entry_info_get_view (info); + win = hd_wm_watched_window_view_get_parent (view); + app = hd_wm_watched_window_get_app (win); + single_view = (hd_wm_watched_window_get_n_views(win) == 1); + + if (app && hd_wm_watchable_app_is_hibernating(app)) + { + HN_DBG ("Window hibernating, calling hd_wm_top_service\n"); + hd_wm_watched_window_set_active_view(win, view); + hd_wm_top_service (hd_wm_watchable_app_get_service (app)); + return; + } + + HN_DBG ("Sending hildon activate message\n"); + + hd_wm_util_send_x_message (hd_wm_watched_window_view_get_id (view), + hd_wm_watched_window_get_x_win (win), + hdwm.atoms[HN_ATOM_HILDON_VIEW_ACTIVE], + SubstructureRedirectMask | SubstructureNotifyMask, + 0, + 0, + 0, + 0, + 0); + + if(!single_view) + return; + } + + if (info->type == HN_ENTRY_WATCHED_WINDOW || single_view) + { + XEvent ev; + + win = hn_entry_info_get_window (info); + app = hd_wm_watched_window_get_app (win); + + HN_DBG ("Found window without views: '%s'\n", + hd_wm_watched_window_get_name (win)); + + if (app) + { + if (hd_wm_watched_window_is_hibernating (win)) + { + HN_DBG ("Window hibernating, calling hd_wm_top_service\n"); + + /* make sure we top the window user requested */ + hd_wm_watchable_app_set_active_window(app, win); + hd_wm_top_service (hd_wm_watchable_app_get_service (app)); + + return; + } + } + + HN_DBG ("toping non view window (%li) via _NET_ACTIVE_WINDOW message", + hd_wm_watched_window_get_x_win (win)); + + /* FIXME: hd_wm_util_send_x_message() should be used here but wont + * work! + */ + memset (&ev, 0, sizeof (ev)); + + ev.xclient.type = ClientMessage; + ev.xclient.window = hd_wm_watched_window_get_x_win (win); + ev.xclient.message_type = hdwm.atoms[HN_ATOM_NET_ACTIVE_WINDOW]; + ev.xclient.format = 32; + + gdk_error_trap_push (); + XSendEvent (GDK_DISPLAY(), + GDK_ROOT_WINDOW(), False, + SubstructureRedirectMask, &ev); + XSync (GDK_DISPLAY(),FALSE); + gdk_error_trap_pop(); + + } + else + HN_DBG ("### Invalid window type ###\n"); +} + +gboolean +hd_wm_top_service(const gchar *service_name) +{ + osso_manager_t *osso_man; + HDWMWatchedWindow *win; + guint pages_used = 0, pages_available = 0; + + HN_DBG(" Called with '%s'", service_name); + + if (service_name == NULL) + { + osso_log(LOG_ERR, "There was no service name!\n"); + return FALSE; + } + + hd_wm_reset_focus(); + + win = hd_wm_lookup_watched_window_via_service (service_name); + + if (hd_wm_is_lowmem_situation() || + (pages_available > 0 && pages_available < hdwm.lowmem_min_distance)) + { + gboolean killed = TRUE; + if (win == NULL) + { + killed = tn_close_application_dialog(CAD_ACTION_OPENING); + } + else if (hd_wm_watched_window_is_hibernating(win)) + { + killed = tn_close_application_dialog(CAD_ACTION_SWITCHING); + } + + if (!killed) + { + return FALSE; + } + } + + /* Check how much memory we do have until the lowmem threshold */ + + if (!hd_wm_memory_get_limits (&pages_used, &pages_available)) + HN_DBG("### Failed to read memory limits, using scratchbox ??"); + + /* Here we should compare the amount of pages to a configurable + * threshold. Value 0 means that we don't know and assume + * slightly riskily that we can start the app... + * + * This code is not removed to preserve the configurability as fallback + * for non-lowmem situtations + */ + if (pages_available > 0 && pages_available < hdwm.lowmem_min_distance) + { + + gboolean killed = TRUE; + if (win == NULL) + { + killed = tn_close_application_dialog(CAD_ACTION_OPENING); + } + else if (hd_wm_watched_window_is_hibernating(win)) + { + killed = tn_close_application_dialog(CAD_ACTION_SWITCHING); + } + + if (!killed) + { + return FALSE; + } + } + + if (win == NULL) + { + /* We dont have a watched window for this service currently + * so just launch it. + */ + HN_DBG("unable to find service name '%s' in running wins", service_name); + HN_DBG("Thus launcing via osso_manager_launch()"); + osso_man = osso_manager_singleton_get_instance(); + osso_manager_launch(osso_man, service_name, NULL); + return TRUE; + + } + else + { + HDWMWatchableApp *app; + HDWMWatchedWindowView *view = NULL; + + app = hd_wm_watched_window_get_app (win); + + /* set active view before we attempt to waken up hibernating app */ + if (hd_wm_watched_window_get_views (win)) + { + view = hd_wm_watched_window_get_active_view(win); + + if (!view) /* There is no active so just grab the first one */ + { + view = (HDWMWatchedWindowView *)((hd_wm_watched_window_get_views (win))->data); + HN_DBG ("Window does not have active view !!!"); + hd_wm_watched_window_set_active_view(win, view); + } + else + HN_DBG ("Active view [%s]", + hd_wm_watched_window_view_get_name(view)); + + } + + if (hd_wm_watched_window_is_hibernating(win)) + { + guint interval = LAUNCH_SUCCESS_TIMEOUT * 1000; + HDWMWatchedWindow * active_win + = hd_wm_watchable_app_get_active_window(app); + + HN_DBG("app is hibernating, attempting to reawaken" + "via osso_manager_launch()"); + + if (active_win) + { + hd_wm_watched_window_awake (active_win); + } + else + { + /* we do not know which was the active window, so just launch it */ + hd_wm_watchable_app_set_launching (app, TRUE); + osso_man = osso_manager_singleton_get_instance(); + osso_manager_launch(osso_man, hd_wm_watchable_app_get_service (app), + RESTORED); + + } + + /* + we add a timeout allowing us to check the application started, + since we need to display a banner if it did not + */ + HN_DBG("adding launch_timeout() callback"); + g_timeout_add( interval, + hd_wm_relaunch_timeout, + (gpointer) g_strdup(service_name)); + return TRUE; + } + + HN_DBG("sending x message to activate app"); + + if (view) + { + hd_wm_util_send_x_message (hd_wm_watched_window_view_get_id (view), + hd_wm_watched_window_get_x_win (win), + hdwm.atoms[HN_ATOM_HILDON_VIEW_ACTIVE], + SubstructureRedirectMask + |SubstructureNotifyMask, + 0, + 0, + 0, + 0, + 0); + } + else + { + /* Regular or grouped win, get MB to top */ + XEvent ev; + HDWMWatchedWindow *active_win = hd_wm_watchable_app_get_active_window(app); + + memset(&ev, 0, sizeof(ev)); + + HN_DBG("@@@@ Last active window %s\n", + active_win ? hd_wm_watched_window_get_hibernation_key(active_win) : "none"); + + ev.xclient.type = ClientMessage; + ev.xclient.window = hd_wm_watched_window_get_x_win (active_win ? active_win : win); + ev.xclient.message_type = hdwm.atoms[HN_ATOM_NET_ACTIVE_WINDOW]; + ev.xclient.format = 32; + + gdk_error_trap_push(); + XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False, + SubstructureRedirectMask, &ev); + XSync(GDK_DISPLAY(),FALSE); + gdk_error_trap_pop(); + + /* + * do not call hd_wm_watchable_app_set_active_window() from here -- this + * is only a request; we set the window only when it becomes active in + * hd_wm_process_mb_current_app_window() + */ + } + + } + + return TRUE; +} + +#include "close-application-dialog.h" + +void +hd_wm_toggle_desktop (void) +{ + int *desktop_state; + + desktop_state = hd_wm_util_get_win_prop_data_and_validate ( + GDK_WINDOW_XID(gdk_get_default_root_window()), + hdwm.atoms[HN_ATOM_NET_SHOWING_DESKTOP], + XA_CARDINAL, + 32, + 1, + NULL); + + if (desktop_state) + { + if (desktop_state[0] == 1 && hdwm.last_active_window) + { + HDWMWatchableApp* app = + hd_wm_watched_window_get_app(hdwm.last_active_window); + + const gchar * service = hd_wm_watchable_app_get_service (app); + hd_wm_top_service (service); + } + else + { + hd_wm_top_desktop(); + } + + XFree(desktop_state); + } +} + +void +hd_wm_top_desktop(void) +{ + XEvent ev; + + hd_wm_reset_focus(); + + memset(&ev, 0, sizeof(ev)); + + ev.xclient.type = ClientMessage; + ev.xclient.window = GDK_ROOT_WINDOW(); + ev.xclient.message_type = hdwm.atoms[HN_ATOM_NET_SHOWING_DESKTOP]; + ev.xclient.format = 32; + ev.xclient.data.l[0] = 1; + + gdk_error_trap_push(); + XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False, + SubstructureRedirectMask, &ev); + XSync(GDK_DISPLAY(),FALSE); + gdk_error_trap_pop(); + + /* + * FIXME -- this should be reset in response to _NET_SHOWING_DESKTOP event + * but for some reasons we receive one of those *after* each new window is + * created, so that resetting it there means active_window remain NULL and + * this breaks the AS menu focus. + */ + hdwm.active_window = NULL; +} + + +static void +hd_wm_atoms_init() +{ + /* + * The list below *MUST* be kept in the same order as the corresponding + * emun in tm-wm-types.h above or *everything* will break. + * Doing it like this avoids a mass of round trips on startup. + */ + + char *atom_names[] = { + + "WM_CLASS", /* ICCCM */ + "WM_NAME", + "WM_STATE", + "WM_TRANSIENT_FOR", + "WM_HINTS", + "WM_WINDOW_ROLE", + + "_NET_WM_WINDOW_TYPE", /* EWMH */ + "_NET_WM_WINDOW_TYPE_MENU", + "_NET_WM_WINDOW_TYPE_NORMAL", + "_NET_WM_WINDOW_TYPE_DIALOG", + "_NET_WM_WINDOW_TYPE_DESKTOP", + "_NET_WM_STATE", + "_NET_WM_STATE_MODAL", + "_NET_SHOWING_DESKTOP", + "_NET_WM_PID", + "_NET_ACTIVE_WINDOW", + "_NET_CLIENT_LIST", + "_NET_WM_ICON", + "_NET_WM_USER_TIME", + "_NET_WM_NAME", + "_NET_CLOSE_WINDOW", + "_NET_WM_STATE_FULLSCREEN", + + "_HILDON_APP_KILLABLE", /* Hildon only props */ + "_HILDON_ABLE_TO_HIBERNATE",/* alias for the above */ + "_NET_CLIENT_LIST", /* NOTE: Hildon uses these values on app wins*/ + "_NET_ACTIVE_WINDOW", /* for views, thus index is named different */ + /* to improve code readablity. */ + /* Ultimatly the props should be renamed with*/ + /* a _HILDON prefix */ + "_HILDON_FROZEN_WINDOW", + "_HILDON_TN_ACTIVATE", + + "_MB_WIN_SUB_NAME", /* MB Only props */ + "_MB_COMMAND", /* FIXME: Unused */ + "_MB_CURRENT_APP_WINDOW", + "_MB_APP_WINDOW_LIST_STACKING", + "_MB_NUM_MODAL_WINDOWS_PRESENT", + + "UTF8_STRING", + }; + + XInternAtoms (GDK_DISPLAY(), + atom_names, + HN_ATOM_COUNT, + False, + hdwm.atoms); +} + + +static HDWMWatchableApp* +hd_wm_x_window_is_watchable (Window xid) +{ + HDWMWatchableApp *app; + XClassHint class_hint; + Atom *wm_type_atom; + Status status = 0; + + app = NULL; + + memset(&class_hint, 0, sizeof(XClassHint)); + + gdk_error_trap_push(); + + status = XGetClassHint(GDK_DISPLAY(), xid, &class_hint); + + if (gdk_error_trap_pop() || status == 0 || class_hint.res_name == NULL) + goto out; + + /* Does this window class belong to a 'watched' application ? */ + + app = g_hash_table_lookup(hdwm.watched_apps, + (gconstpointer)class_hint.res_name); + + /* FIXME: below checks are really uneeded assuming we trust new MB list prop + */ + wm_type_atom + = hd_wm_util_get_win_prop_data_and_validate (xid, + hdwm.atoms[HN_ATOM_NET_WM_WINDOW_TYPE], + XA_ATOM, + 32, + 0, + NULL); + if (!wm_type_atom) + { + Window trans_win; + Status result; + + /* Assume anything not setting there type is a TYPE_NORMAL. + * This is to support non EWMH 1980 style wins created by + * SDL, alegro etc. + */ + gdk_error_trap_push(); + + result = XGetTransientForHint(GDK_DISPLAY(), xid, &trans_win); + + /* If its transient for something, assume dialog and ignore. + * This should really never happen. + */ + if (gdk_error_trap_pop() || (result && trans_win != None)) + app = NULL; + goto out; + } + + /* Only care about desktop and app wins */ + if (wm_type_atom[0] != hdwm.atoms[HN_ATOM_NET_WM_WINDOW_TYPE_NORMAL] + && wm_type_atom[0] != hdwm.atoms[HN_ATOM_NET_WM_WINDOW_TYPE_DESKTOP]) + { + app = NULL; + XFree(wm_type_atom); + goto out; + } + + if(!app) + { + /* + * If we got this far and have no app, we are dealing with an application + * that did not provide a .desktop file; we are expected to provide + * rudimentary support, so we create a dummy app object. + * + * We do not add this app to the watchable app hash. + */ + + app = hd_wm_watchable_app_new_dummy (); + + HN_DBG(" ## Created dummy application for app without .desktop ##"); + } + + + XFree(wm_type_atom); + + out: + + if (class_hint.res_class) + XFree(class_hint.res_class); + + if (class_hint.res_name) + XFree(class_hint.res_name); + + return app; +} + +/* various lookup functions. */ + +static gboolean +hd_wm_lookup_watched_window_via_service_find_func (gpointer key, + gpointer value, + gpointer user_data) +{ + HDWMWatchedWindow *win; + HDWMWatchableApp *app; + + win = (HDWMWatchedWindow*)value; + + if (win == NULL || user_data == NULL) + return FALSE; + + app = hd_wm_watched_window_get_app (win); + + if (!app) + return FALSE; + + if (hd_wm_watchable_app_get_service (app) + && !strcmp(hd_wm_watchable_app_get_service (app), (gchar*)user_data)) + return TRUE; + + return FALSE; +} + +HDWMWatchedWindow* +hd_wm_lookup_watched_window_via_service (const gchar *service_name) +{ + HDWMWatchedWindow *win = NULL; + + win = g_hash_table_find (hdwm.watched_windows, + hd_wm_lookup_watched_window_via_service_find_func, + (gpointer)service_name); + + if (!win) + { + /* Maybe its stored in our hibernating hash */ + win + = g_hash_table_find (hdwm.watched_windows_hibernating, + hd_wm_lookup_watched_window_via_service_find_func, + (gpointer)service_name); + } + + return win; +} + +#if 0 +static gboolean +hd_wm_lookup_watched_window_via_menu_widget_find_func (gpointer key, + gpointer value, + gpointer user_data) +{ + HDWMWatchedWindow *win; + + win = (HDWMWatchedWindow*)value; + + if (hd_wm_watched_window_get_menu (win) == (GtkWidget*)user_data) + return TRUE; + + return FALSE; +} + + +HDWMWatchedWindow* +hd_wm_lookup_watched_window_via_menu_widget (GtkWidget *menu_widget) +{ + HDWMWatchedWindow *win = NULL; + + win + = g_hash_table_find (hdwm.watched_windows, + hd_wm_lookup_watched_window_via_menu_widget_find_func, + (gpointer)menu_widget); + + if (!win) + { + /* Maybe its stored in our hibernating hash + */ + win = g_hash_table_find (hdwm.watched_windows_hibernating, + hd_wm_lookup_watched_window_via_menu_widget_find_func, + (gpointer)menu_widget); + } + + return win; +} +#endif + +static gboolean +hd_wm_lookup_watchable_app_via_service_find_func (gpointer key, + gpointer value, + gpointer user_data) +{ + HDWMWatchableApp *app; + + app = (HDWMWatchableApp *)value; + + if (app == NULL || user_data == NULL) + return FALSE; + + if (hd_wm_watchable_app_get_service (app) == NULL) + return FALSE; + + if (hd_wm_watchable_app_get_service (app) && + !strcmp(hd_wm_watchable_app_get_service (app), (gchar*)user_data)) + return TRUE; + + return FALSE; +} + +HDWMWatchableApp* +hd_wm_lookup_watchable_app_via_service (const gchar *service_name) +{ + return g_hash_table_find ( hdwm.watched_apps, + hd_wm_lookup_watchable_app_via_service_find_func, + (gpointer)service_name); +} + +static gboolean +hd_wm_lookup_watchable_app_via_exec_find_func (gpointer key, + gpointer value, + gpointer user_data) +{ + HDWMWatchableApp *app = (HDWMWatchableApp *)value; + const gchar *exec_name; + + if (app == NULL || user_data == NULL) + return FALSE; + + exec_name = hd_wm_watchable_app_get_exec(app); + + if (exec_name && !strcmp(exec_name, (gchar*)user_data)) + return TRUE; + + return FALSE; +} + +HDWMWatchableApp * +hd_wm_lookup_watchable_app_via_exec (const gchar *exec_name) +{ + return g_hash_table_find(hdwm.watched_apps, + hd_wm_lookup_watchable_app_via_exec_find_func, + (gpointer)exec_name); +} + +#if 0 +HDWMWatchableApp* +hd_wm_lookup_watchable_app_via_menu (GtkWidget *menu) +{ + HDWMWatchedWindow *win; + + win = hd_wm_lookup_watched_window_via_menu_widget (menu); + + if (!win) + win = hd_wm_lookup_watched_window_view (menu); + + if (win) + return hd_wm_watched_window_get_app (win); + + return NULL; +} +#endif + +static gboolean +hd_wm_lookup_watched_window_view_find_func (gpointer key, + gpointer value, + gpointer user_data) +{ + HDWMWatchedWindow *win; + GList *iter; + + win = (HDWMWatchedWindow*)value; + + iter = hd_wm_watched_window_get_views (win); + + while (iter != NULL) + { + HDWMWatchedWindowView *view; + + view = (HDWMWatchedWindowView *)iter->data; + + if (hd_wm_watched_window_view_get_menu (view) == (GtkWidget*)user_data) + return TRUE; + + iter = g_list_next(iter); + } + + return FALSE; +} + +HDWMWatchedWindow* +hd_wm_lookup_watched_window_view (GtkWidget *menu_widget) +{ + HDWMWatchedWindow *win; + + win = g_hash_table_find ( hdwm.watched_windows, + hd_wm_lookup_watched_window_view_find_func, + (gpointer)menu_widget); + + if (!win) + { + HN_DBG("checking WatchedWindowsHibernating hash, has %i items", + g_hash_table_size (hdwm.watched_windows_hibernating)); + + win = g_hash_table_find ( hdwm.watched_windows_hibernating, + hd_wm_lookup_watched_window_view_find_func, + (gpointer)menu_widget); + } + + return win; +} + + +/* Root win property changes */ + +static void +hd_wm_process_mb_current_app_window (void) +{ + Window previous_app_xwin = 0; + + HDWMWatchedWindow *win; + Window *app_xwin; + GList *views; + + HN_DBG ("called"); + + if(hdwm.active_window) + previous_app_xwin = hd_wm_watched_window_get_x_win (hdwm.active_window); + + app_xwin = hd_wm_util_get_win_prop_data_and_validate (GDK_ROOT_WINDOW(), + hdwm.atoms[HN_ATOM_MB_CURRENT_APP_WINDOW], + XA_WINDOW, + 32, + 0, + NULL); + if (!app_xwin) + return; + + if (*app_xwin == previous_app_xwin) + goto out; + + previous_app_xwin = *app_xwin; + + win = g_hash_table_lookup(hdwm.watched_windows, (gconstpointer)app_xwin); + + if (win) + { + HDWMWatchableApp *app; + + app = hd_wm_watched_window_get_app (win); + + if (!app) + goto out; + + hd_wm_watchable_app_set_active_window(app, win); + + hd_wm_watchable_app_set_active_window(app, win); + hdwm.active_window = hdwm.last_active_window = win; + + /* Note: this is whats grouping all views togeather */ + views = hd_wm_watched_window_get_views (win); + if (views) + { + GList *l; + + for (l = views; l != NULL; l = l->next) + { + HDWMWatchedWindowView *view = l->data; + HNEntryInfo *info = hd_wm_watched_window_view_get_info (view); + + g_debug ("%s: %d, Here we notify changed stack to as",__FILE__,__LINE__); + /* + hn_app_switcher_changed_stack (hdwm.app_switcher, info); + */ + } + } + else + { + /* Window with no views */ + HN_DBG("Window 0x%x just became active", (int)win); + HNEntryInfo *info = hd_wm_watched_window_peek_info (win); + + g_debug ("%s: %d, Here we notify changed stack to as",__FILE__,__LINE__); + /* + hn_app_switcher_changed_stack (hdwm.app_switcher, info); + */ + } + } + else + { + /* this happens when, for example, when Home is topped, or an application + * gets minimised and the desktop is showing. We need to notify the AS to + * deactivate any active buttons. + */ + /* + HNEntryInfo * info + = hn_app_switcher_get_home_entry_info (hdwm.app_switcher); + */ + if (info) + /*hn_app_switcher_changed_stack (hdwm.app_switcher, info);*/ + g_debug ("%s: %d, Here we try to get home entry and we notify changed stack to as",__FILE__,__LINE__); + else + HN_DBG ("***************** No Home info yet"); + } + +out: + XFree(app_xwin); +} + +static gboolean +client_list_steal_foreach_func (gpointer key, + gpointer value, + gpointer userdata) +{ + HDWMWatchedWindow *win; + struct xwinv *xwins; + GdkWindow *gdk_win_wrapper = NULL; + int i; + + xwins = (struct xwinv*)userdata; + win = (HDWMWatchedWindow *)value; + + /* check if the window is on the list */ + for (i=0; i < xwins->n_wins; i++) + if (G_UNLIKELY((xwins->wins[i] == hd_wm_watched_window_get_x_win (win)))) + { + /* if the window is on the list, we do not touch it */ + return FALSE; + } + + /* not on the list */ + if (hd_wm_watched_window_is_hibernating (win)) + { + /* the window is marked as hibernating, we move it to the hibernating + * windows hash + */ + HDWMWatchableApp * app; + HNEntryInfo * app_info = NULL; + + HN_DBG ("hibernating window [%s], moving to hibernating hash", + hd_wm_watched_window_get_hibernation_key(win)); + + g_hash_table_insert (hd_wm_get_hibernating_windows(), + g_strdup (hd_wm_watched_window_get_hibernation_key(win)), + win); + + /* reset the window xid */ + hd_wm_watched_window_reset_x_win (win); + + /* update AS */ + app = hd_wm_watched_window_get_app (win); + + if (app) + app_info = hd_wm_watchable_app_get_info (app); + /* + hn_app_switcher_changed (hdwm.app_switcher, app_info); + */ + g_debug ("%s: %d, Here we notify changes to as",__FILE__,__LINE__); + /* free the original hash key, since we are stealing */ + g_free (key); + + /* remove it from watched hash */ + return TRUE; + } + + /* not on the list and not hibernating, we have to explicitely destroy the + * hash entry and its key, since we are using a steal function + */ + + /* Explicitely remove the event filter */ + gdk_win_wrapper = hd_wm_watched_window_get_gdk_wrapper_win (win); + + if (gdk_win_wrapper) + gdk_window_remove_filter (gdk_win_wrapper, + hd_wm_x_event_filter, + NULL); + + hd_wm_watched_window_destroy (win); + g_free (key); + + /* remove the entry from our hash */ + return TRUE; +} + +static void +hd_wm_process_x_client_list(void) +{ + struct xwinv xwins; + int i; + + /* FIXME: We (or MB!) should probably keep a copy of ordered window list + * that way we can check against new list for changes before to save + * some hash lookups etc. + * + * Also now we have the list in stacking order could use this to update + * app switcher ordering more efficiently, but need to figure out how + * that works first. + */ + + xwins.wins + = hd_wm_util_get_win_prop_data_and_validate (GDK_ROOT_WINDOW(), + hdwm.atoms[HN_ATOM_MB_APP_WINDOW_LIST_STACKING], + XA_WINDOW, + 32, + 0, + &xwins.n_wins); + + if (G_UNLIKELY(xwins.wins == NULL)) + { + g_warning("Failed to read _MB_APP_WINDOW_LIST_STACKING root win prop, " + "you probably need a newer matchbox !!!"); + } + + /* Check if any windows in our hash have since disappeared -- we use + * foreach_steal here because some of the windows that disappeared might in + * fact be hibernating, and we do not want to destroy those, see + * client_list_steal_foreach_func () + */ + g_hash_table_foreach_steal ( hdwm.watched_windows, + client_list_steal_foreach_func, + (gpointer)&xwins); + + /* Now add any new ones */ + for (i=0; i < xwins.n_wins; i++) + { + if (!g_hash_table_lookup(hdwm.watched_windows, + (gconstpointer)&xwins.wins[i])) + { + HDWMWatchedWindow *win; + HDWMWatchableApp *app; + + /* We've found a window thats listed but not currently watched. + * Check if it is watchable by us + */ + app = hd_wm_x_window_is_watchable (xwins.wins[i]); + + if (!app) + continue; + + win = hd_wm_watched_window_new (xwins.wins[i], app); + + if (!win) + continue; + + + if (!hd_wm_add_watched_window (win)) + continue; /* XError likely occured, xwin gone */ + + /* since we now have a window for the application, we clear any + * outstanding is_launching flag + */ + hd_wm_watchable_app_set_launching (app, FALSE); + + /* Grab the view prop from the window and add any views. + * Note this will add menu items for em. + */ + hd_wm_watched_window_props_sync (win, HN_WM_SYNC_HILDON_VIEW_LIST); + + if (hd_wm_watchable_app_is_dummy (app)) + g_warning("Application %s did not provide valid .desktop file", + hd_wm_watched_window_get_name(win)); + + if (hd_wm_watched_window_get_n_views (win) == 0) + { + HNEntryInfo *info; + + HN_MARK(); + + /* if the window does not have attached info yet, then it is new + * and needs to be added to AS; if it has one, then it is coming + * out of hibernation, in which case it must not be added + */ + info = hd_wm_watched_window_peek_info (win); + if (!info) + { + info = hd_wm_watched_window_create_new_info (win); + HN_DBG ("Adding AS entry for view-less window\n"); + + g_debug ("%s: %d, Here we add entry to as",__FILE__,__LINE__); + + /* + hn_app_switcher_add (hdwm.app_switcher, info); + */ + } + } + } + } + + if (xwins.wins) + XFree(xwins.wins); +} + +gboolean +hd_wm_add_watched_window (HDWMWatchedWindow *win) +{ + GdkWindow *gdk_wrapper_win = NULL; + gint *key; + + key = g_new0 (gint, 1); + + if (!key) /* FIXME: Handle OOM */ + return FALSE; + + *key = hd_wm_watched_window_get_x_win(win); + + gdk_error_trap_push(); + + gdk_wrapper_win = gdk_window_foreign_new (*key); + + if (gdk_wrapper_win != NULL) + { + XWindowAttributes attributes; + + XGetWindowAttributes (GDK_DISPLAY (), + GDK_WINDOW_XID (gdk_wrapper_win), + &attributes); + + XSelectInput (GDK_DISPLAY (), + GDK_WINDOW_XID (gdk_wrapper_win), + attributes.your_event_mask + | StructureNotifyMask + | PropertyChangeMask); + + gdk_window_add_filter (gdk_wrapper_win, + hd_wm_x_event_filter, + NULL); + } + + XSync (GDK_DISPLAY(), False); /* FIXME: Check above does not sync */ + + if (gdk_error_trap_pop () || gdk_wrapper_win == NULL) + goto abort; + + hd_wm_watched_window_set_gdk_wrapper_win (win, gdk_wrapper_win); + + g_hash_table_insert (hdwm.watched_windows, key, (gpointer)win); + + /* we also mark this as the active window */ + hdwm.active_window = hdwm.last_active_window = win; + hd_wm_watchable_app_set_active_window (hd_wm_watched_window_get_app (win), + win); + + return TRUE; + + abort: + + if (win) + hd_wm_watched_window_destroy (win); + + if (gdk_wrapper_win) + g_object_unref (gdk_wrapper_win); + + return FALSE; +} + +static void +hd_wm_reset_focus () +{ + + if(hdwm.has_focus) + { + HN_DBG("Making TN unfocusable"); + hdwm.has_focus = FALSE; + g_debug ("%s: %d, set focus to tn to false",__FILE__,__LINE__); + /*hn_window_set_focus (tasknav,FALSE);*/ + } +}; + + +void +hd_wm_focus_active_window () +{ + if(hdwm.active_window) + { + HDWMWatchableApp* app = hd_wm_watched_window_get_app(hdwm.active_window); + const gchar * service = hd_wm_watchable_app_get_service (app); + hd_wm_top_service (service); + } + else + { + hd_wm_top_desktop(); + } +} + +void +hd_wm_activate(guint32 what) +{ + GtkWidget * button = NULL; + + g_debug ("received request %d", what); + + if (what >= (int) HN_TN_ACTIVATE_LAST) + { + g_critical("Invalid value passed to hd_wm_activate()"); + return; + } + + switch (what) + { + case HN_TN_ACTIVATE_KEY_FOCUS: + HN_DBG("Making TN focusable"); + hdwm.has_focus = TRUE; + + g_debug ("%s: %d, set focus to tn to true",__FILE__,__LINE__); + /*hn_window_set_focus (tasknav,TRUE);*/ + return; + + case HN_TN_DEACTIVATE_KEY_FOCUS: + HN_DBG("Making TN unfocusable"); + hdwm.has_focus = FALSE; + + g_debug ("%s: %d, set focus to tn to false",__FILE__,__LINE__); + /*hn_window_set_focus (tasknav,FALSE);*/ + return; + + case HN_TN_ACTIVATE_MAIN_MENU: + HN_DBG("activating main menu"); + + g_debug ("%s: %d, Here we toggle appswitcher's menu button",__FILE__,__LINE__); + + /*hn_app_switcher_toggle_menu_button (hdwm.app_switcher);*/ + return; + + case HN_TN_ACTIVATE_LAST_APP_WINDOW: + HN_DBG("passing focus to last active window"); + hdwm.has_focus = FALSE; + hd_wm_focus_active_window (); + return; + + default: + + g_debug ("%s: %d, try to activate button in tasknav",__FILE__,__LINE__); + /* + button = hn_window_get_button_focus (tasknav,what); + if(button) + { + HN_DBG("activating some other button"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); + g_signal_emit_by_name(button, "toggled"); + } + */ + } +} + +static gboolean +hdwm_power_key_timeout (gpointer data) +{ + if (hdwm.shortcut != NULL && + hdwm.shortcut->action == HN_KEY_ACTION_POWER) + { + hdwm.shortcut->action_func (hdwm.keys, GINT_TO_POINTER(TRUE)); + hdwm.shortcut = NULL; + } + + hdwm.power_key_timeout = 0; + return FALSE; +} + +/* Main event filter */ + +static GdkFilterReturn +hd_wm_x_event_filter (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + XPropertyEvent *prop; + HDWMWatchedWindow *win = NULL; + + /* Handle client messages */ + + if (((XEvent*)xevent)->type == ClientMessage) + { + XClientMessageEvent *cev = (XClientMessageEvent *)xevent; + + if (cev->message_type == hdwm.atoms[HN_ATOM_HILDON_FROZEN_WINDOW]) + { + Window xwin_hung; + gboolean has_reawoken; + + xwin_hung = (Window)cev->data.l[0]; + has_reawoken = (gboolean)cev->data.l[1]; + + HN_DBG("@@@@ FROZEN: Window %li status %i @@@@", + xwin_hung, has_reawoken); + + win = g_hash_table_lookup(hdwm.watched_windows, + &xwin_hung); + + if ( win ) { + if ( has_reawoken == TRUE ) { + hd_wm_ping_timeout_cancel( win ); + } else { + hd_wm_ping_timeout( win ); + } + } + + } + else if (cev->message_type == hdwm.atoms[HN_ATOM_HILDON_TN_ACTIVATE]) + { + HN_DBG("_HILDON_TN_ACTIVATE: %d", (int)cev->data.l[0]); + hd_wm_activate(cev->data.l[0]); + } + return GDK_FILTER_CONTINUE; + } + + if (((XEvent*)xevent)->type == KeyPress) + { + XKeyEvent *kev = (XKeyEvent *)xevent; + hdwm.shortcut = hn_keys_handle_keypress (hdwm.keys, kev->keycode, kev->state); + + if (hdwm.shortcut != NULL && + hdwm.shortcut->action == HN_KEY_ACTION_POWER && + !hdwm.power_key_timeout) + { + hdwm.power_key_timeout = g_timeout_add + (HILDON_WINDOW_LONG_PRESS_TIME, + hdwm_power_key_timeout, NULL); + } + + return GDK_FILTER_CONTINUE; + } + else if (((XEvent*)xevent)->type == KeyRelease) + { + if (hdwm.power_key_timeout) + { + g_source_remove (hdwm.power_key_timeout); + hdwm.power_key_timeout = 0; + } + + if (hdwm.shortcut != NULL) + { + if (!hd_wm_modal_windows_present()) + hdwm.shortcut->action_func (hdwm.keys, hdwm.shortcut->action_func_data); + hdwm.shortcut = NULL; + } + return GDK_FILTER_CONTINUE; + } + + /* If this isn't a property change event ignore ASAP */ + if (((XEvent*)xevent)->type != PropertyNotify) + return GDK_FILTER_CONTINUE; + + prop = (XPropertyEvent*)xevent; + + /* Root window property change */ + + if (G_LIKELY(prop->window == GDK_ROOT_WINDOW())) + { + if (prop->atom == hdwm.atoms[HN_ATOM_MB_APP_WINDOW_LIST_STACKING]) + { + hd_wm_process_x_client_list(); + } + else if (prop->atom == hdwm.atoms[HN_ATOM_MB_CURRENT_APP_WINDOW]) + { + hd_wm_process_mb_current_app_window (); + } + else if (prop->atom == hdwm.atoms[HN_ATOM_NET_SHOWING_DESKTOP]) + { + int *desktop_state; + + desktop_state = + hd_wm_util_get_win_prop_data_and_validate (GDK_WINDOW_XID(gdk_get_default_root_window()), + hdwm.atoms[HN_ATOM_NET_SHOWING_DESKTOP], + XA_CARDINAL, + 32, + 1, + NULL); + if (desktop_state) + { + if (desktop_state[0] == 1) + { + hdwm.active_window = NULL; + } + + XFree(desktop_state); + } + } + else if (prop->atom == hdwm.atoms[HN_ATOM_MB_NUM_MODAL_WINDOWS_PRESENT]) + { + HN_DBG ("Received MODAL WINDOWS notification"); + + int * value; + + value = + hd_wm_util_get_win_prop_data_and_validate ( + GDK_WINDOW_XID(gdk_get_default_root_window()), + hdwm.atoms[HN_ATOM_MB_NUM_MODAL_WINDOWS_PRESENT], + XA_CARDINAL, + 32, + 1, + NULL); + + if (value) + { + hdwm.modal_windows = *value; + HN_DBG ("value = %d", hdwm.modal_windows); + XFree(value); + } + } + } + else /* Non root win prop change */ + { + /* Hopefully one of our watched windows changing a prop.. + * + * Check if its an atom were actually interested in + * before doing the assumed to be more expensive hash + * lookup. FIXME: hmmm.. + */ + + if ( prop->atom == hdwm.atoms[HN_ATOM_WM_NAME] + || prop->atom == hdwm.atoms[HN_ATOM_WM_STATE] + || prop->atom == hdwm.atoms[HN_ATOM_HILDON_VIEW_LIST] + || prop->atom == hdwm.atoms[HN_ATOM_HILDON_VIEW_ACTIVE] + || prop->atom == hdwm.atoms[HN_ATOM_HILDON_APP_KILLABLE] + || prop->atom == hdwm.atoms[HN_ATOM_HILDON_ABLE_TO_HIBERNATE] + || prop->atom == hdwm.atoms[HN_ATOM_NET_WM_STATE] + || prop->atom == hdwm.atoms[HN_ATOM_WM_HINTS] + || prop->atom == hdwm.atoms[HN_ATOM_NET_WM_ICON] + || prop->atom == hdwm.atoms[HN_ATOM_MB_WIN_SUB_NAME] + || prop->atom == hdwm.atoms[HN_ATOM_NET_WM_NAME] + || prop->atom == hdwm.atoms[HN_ATOM_WM_WINDOW_ROLE]) + + { + win = g_hash_table_lookup(hdwm.watched_windows, + (gconstpointer)&prop->window); + } + + if (!win) + return GDK_FILTER_CONTINUE; + + if (prop->atom == hdwm.atoms[HN_ATOM_WM_NAME] + || prop->atom == hdwm.atoms[HN_ATOM_MB_WIN_SUB_NAME] + || prop->atom == hdwm.atoms[HN_ATOM_NET_WM_NAME]) + { + hd_wm_watched_window_props_sync (win, HN_WM_SYNC_NAME); + } + else if (prop->atom == hdwm.atoms[HN_ATOM_WM_STATE]) + { + hd_wm_watched_window_props_sync (win, HN_WM_SYNC_WM_STATE); + } + else if (prop->atom == hdwm.atoms[HN_ATOM_NET_WM_ICON]) + { + hd_wm_watched_window_props_sync (win, HN_WM_SYNC_ICON); + } + else if (prop->atom == hdwm.atoms[HN_ATOM_HILDON_VIEW_ACTIVE]) + { + hd_wm_watched_window_props_sync (win, HN_WM_SYNC_HILDON_VIEW_ACTIVE); + } + else if (prop->atom == hdwm.atoms[HN_ATOM_WM_HINTS]) + { + hd_wm_watched_window_props_sync (win, HN_WM_SYNC_WMHINTS); + } + else if (prop->atom == hdwm.atoms[HN_ATOM_HILDON_VIEW_LIST]) + { + hd_wm_watched_window_props_sync (win, HN_WM_SYNC_HILDON_VIEW_LIST); + } + else if (prop->atom == hdwm.atoms[HN_ATOM_WM_WINDOW_ROLE]) + { + /* Windows realy shouldn't do this... */ + hd_wm_watched_window_props_sync (win, HN_WM_SYNC_WINDOW_ROLE); + } + else if (prop->atom == hdwm.atoms[HN_ATOM_HILDON_APP_KILLABLE] + || prop->atom == hdwm.atoms[HN_ATOM_HILDON_ABLE_TO_HIBERNATE]) + { + HDWMWatchableApp *app; + + app = hd_wm_watched_window_get_app(win); + + if (prop->state == PropertyDelete) + { + hd_wm_watchable_app_set_able_to_hibernate (app, FALSE); + } + else + { + hd_wm_watched_window_props_sync (win, + HN_WM_SYNC_HILDON_APP_KILLABLE); + } + } + } + + return GDK_FILTER_CONTINUE; +} + +#if 0 +static void +hd_wm_watchable_apps_reload (void) +{ + GHashTable *watchable_apps; + HDWMWatchableApp *app; + DIR *directory; + struct dirent *entry = NULL; + + HN_DBG("Attempting to open directory [%s]", DESKTOPENTRYDIR); + + if ((directory = opendir(DESKTOPENTRYDIR)) == NULL) + { + HN_DBG(" ##### Failed in opening " DESKTOPENTRYDIR " ##### "); + return NULL; + } + + watchable_apps = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)hd_wm_watchable_app_destroy); + + while ((entry = readdir(directory)) != NULL) + { + gchar *path; + + if (!g_str_has_suffix(entry->d_name, DESKTOP_SUFFIX)) + continue; + + path = g_build_filename(DESKTOPENTRYDIR, entry->d_name, NULL); + + HN_DBG("Attempting to open desktop file [%s] ...", path); + + app = hd_wm_watchable_app_new (path); + + if (app) + { + g_hash_table_insert (watchable_apps, + g_strdup(hd_wm_watchable_app_get_class_name (app)), + (gpointer)app); + } + + g_free(path); + } + + closedir(directory); + + return watchable_apps; +} +#endif + +/* DBus related callbacks */ + +static DBusHandlerResult +hd_wm_dbus_method_call_handler (DBusConnection *connection, + DBusMessage *message, + void *data ) +{ + const gchar *path; + + /* Catch APP_LAUNCH_BANNER_METHOD */ + if (dbus_message_is_method_call (message, + APP_LAUNCH_BANNER_METHOD_INTERFACE, + APP_LAUNCH_BANNER_METHOD ) ) + { + DBusError error; + gchar *service_name = NULL; + HDWMWatchableApp *app; + + dbus_error_init (&error); + + dbus_message_get_args (message, + &error, + DBUS_TYPE_STRING, + &service_name, + DBUS_TYPE_INVALID ); + + if (dbus_error_is_set (&error)) + { + osso_log(LOG_WARNING, "Error getting message args: %s\n", + error.message); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + + g_return_val_if_fail (service_name, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + + HN_DBG("Checking if service: '%s' is watchable", service_name); + + /* Is this 'service' watchable ? */ + if ((app = hd_wm_lookup_watchable_app_via_service (service_name)) != NULL) + { + if (hd_wm_watchable_app_has_startup_notify (app) + && hdwm.lowmem_banner_timeout > 0 + && !hd_wm_watchable_app_has_windows (app)) + { + HN_DBG("Showing Launchbanner..."); + /* + * This function takes care of the distinction between the Loading + * and Resuming banners, hence we no longer test for hibernation + */ + hd_wm_watchable_app_launch_banner_show (app); + } + } + } + + path = dbus_message_get_path(message); + if (path != NULL && g_str_equal(path, TASKNAV_GENERAL_PATH)) + { + const gchar * interface = dbus_message_get_interface(message); + if (g_str_equal(interface, TASKNAV_SENSITIVE_INTERFACE)) + { + g_debug ("%s: %d, set sensitiveness to tn to true",__FILE__,__LINE__); + /* hn_window_set_sensitive (tasknav,TRUE); */ + return DBUS_HANDLER_RESULT_HANDLED; + } + else if (g_str_equal(interface, TASKNAV_INSENSITIVE_INTERFACE)) + { + g_debug ("%s: %d, set sensitiveness to tn to false",__FILE__,__LINE__); + /* hn_window_set_sensitive (tasknav,TRUE); */ + return DBUS_HANDLER_RESULT_HANDLED; + } + } + + + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult +hd_wm_dbus_signal_handler(DBusConnection *conn, DBusMessage *msg, void *data) +{ + if (dbus_message_is_signal(msg, MAEMO_LAUNCHER_SIGNAL_IFACE, + APP_DIED_SIGNAL_NAME)) + { + DBusError err; + gchar *filename; + int pid; + int status; + HDWMWatchableApp *app; + + + dbus_error_init(&err); + + dbus_message_get_args(msg, &err, + DBUS_TYPE_STRING, &filename, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INT32, &status, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) + { + osso_log(LOG_WARNING, "Error getting message args: %s\n", + err.message); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + HN_DBG("Checking if filename: '%s' is watchable pid='%i' status='%i'", + filename, pid, status); + + /* Is this 'filename' watchable ? */ + app = hd_wm_lookup_watchable_app_via_exec(filename); + if (app) + { + HN_DBG("Showing app died dialog ..."); + hd_wm_watchable_app_died_dialog_show(app); + } + return DBUS_HANDLER_RESULT_HANDLED; + } + + if (dbus_message_is_signal(msg, APPKILLER_SIGNAL_INTERFACE, + APPKILLER_SIGNAL_NAME)) + { + hd_wm_memory_kill_all_watched(FALSE); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +struct _cb_steal_data +{ + GHashTable *apps; + gboolean update; +}; + +/* iterates over the new hash and carries out updates on the old hash */ +static gboolean +dnotify_hash_table_foreach_steal_func (gpointer key, + gpointer value, + gpointer user_data) +{ + struct _cb_steal_data* old_apps = (struct _cb_steal_data*)user_data; + HDWMWatchableApp *old_app, * new_app = (HDWMWatchableApp *)value; + + old_app = g_hash_table_lookup(old_apps->apps, key); + + if(!old_app) + { + /* + * we need to insert new_app into the old apps hash + */ + HN_DBG("Inserting a new application"); + g_hash_table_insert(old_apps->apps, + g_strdup(hd_wm_watchable_app_get_class_name(new_app)), + new_app); + + /* indicate that the app should be removed from the new apps hash */ + return TRUE; + } + else + { + /* + * we already have this app in the old_app hash, so we need to update + * it + */ + HN_DBG("Updating existing application"); + old_apps->update |= hd_wm_watchable_app_update(old_app, new_app); + + /* the original should be left in the in new apps hash */ + return FALSE; + } +} + +/* iterates over the old app hash and removes any apps that disappeared */ +static gboolean +dnotify_hash_table_foreach_remove_func (gpointer key, + gpointer value, + gpointer user_data) +{ + GHashTable *new_apps = (GHashTable*)user_data; + HDWMWatchableApp *new_app, * old_app = (HDWMWatchableApp *)value; + + new_app = g_hash_table_lookup(new_apps, key); + + if(!new_app) + { + /* this app is gone, but we can only remove if it is not running */ + if(!hd_wm_watchable_app_has_windows(old_app) && + !hd_wm_watchable_app_has_hibernating_windows(old_app)) + { + return TRUE; + } + else + { + g_warning("it looks like someone uninstalled a running application"); + } + } + + return FALSE; +} + +static gboolean +hd_wm_dnotify_process () +{ + GHashTable * new_apps; + struct _cb_steal_data std; + + hdwm.dnotify_timeout_id = 0; + + /* reread all .desktop files and compare each agains existing apps; add any + * new ones, updated existing ones + * + * This is quite involved, so we will take a shortcut if we can + */ + + if(!g_hash_table_size(hdwm.watched_windows) && + !g_hash_table_size(hdwm.watched_windows_hibernating)) + { + /* + * we have no watched windows, i.e., no references to the apps, so we can + * just replace the old apps with the new ones + */ + HN_DBG("Have no watched windows -- reinitialising watched apps"); + g_hash_table_destroy(hdwm.watched_apps); + hdwm.watched_apps = hd_wm_watchable_apps_init(); + return FALSE; + } + + HN_DBG("Some watched windows -- doing it the hard way"); + + new_apps = hd_wm_watchable_apps_init(); + + /* + * first we iterate the old hash, looking for any apps that no longer + * exist in the new one + */ + g_hash_table_foreach_remove(hdwm.watched_apps, + dnotify_hash_table_foreach_remove_func, + new_apps); + + /* + * then we do updates on what is left in the old hash + */ + std.apps = hdwm.watched_apps; + std.update = FALSE; + + g_hash_table_foreach_steal(new_apps, + dnotify_hash_table_foreach_steal_func, + &std); + + if(std.update) + { + HN_DBG("Some apps updated -- notifying AS"); + + g_debug ("%s: %d, Here we notify changes to as",__FILE__,__LINE__); + /* + hn_app_switcher_changed (hdwm.app_switcher, NULL); + */ + } + + /* whatever is left in the new_apps hash, we are not interested in */ + g_hash_table_destroy(new_apps); + + return FALSE; +} + + + +static int +hd_wm_osso_kill_method(GArray *arguments, gpointer data) +{ + gchar *appname = NULL, *operation = NULL; + HDWMWatchedWindow *win = NULL; + HDWMWatchableApp *app; + + if (arguments->len < 1) + return 1; + + operation = (gchar *)g_array_index(arguments, osso_rpc_t, 0).value.s; + + /* In this case, HN will kill every process that has supposedly + * statesaved + */ + + if (operation == NULL) + return 1; + + if (strcmp(operation, "lru") == 0) + { + return hd_wm_memory_kill_lru(); + } + else if (strcmp(operation, "all") == 0) + { + return hd_wm_memory_kill_all_watched(TRUE); + } + else if (strcmp(operation, "app") != 0 || (arguments->len < 2) ) + { + return 1; + } + + /* Kill a certain application */ + + appname = (gchar *)g_array_index(arguments, osso_rpc_t, 1).value.s; + + if (appname == NULL) + return 1; + + win = hd_wm_lookup_watched_window_via_service (appname); + app = hd_wm_watched_window_get_app (win); + + if (win) + { + if (hd_wm_watchable_app_is_able_to_hibernate (app)) + hd_wm_watched_window_attempt_signal_kill (win, SIGTERM, TRUE); + } + + return 0; +} + +/* FIXME -- this function does nothing */ +static gboolean +hd_wm_relaunch_timeout(gpointer data) +{ + gchar *service_name = (gchar *)data; + HDWMWatchedWindow *win = NULL; + + win = hd_wm_lookup_watched_window_via_service (service_name); + + g_free(service_name); + + return FALSE; +} + +static GHashTable* +hd_wm_watchable_apps_init (void) +{ + GHashTable *watchable_apps; + HDWMWatchableApp *app; + DIR *directory; + struct dirent *entry = NULL; + + HN_DBG("Attempting to open directory [%s]", DESKTOPENTRYDIR); + + if ((directory = opendir(DESKTOPENTRYDIR)) == NULL) + { + HN_DBG(" ##### Failed in opening " DESKTOPENTRYDIR " ##### "); + return NULL; + } + + watchable_apps = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)hd_wm_watchable_app_destroy); + + while ((entry = readdir(directory)) != NULL) + { + gchar *path; + + if (!g_str_has_suffix(entry->d_name, DESKTOP_SUFFIX)) + continue; + + path = g_build_filename(DESKTOPENTRYDIR, entry->d_name, NULL); + + HN_DBG("Attempting to open desktop file [%s] ...", path); + + app = hd_wm_watchable_app_new (path); + + if (app) + { + g_hash_table_insert (watchable_apps, + g_strdup(hd_wm_watchable_app_get_class_name (app)), + (gpointer)app); + } + + g_free(path); + } + + closedir(directory); + + return watchable_apps; +} + +gchar* +hd_wm_compute_watched_window_hibernation_key (Window xwin, + HDWMWatchableApp *app) +{ + gchar *role, *hibernation_key = NULL; + + HN_DBG("#### computing hibernation key ####"); + + g_return_val_if_fail(app, NULL); + + gdk_error_trap_push(); + + role = hd_wm_util_get_win_prop_data_and_validate (xwin, + hdwm.atoms[HN_ATOM_WM_WINDOW_ROLE], + XA_STRING, + 8, + 0, + NULL); + + if (gdk_error_trap_pop()||!role || !*role) + hibernation_key = g_strdup(hd_wm_watchable_app_get_class_name (app)); + else + hibernation_key = g_strdup_printf("%s%s", + hd_wm_watchable_app_get_class_name (app), + role); + if (role) + XFree(role); + + HN_DBG("#### hibernation key: %s ####", hibernation_key); + + return hibernation_key; +} + +static void +hd_wm_lowmem_cb (HNAppSwitcher *app_switcher, + gboolean is_on, + gpointer user_data) +{ + hd_wm_memory_lowmem_func (is_on); +} + +static void +hd_wm_bgkill_cb (HNAppSwitcher *app_switcher, + gboolean is_on, + gpointer user_data) +{ + hd_wm_memory_bgkill_func (is_on); +} + +gboolean +hd_wm_init (HNAppSwitcher *as) +{ + DBusConnection *connection; + DBusError error; + gchar *match_rule = NULL; + GdkKeymap *keymap; + + memset(&hdwm, 0, sizeof(hdwm)); + + osso_manager_t *osso_man = osso_manager_singleton_get_instance(); + + hdwm.app_switcher = as; + + /* Check for configurable lowmem values. */ + + hdwm.lowmem_min_distance + = hd_wm_util_getenv_long (LOWMEM_LAUNCH_THRESHOLD_DISTANCE_ENV, + LOWMEM_LAUNCH_THRESHOLD_DISTANCE); + hdwm.lowmem_banner_timeout + = hd_wm_util_getenv_long (LOWMEM_LAUNCH_BANNER_TIMEOUT_ENV, + LOWMEM_LAUNCH_BANNER_TIMEOUT); + + /* Guard about insensibly long values. */ + if (hdwm.lowmem_banner_timeout > LOWMEM_LAUNCH_BANNER_TIMEOUT_MAX) + hdwm.lowmem_banner_timeout = LOWMEM_LAUNCH_BANNER_TIMEOUT_MAX; + + hdwm.lowmem_timeout_multiplier + = hd_wm_util_getenv_long (LOWMEM_TIMEOUT_MULTIPLIER_ENV, + LOWMEM_TIMEOUT_MULTIPLIER); + + /* Various app switcher callbacks */ +#if 0 + application_switcher_set_dnotify_handler (as, &hd_wm_dnotify_func); + application_switcher_set_shutdown_handler (as, &hd_wm_shutdown_func); + application_switcher_set_lowmem_handler (as, &hd_wm_memory_lowmem_func); + application_switcher_set_bgkill_handler (as, &hd_wm_memory_bgkill_func); +#endif + g_signal_connect (as, "lowmem", G_CALLBACK (hd_wm_lowmem_cb), NULL); + g_signal_connect (as, "bgkill", G_CALLBACK (hd_wm_bgkill_cb), NULL); + + /* build our hash of watchable apps via .desktop key/values */ + + hdwm.watched_apps = hd_wm_watchable_apps_init (); + + /* Initialize the common X atoms */ + + hd_wm_atoms_init(); + + /* Hash to track watched windows */ + + hdwm.watched_windows + = g_hash_table_new_full (g_int_hash, + g_int_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)hd_wm_watched_window_destroy); + + /* Hash for windows that dont really still exists but HN makes them appear + * as they do - they are basically backgrounded. + */ + hdwm.watched_windows_hibernating + = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)hd_wm_watched_window_destroy); + + gdk_error_trap_push(); + + /* select X events */ + + gdk_window_set_events(gdk_get_default_root_window(), + gdk_window_get_events(gdk_get_default_root_window()) + | GDK_PROPERTY_CHANGE_MASK ); + + gdk_window_add_filter(gdk_get_default_root_window(), + hd_wm_x_event_filter, + NULL); + + gdk_error_trap_pop(); + + /* Setup shortcuts */ + + hdwm.keys = hn_keys_init (); + + /* Track changes in the keymap */ + + keymap = gdk_keymap_get_default (); + g_signal_connect (G_OBJECT (keymap), "keys-changed", + G_CALLBACK (hn_keys_reload), hdwm.keys); + + /* Get on the DBus */ + + dbus_error_init (&error); + + connection = dbus_bus_get( DBUS_BUS_SESSION, &error ); + + if (!connection ) + { + osso_log(LOG_ERR, "Failed to connect to DBUS: %s!\n", error.message ); + dbus_error_free( &error ); + } + else + { + /* Match rule */ + + match_rule = g_strdup_printf("interface='%s'", + APP_LAUNCH_BANNER_METHOD_INTERFACE ); + + dbus_bus_add_match( connection, match_rule, NULL ); + + g_free (match_rule); + + match_rule = g_strdup_printf( + "type='signal', interface='%s'", + APPKILLER_SIGNAL_INTERFACE); + + dbus_bus_add_match( connection, match_rule, NULL ); + dbus_connection_add_filter(connection, hd_wm_dbus_signal_handler, + NULL, NULL); + g_free(match_rule); + + match_rule = g_strdup_printf("interface='%s'", + TASKNAV_INSENSITIVE_INTERFACE ); + + dbus_bus_add_match( connection, match_rule, NULL ); + + dbus_connection_add_filter( connection, hd_wm_dbus_method_call_handler, + /* model */ NULL, NULL ); + g_free(match_rule); + + /* Setup match rule for Maemo Launcher */ + match_rule = g_strdup_printf("type='signal', interface='%s'", + MAEMO_LAUNCHER_SIGNAL_IFACE); + + dbus_bus_add_match(connection, match_rule, NULL); + dbus_connection_add_filter(connection, hd_wm_dbus_signal_handler, + NULL, NULL); + g_free(match_rule); + + dbus_connection_flush(connection); + + /* Add the com.nokia.tasknav callbacks - FIXME: what are these for ? */ + add_method_cb(osso_man, KILL_APPS_METHOD, + &hd_wm_osso_kill_method, osso_man); + + } + + return TRUE; +} + +Atom +hd_wm_get_atom(gint indx) +{ + return hdwm.atoms[indx]; +} + +GHashTable * +hd_wm_get_watched_windows(void) +{ + return hdwm.watched_windows; +} + +GHashTable * +hd_wm_get_hibernating_windows(void) +{ + return hdwm.watched_windows_hibernating; +} + +gboolean +hd_wm_is_lowmem_situation(void) +{ + return hdwm.lowmem_situation; +} + +void +hd_wm_set_lowmem_situation(gboolean b) +{ + hdwm.lowmem_situation = b; +} + +gboolean +hd_wm_is_bg_kill_situation(void) +{ + return hdwm.bg_kill_situation; +} + +void +hd_wm_set_bg_kill_situation(gboolean b) +{ + hdwm.bg_kill_situation = b; +} + +HNAppSwitcher * +hd_wm_get_app_switcher(void) +{ + return hdwm.app_switcher; +} + +gint +hd_wm_get_timer_id(void) +{ + return hdwm.timer_id; +} + +void +hd_wm_set_timer_id(gint id) +{ + hdwm.timer_id = id; +} + +void +hd_wm_set_about_to_shutdown(gboolean b) +{ + hdwm.about_to_shutdown = b; +} + +gboolean +hd_wm_get_about_to_shutdown(void) +{ + return hdwm.about_to_shutdown; +} + +GList * +hd_wm_get_banner_stack(void) +{ + return hdwm.banner_stack; +} + +void +hd_wm_set_banner_stack(GList * l) +{ + hdwm.banner_stack = l; +} + +gulong +hd_wm_get_lowmem_banner_timeout(void) +{ + return hdwm.lowmem_banner_timeout; +} + + +gulong +hd_wm_get_lowmem_timeout_multiplier(void) +{ + return hdwm.lowmem_timeout_multiplier; +} + +HDWMWatchedWindow * +hd_wm_get_active_window(void) +{ + return hdwm.active_window; +} + +/* + * reset the active window to NULL + */ +void +hd_wm_reset_active_window(void) +{ + hdwm.active_window = NULL; +} + +HDWMWatchedWindow * +hd_wm_get_last_active_window(void) +{ + return hdwm.last_active_window; +} + +gboolean +hd_wm_modal_windows_present(void) +{ + return hdwm.modal_windows; +} + + +void +hd_wm_reset_last_active_window(void) +{ + hdwm.last_active_window = NULL; +} + +gboolean +hd_wm_fullscreen_mode () +{ + if(hdwm.active_window) + { + Atom *wm_type_atom; + Window xid = hd_wm_watched_window_get_x_win (hdwm.active_window); + + gdk_error_trap_push(); + + wm_type_atom + = hd_wm_util_get_win_prop_data_and_validate (xid, + hdwm.atoms[HN_ATOM_NET_WM_STATE_FULLSCREEN], + XA_ATOM, + 32, + 0, + NULL); + + gdk_error_trap_pop(); + + if(!wm_type_atom) + return FALSE; + + XFree(wm_type_atom); + return TRUE; + } + + /* destktop cannot run in fullscreen mode */ + return FALSE; +} + +/* Dnotify callback function -- we filter dnotify calls through a timout, see + * comments on hd_wm_dnotify_process () + */ +static void +hd_wm_dnotify_cb ( char *path, void * data) +{ + if( !hdwm.dnotify_timeout_id ) + { + hdwm.dnotify_timeout_id = + g_timeout_add(1000, + (GSourceFunc)hd_wm_dnotify_process, + NULL); + } +} + +/* Public function to register our dnotify callback (called from + * hildon-navigator-main.c) + */ +void +hd_wm_dnotify_register () +{ + if(hildon_dnotify_set_cb((hildon_dnotify_cb_f *)hd_wm_dnotify_cb, + DESKTOPENTRYDIR, + NULL) != HILDON_OK) + { + g_warning("unable to register TN callback for %s", + DESKTOPENTRYDIR); + } +} + Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm.h =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm.h 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/hd-wm.h 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,275 @@ +/* -*- mode:C; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005, 2006 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +/** + * @file hn-wm.h + */ + +#ifndef __HD_WM_H__ +#define __HD_WM_H__ + +#include <X11/Xlib.h> +#include <sys/time.h> +#include <gtk/gtk.h> + +#include "hd-wm-types.h" + +#define HN_WANT_DEBUG 0 /* Set to 1 for more verbose hn */ + +#if (HN_WANT_DEBUG) +#define HN_DBG(x, a...) \ + fprintf(stderr, __FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a) +#else +#define HN_DBG(x, a...) do {} while (0) +#endif +#define HN_MARK() HN_DBG("--mark--"); + +/* For gathering available memory information */ +#define LOWMEM_PROC_ALLOWED "/proc/sys/vm/lowmem_allowed_pages" +#define LOWMEM_PROC_USED "/proc/sys/vm/lowmem_used_pages" + +#define LOWMEM_LAUNCH_BANNER_TIMEOUT 0 +#define LOWMEM_LAUNCH_BANNER_TIMEOUT_MAX 60000 +#define LOWMEM_LAUNCH_BANNER_TIMEOUT_ENV "NAVIGATOR_LOWMEM_LAUNCH_BANNER_TIMEOUT" +/* Added by Karoliina 26092005 */ +#define LOWMEM_TIMEOUT_MULTIPLIER_ENV "NAVIGATOR_LOWMEM_TIMEOUT_MULTIPLIER" +#define LOWMEM_TIMEOUT_MULTIPLIER 2 +/* */ +#define LOWMEM_LAUNCH_THRESHOLD_DISTANCE 2500 +#define LOWMEM_LAUNCH_THRESHOLD_DISTANCE_ENV "NAVIGATOR_LOWMEM_LAUNCH_THRESHOLD_DISTANCE" + +/* DBus/Banner etc related defines + */ +#define APP_LAUNCH_BANNER_METHOD_INTERFACE "com.nokia.tasknav.app_launch_banner" +#define APP_LAUNCH_BANNER_METHOD_PATH "/com/nokia/tasknav/app_launch_banner" +#define APP_LAUNCH_BANNER_METHOD "app_launch_banner" +#define APP_LAUNCH_BANNER_MSG_LOADING "ckct_ib_application_loading" +#define APP_LAUNCH_BANNER_MSG_RESUMING "ckct_ib_application_resuming" +#define APP_LAUNCH_BANNER_MSG_LOADING_FAILED "ckct_ib_application_loading_failed" +/* Timeout of the launch banner, in secons */ +#define APP_LAUNCH_BANNER_TIMEOUT 20 +/* Timeout of the launch banner in lowmem situation */ +#define APP_LAUNCH_BANNER_TIMEOUT_LOWMEM 40 +/* Interval for checking for new window or timeout, in seconds */ +#define APP_LAUNCH_BANNER_CHECK_INTERVAL 0.5 + +/* .desktop file related defines, mainly for keys + */ +#define DESKTOP_VISIBLE_FIELD "Name" +#define DESKTOP_LAUNCH_FIELD "X-Osso-Service" +#define DESKTOP_EXEC_FIELD "Exec" +#define DESKTOP_ICON_FIELD "Icon" +#define DESKTOP_ICON_PATH_FIELD "X-Icon-path" +#define DESKTOP_SUP_WMCLASS "StartupWMClass" +#define DESKTOP_STARTUPNOTIFY "StartupNotify" +#define DESKTOP_TEXT_DOMAIN_FIELD "X-Text-Domain" +#define DESKTOP_SUFFIX ".desktop" + +/* Maemo Launcher DBus interface + */ +#define MAEMO_LAUNCHER_SIGNAL_IFACE "org.maemo.launcher" +#define MAEMO_LAUNCHER_SIGNAL_PATH "/org/maemo/launcher" +#define APP_DIED_SIGNAL_NAME "ApplicationDied" + +/* Application killer DBus interface + */ +#define APPKILLER_SIGNAL_INTERFACE "com.nokia.osso_app_killer" +#define APPKILLER_SIGNAL_PATH "/com/nokia/osso_app_killer" +#define APPKILLER_SIGNAL_NAME "exit" + +#define SAVE_METHOD "save" +#define KILL_APPS_METHOD "kill_app" + +#define UNKNOWN_TITLE "Unknown" + +#undef TN_ALWAYS_FOCUSABLE + +#ifdef TN_ALWAYS_FOCUSABLE +#define TN_DEFAULT_FOCUS TRUE +#else +#define TN_DEFAULT_FOCUS FALSE +#endif + +typedef struct +{ + gpointer entry_ptr; + gulong view_id; + gchar *service; + gchar *wm_class; + gulong window_id; +} menuitem_comp_t; + +struct HDWMLaunchBannerInfo +{ + GtkWidget *parent; + GtkWidget *banner; + struct timeval launch_time; + gchar *msg; + HDWMWatchableApp *app; +}; + +/** Send 'top' request for a certain existing window/view + * + * @param info the window/view to be topped + * + */ +void hd_wm_top_item (HNEntryInfo *info); + + +/** Send 'top' request for a certain service + * @param service_name The name of the service that is to be topped + */ +gboolean hd_wm_top_service(const gchar *service_name); + +/** + * Requests the real window manager to top the desktop + */ +void hd_wm_top_desktop(void); + +/** + * Toggle between desktop and the last active application + */ +void hd_wm_toggle_desktop (void); + +HDWMWatchedWindow* +hd_wm_lookup_watched_window_via_service (const gchar *service_name); + +HDWMWatchedWindow* +hd_wm_lookup_watched_window_via_menu_widget (GtkWidget *menu_widget); + +HDWMWatchableApp* +hd_wm_lookup_watchable_app_via_service (const gchar *service_name); + +HDWMWatchableApp* +hd_wm_lookup_watchable_app_via_exec (const gchar *exec_name); + +HDWMWatchableApp* +hd_wm_lookup_watchable_app_via_menu (GtkWidget *menu); + +HDWMWatchedWindow* +hd_wm_lookup_watched_window_view (GtkWidget *menu_widget); + +gchar * +hd_wm_compute_watched_window_hibernation_key (Window xwin, + HDWMWatchableApp *app); + +gboolean +hd_wm_init (HNAppSwitcher *as); + +void +hd_wm_dnotify_register (void); + +/* keyboard handling functions */ + +void +hd_wm_activate(guint32 what); + +void +hd_wm_focus_active_window (void); + +gboolean +hd_wm_fullscreen_mode (void); + +/* + * These are simple getters/setters that replace direct use of global + * hnwm->something. In order to ensure that we do not incure performance + * penalty due to the function call, we declare all of these as + * 'extern inline'; this ensures that these functions will always be inlined. + */ + + +extern inline Atom +hd_wm_get_atom(gint indx); + +extern inline GHashTable * +hd_wm_get_watched_windows(void); + +extern inline GHashTable * +hd_wm_get_hibernating_windows(void); + +extern inline gboolean +hd_wm_is_lowmem_situation(void); + +extern inline void +hd_wm_set_lowmem_situation(gboolean b); + +extern inline gboolean +hd_wm_is_bg_kill_situation(void); + +extern inline void +hd_wm_set_bg_kill_situation(gboolean b); + +extern inline HNAppSwitcher * +hd_wm_get_app_switcher(void); + +extern inline gint +hd_wm_get_timer_id(void); + +extern inline void +hd_wm_set_timer_id(gint id); + +extern inline void +hd_wm_set_about_to_shutdown(gboolean b); + +extern inline gboolean +hd_wm_get_about_to_shutdown(void); + +extern inline GList * +hd_wm_get_banner_stack(void); + +extern inline void +hd_wm_set_banner_stack(GList * l); + +extern inline gulong +hd_wm_get_lowmem_banner_timeout(void); + +extern inline gulong +hd_wm_get_lowmem_timeout_multiplier(void); + +extern inline HDWMWatchedWindow * +hd_wm_get_active_window(void); + +extern inline HDWMWatchedWindow * +hd_wm_get_last_active_window(void); + +extern inline gboolean +hd_wm_modal_windows_present(void); + +/* + * reset the active window to NULL + * + * NB: we intentionally do not provide a setter -- the active window is our + * business alone and must not be done from anywhere else than the WM itself. + * The reset function is only to be called from hd_wm_watched_window_destroy(). + */ +extern inline void +hd_wm_reset_active_window(void); + +extern inline void +hd_wm_reset_last_active_window(void); + +#endif/*__HD_WM_H__*/ + Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/osso-manager.c =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/osso-manager.c 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/osso-manager.c 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,257 @@ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + + +/* + * + * @file osso-manager.c + * + */ + + +/* System includes */ +#include <glib.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +/* log include */ +#include <log-functions.h> + +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus.h> + +/* hildon includes */ +#include "osso-manager.h" + + + +static int start_osso(osso_manager_t *man, GMainContext *context); +static int osso_callback(const gchar *interface, + const gchar *method, + GArray *arguments, + gpointer data, + osso_rpc_t *retval); + + +static int start_osso(osso_manager_t *man, GMainContext *context) +{ + if (man->osso != NULL) + return -1; + + man->osso = osso_initialize(TASKNAV,TASKNAV_VERSION,FALSE,NULL); + + if (!man->osso) + { + osso_log(LOG_ERR, + "Could not initialize osso from task nav. DBUS running ?"); + + return -1; + + } + osso_rpc_set_default_cb_f(man->osso,(osso_rpc_cb_f*)osso_callback,man); + return 0; +} + + +osso_manager_t *osso_manager_singleton_get_instance( void ) +{ + static osso_manager_t *instance =NULL; + + + if (!instance) + { + instance = g_malloc0(sizeof(osso_manager_t)); + + instance->methods = g_array_new(FALSE,TRUE,sizeof(osso_method)); + + if (start_osso(instance, NULL)) + { + osso_log(LOG_ERR, "Could not connect to osso"); + return NULL; + } + } + + + return instance; +} + +static int osso_callback(const gchar *interface, + const gchar *method, + GArray *arguments, + gpointer data, + osso_rpc_t *retval) +{ + + osso_manager_t *man; + int n; + + man = (osso_manager_t *)data; + + retval->type = DBUS_TYPE_INVALID; + + + + for ( n=0;n< man->methods->len;n++) + { + osso_method *met; + met = &g_array_index(man->methods,osso_method,n); + if (!strncmp(method,met->name,METHOD_NAME_LEN)) + { + + if (met->method(arguments,met->data) == OSSO_ERROR) + { + retval->type = DBUS_TYPE_STRING; /* err */ + retval->value.s = "Error in callback method!\n"; + osso_log(LOG_ERR,"Callback method %s failed\n",method); + return OSSO_ERROR; + } + break; + } + } + + + if (n == man->methods->len) + { + retval->type = DBUS_TYPE_STRING; /* err */ + retval->value.s = "Unknown method called!\n"; + + return OSSO_ERROR; + } + + retval->type = DBUS_TYPE_INT32; + retval->value.i = 0; + + return OSSO_OK; +} + +void add_method_cb(osso_manager_t *man,const gchar *name, + tasknav_cb_f *method,gpointer data) +{ + osso_method met; + + g_snprintf(met.name,METHOD_NAME_LEN,"%s",name); + met.method = method; + met.data = data; + + g_array_append_val(man->methods,met); +} + +void osso_manager_launch(osso_manager_t *man, const gchar *app, + const gchar *launch_param) +{ + char service[SERVICE_NAME_LEN], + path[PATH_NAME_LEN], + interface[INTERFACE_NAME_LEN], + tmp[TMP_NAME_LEN]; + + /* If we have full service name we will use it*/ + if (g_strrstr(app,".")) + { + g_snprintf(service,SERVICE_NAME_LEN,"%s",app); + g_snprintf(interface,INTERFACE_NAME_LEN,"%s",service); + g_snprintf(tmp,TMP_NAME_LEN,"%s",app); + g_snprintf(path,PATH_NAME_LEN,"/%s",g_strdelimit(tmp,".",'/')); + } + else /* we will use com.nokia prefix*/ + { + g_snprintf(service,SERVICE_NAME_LEN,"%s.%s",OSSO_BUS_ROOT,app); + g_snprintf(path,PATH_NAME_LEN,"%s/%s",OSSO_BUS_ROOT_PATH,app); + g_snprintf(interface,INTERFACE_NAME_LEN,"%s",service); + } + + d_log(LOG_D,"Launch: s:%s\np:%s\ni:%s\n",service,path,interface); + + if (launch_param != NULL) + { + if ( (osso_rpc_run( man->osso, service, path, interface, + OSSO_BUS_TOP , + NULL, DBUS_TYPE_STRING, launch_param, + DBUS_TYPE_INVALID )) != OSSO_OK ) + { + osso_log(LOG_ERR, "Failed to restart!" ); + } + } + else + { + if ( (osso_rpc_run( man->osso, service, path, interface, + OSSO_BUS_TOP , + NULL, DBUS_TYPE_INVALID )) != OSSO_OK ) { + osso_log(LOG_ERR, "Failed to launch!" ); + } + } +} + + +void osso_manager_infoprint(osso_manager_t *man, const gchar *message) +{ + osso_rpc_t retval; + if (osso_system_note_infoprint(man->osso, message, &retval) != OSSO_OK) + osso_log(LOG_ERR,"Could not show infoprint %s\n",message); + osso_rpc_free_val (&retval); +} + +/** Method to set the x window to be used by the osso manager */ +void osso_manager_set_window(osso_manager_t *man,Window win) +{ + g_assert(win); + man->window=win; +} + +int is_service_running(const char *service) +{ + osso_manager_t *man; + DBusConnection *con; + DBusError error; + char buf[DBUS_BUF_SIZE]; + int n; + + g_snprintf(buf,sizeof(buf),"%s%s",SERVICE_PREFIX,service); + + man = osso_manager_singleton_get_instance(); + if(man == NULL) + { + return -1; + } + + con = (DBusConnection *)osso_get_dbus_connection(man->osso); + + dbus_error_init(&error); + n = dbus_bus_name_has_owner(con,buf,&error); + + if (dbus_error_is_set(&error)) + { + osso_log(LOG_ERR, "Error detecting if %s is running: %s\n", + service, + error.message); + dbus_error_free(&error); + return -1; + } + + return n; +} + +osso_context_t *get_context(osso_manager_t *man) +{ + return man->osso; +} Added: projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/osso-manager.h =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/osso-manager.h 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/libhildonwm/osso-manager.h 2006-11-22 14:33:55 UTC (rev 8258) @@ -0,0 +1,133 @@ +/* + * This file is part of maemo-af-desktop + * + * Copyright (C) 2005 Nokia Corporation. + * + * Contact: Karoliina Salminen <karoliina.t.salminen at nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** +* @file osso-manager.h +*/ + +#ifndef OSSO_MANAGER_H +#define OSSO_MANAGER_H + +#include <libosso.h> +#include <X11/Xlib.h> +/* hildon includes */ +#include "hildon-navigator.h" + +#define APP_NAME_LEN 64 + +#define OSSO_BUS_ROOT "com.nokia" +#define OSSO_BUS_ROOT_PATH "/com/nokia" +#define OSSO_BUS_TOP "top_application" + +#define TASKNAV "tasknav" +#define TASKNAV_VERSION "0.1" + +#define METHOD_NAME_LEN 64 + +#define SERVICE_PREFIX "com.nokia." + +#define SERVICE_NAME_LEN 255 +#define PATH_NAME_LEN 255 +#define INTERFACE_NAME_LEN 255 +#define TMP_NAME_LEN 255 + +#define DBUS_BUF_SIZE 128 + +typedef struct osso_manager osso_manager_t; + +G_BEGIN_DECLS + +struct osso_manager { + osso_context_t *osso; + GArray *methods; + Window window; +}; + + + +/** Call back function pointer type used by plugins to listen to + * the messages from DBUS. + * + * @param arguments The argument table from DBUS as specified un + * libosso.h + * @param data The data pointer passed to the add_method_cb + * + * @return 0 on success, -1 on error + */ +typedef int (tasknav_cb_f)(GArray *arguments, gpointer data); + +typedef struct osso_method { + gchar name[METHOD_NAME_LEN]; + tasknav_cb_f *method; + gpointer data; +} osso_method; + +typedef struct { + gchar name[APP_NAME_LEN]; +} app_name_t; + + + + +/** Returns a global instance of the osso manager. + * + */ +osso_manager_t *osso_manager_singleton_get_instance( void ); + +/** Used by plugins to add a listener method for DBUS + * messags. + * @param manager Osso manager as returned by + * osso_manager_singleton_get_instance + * @param methodname The name of the method visible to the + * DBUS + * @param method A pointer to the callback method to call. + * @param data A data pointer to be passed to the method called + */ +void add_method_cb(osso_manager_t *manager, + const gchar *methodname, + tasknav_cb_f *method, + gpointer data); + +/** Routine to launch applications **/ +void osso_manager_launch(osso_manager_t *man,const gchar *app, + const gchar *launch_data); + + +/** Routine to print an infoprint trough osso*/ +void osso_manager_infoprint(osso_manager_t *man, const gchar *message); + +/** Method to set the x window to be used by the osso manager */ +void osso_manager_set_window(osso_manager_t *man,Window win); + + + +/** Check if a service given is connected to D-BUS*/ +int is_service_running(const char *service); + +/** Getter for the osso context */ + +osso_context_t *get_context(osso_manager_t *man); + +G_END_DECLS + +#endif /* OSSO_MANAGER_H */ Modified: projects/haf/branches/maemo-af-desktop/hildon-desktop/window_management_dependencies =================================================================== --- projects/haf/branches/maemo-af-desktop/hildon-desktop/window_management_dependencies 2006-11-22 14:20:17 UTC (rev 8257) +++ projects/haf/branches/maemo-af-desktop/hildon-desktop/window_management_dependencies 2006-11-22 14:33:55 UTC (rev 8258) @@ -29,3 +29,13 @@ - To remove an entry +hn-wm +----- + +- To initialize hn_wm, it needs appswitcher + +- getter AppSwitcher + +DBUS APIs to be removed: + + - launching (?)
- Previous message: [maemo-commits] r8257 - projects/haf/branches/maemo-af-desktop/hildon-desktop
- Next message: [maemo-commits] r8259 - projects/connectivity/osso-bluez-compat/trunk/etc
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]