summaryrefslogtreecommitdiff
path: root/mate-panel/panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'mate-panel/panel.c')
-rw-r--r--mate-panel/panel.c1403
1 files changed, 1403 insertions, 0 deletions
diff --git a/mate-panel/panel.c b/mate-panel/panel.c
new file mode 100644
index 00000000..5f2a9666
--- /dev/null
+++ b/mate-panel/panel.c
@@ -0,0 +1,1403 @@
+/* Mate panel: Initialization routines
+ * (C) 1997,1998,1999,2000 the Free Software Foundation
+ * (C) 2000 Eazel, Inc.
+ *
+ * Authors: Federico Mena
+ * Miguel de Icaza
+ * George Lebl
+ */
+
+#include <config.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <libpanel-util/panel-glib.h>
+
+#include "panel.h"
+
+#include "applet.h"
+#include "drawer.h"
+#include "button-widget.h"
+#include "launcher.h"
+#include "panel-context-menu.h"
+#include "panel-util.h"
+#include "panel-config-global.h"
+#include "panel-mateconf.h"
+#include "panel-profile.h"
+#include "mate-panel-applet-frame.h"
+#include "panel-action-button.h"
+#include "panel-menu-bar.h"
+#include "panel-separator.h"
+#include "panel-compatibility.h"
+#include "panel-multiscreen.h"
+#include "panel-toplevel.h"
+#include "panel-menu-button.h"
+#include "panel-globals.h"
+#include "panel-lockdown.h"
+#include "panel-icon-names.h"
+
+enum {
+ TARGET_URL,
+ TARGET_NETSCAPE_URL,
+ TARGET_DIRECTORY,
+ TARGET_COLOR,
+ TARGET_APPLET,
+ TARGET_APPLET_INTERNAL,
+ TARGET_ICON_INTERNAL,
+ TARGET_BGIMAGE,
+ TARGET_BACKGROUND_RESET
+};
+
+/*we call this recursively*/
+static void orient_change_foreach(GtkWidget *w, gpointer data);
+
+void
+orientation_change (AppletInfo *info,
+ PanelWidget *panel)
+{
+ PanelOrientation orientation;
+
+ orientation = panel_widget_get_applet_orientation (panel);
+
+ switch (info->type) {
+ case PANEL_OBJECT_APPLET:
+ mate_panel_applet_frame_change_orientation (
+ MATE_PANEL_APPLET_FRAME (info->widget), orientation);
+ break;
+ case PANEL_OBJECT_MENU:
+ case PANEL_OBJECT_LAUNCHER:
+ case PANEL_OBJECT_ACTION:
+ button_widget_set_orientation (BUTTON_WIDGET (info->widget), orientation);
+ break;
+ case PANEL_OBJECT_MENU_BAR:
+ panel_menu_bar_set_orientation (PANEL_MENU_BAR (info->widget), orientation);
+ break;
+ case PANEL_OBJECT_DRAWER: {
+ Drawer *drawer = info->data;
+ PanelWidget *panel_widget;
+
+ panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel);
+
+ button_widget_set_orientation (BUTTON_WIDGET (info->widget), orientation);
+
+ gtk_widget_queue_resize (GTK_WIDGET (drawer->toplevel));
+ gtk_container_foreach (GTK_CONTAINER (panel_widget),
+ orient_change_foreach,
+ panel_widget);
+ }
+ break;
+ case PANEL_OBJECT_SEPARATOR:
+ panel_separator_set_orientation (PANEL_SEPARATOR (info->widget),
+ orientation);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+orient_change_foreach(GtkWidget *w, gpointer data)
+{
+ AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
+ PanelWidget *panel = data;
+
+ orientation_change(info,panel);
+}
+
+
+static void
+panel_orient_change (GtkWidget *widget, gpointer data)
+{
+ gtk_container_foreach(GTK_CONTAINER(widget),
+ orient_change_foreach,
+ widget);
+}
+
+/*we call this recursively*/
+static void size_change_foreach(GtkWidget *w, gpointer data);
+
+void
+size_change (AppletInfo *info,
+ PanelWidget *panel)
+{
+ if (info->type == PANEL_OBJECT_APPLET)
+ mate_panel_applet_frame_change_size (
+ MATE_PANEL_APPLET_FRAME (info->widget), panel->sz);
+}
+
+static void
+size_change_foreach(GtkWidget *w, gpointer data)
+{
+ AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
+ PanelWidget *panel = data;
+
+ size_change(info,panel);
+}
+
+
+static void
+panel_size_change (GtkWidget *widget, gpointer data)
+{
+ gtk_container_foreach(GTK_CONTAINER(widget), size_change_foreach,
+ widget);
+}
+
+void
+back_change (AppletInfo *info,
+ PanelWidget *panel)
+{
+ switch (info->type) {
+ case PANEL_OBJECT_APPLET:
+ mate_panel_applet_frame_change_background (
+ MATE_PANEL_APPLET_FRAME (info->widget), panel->background.type);
+ break;
+ case PANEL_OBJECT_MENU_BAR:
+ panel_menu_bar_change_background (PANEL_MENU_BAR (info->widget));
+ break;
+ case PANEL_OBJECT_SEPARATOR:
+ panel_separator_change_background (PANEL_SEPARATOR (info->widget));
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+back_change_foreach (GtkWidget *widget,
+ PanelWidget *panel)
+{
+ AppletInfo *info;
+
+ info = g_object_get_data (G_OBJECT (widget), "applet_info");
+
+ back_change (info, panel);
+}
+
+static void
+panel_back_change (GtkWidget *widget, gpointer data)
+{
+ gtk_container_foreach (GTK_CONTAINER (widget),
+ (GtkCallback) back_change_foreach,
+ widget);
+
+#ifdef FIXME_FOR_NEW_CONFIG
+ /*update the configuration box if it is displayed*/
+ update_config_back(PANEL_WIDGET(widget));
+#endif /* FIXME_FOR_NEW_CONFIG */
+}
+
+static void
+mate_panel_applet_added(GtkWidget *widget, GtkWidget *applet, gpointer data)
+{
+ AppletInfo *info;
+
+ info = g_object_get_data (G_OBJECT (applet), "applet_info");
+
+ orientation_change(info,PANEL_WIDGET(widget));
+ size_change(info,PANEL_WIDGET(widget));
+ back_change(info,PANEL_WIDGET(widget));
+}
+
+static void
+mate_panel_applet_removed(GtkWidget *widget, GtkWidget *applet, gpointer data)
+{
+ PanelToplevel *toplevel;
+ AppletInfo *info;
+
+ toplevel = PANEL_WIDGET (widget)->toplevel;
+ info = g_object_get_data (G_OBJECT (applet), "applet_info");
+
+ if (info->type == PANEL_OBJECT_DRAWER) {
+ Drawer *drawer = info->data;
+
+ if (drawer->toplevel)
+ panel_toplevel_queue_auto_hide (toplevel);
+ }
+}
+
+static gboolean
+deactivate_idle (gpointer data)
+{
+ PanelData *pd = data;
+ pd->deactivate_idle = 0;
+
+ pd->insertion_pos = -1;
+
+ return FALSE;
+}
+
+static void
+context_menu_deactivate (GtkWidget *w,
+ PanelData *pd)
+{
+ if (pd->deactivate_idle == 0)
+ pd->deactivate_idle = g_idle_add (deactivate_idle, pd);
+
+ panel_toplevel_pop_autohide_disabler (PANEL_TOPLEVEL (pd->panel));
+}
+
+static void
+context_menu_show (GtkWidget *w,
+ PanelData *pd)
+{
+ panel_toplevel_push_autohide_disabler (PANEL_TOPLEVEL (pd->panel));
+}
+
+static void
+panel_recreate_context_menu (PanelData *pd)
+{
+ if (pd->menu)
+ g_object_unref (pd->menu);
+ pd->menu = NULL;
+}
+
+static void
+panel_destroy (PanelToplevel *toplevel,
+ PanelData *pd)
+{
+ panel_lockdown_notify_remove (G_CALLBACK (panel_recreate_context_menu),
+ pd);
+
+ if (pd->menu) {
+ g_signal_handlers_disconnect_by_func (pd->menu,
+ context_menu_deactivate,
+ pd);
+ g_object_unref (pd->menu);
+ }
+ pd->menu = NULL;
+
+ pd->panel = NULL;
+
+ if (pd->deactivate_idle != 0)
+ g_source_remove (pd->deactivate_idle);
+ pd->deactivate_idle = 0;
+
+ g_object_set_data (G_OBJECT (toplevel), "PanelData", NULL);
+
+ panel_list = g_slist_remove (panel_list, pd);
+ g_free (pd);
+}
+
+static void
+mate_panel_applet_move(PanelWidget *panel, GtkWidget *widget, gpointer data)
+{
+ AppletInfo *info;
+
+ info = g_object_get_data (G_OBJECT (widget), "applet_info");
+
+ g_return_if_fail (info);
+
+ mate_panel_applet_save_position (info, info->id, FALSE);
+}
+
+static GtkWidget *
+panel_menu_get (PanelWidget *panel, PanelData *pd)
+{
+ if (!pd->menu) {
+ pd->menu = g_object_ref_sink (panel_context_menu_create (panel));
+ g_signal_connect (pd->menu, "deactivate",
+ G_CALLBACK (context_menu_deactivate),
+ pd);
+ g_signal_connect (pd->menu, "show",
+ G_CALLBACK (context_menu_show), pd);
+ }
+
+ return pd->menu;
+}
+
+static GtkWidget *
+make_popup_panel_menu (PanelWidget *panel_widget)
+{
+ PanelData *pd;
+ GtkWidget *menu;
+
+ if (!panel_widget) {
+ PanelToplevel *toplevel;
+
+ toplevel = PANEL_TOPLEVEL (((PanelData *) panel_list->data)->panel);
+
+ panel_widget = panel_toplevel_get_panel_widget (toplevel);
+ }
+
+ pd = g_object_get_data (G_OBJECT (panel_widget->toplevel), "PanelData");
+ menu = panel_menu_get (panel_widget, pd);
+ g_object_set_data (G_OBJECT (menu), "menu_panel", panel_widget);
+
+ return menu;
+}
+
+static gboolean
+panel_popup_menu (PanelToplevel *toplevel,
+ guint button,
+ guint32 activate_time)
+{
+ PanelWidget *panel_widget;
+ GtkWidget *menu;
+ PanelData *panel_data;
+ GdkEvent *current_event;
+
+ panel_widget = panel_toplevel_get_panel_widget (toplevel);
+ panel_data = g_object_get_data (G_OBJECT (toplevel), "PanelData");
+
+ current_event = gtk_get_current_event ();
+ if (current_event->type == GDK_BUTTON_PRESS)
+ panel_data->insertion_pos = panel_widget_get_cursorloc (panel_widget);
+ else
+ panel_data->insertion_pos = -1;
+
+ menu = make_popup_panel_menu (panel_widget);
+ if (!menu)
+ return FALSE;
+
+ gtk_menu_set_screen (GTK_MENU (menu),
+ gtk_window_get_screen (GTK_WINDOW (toplevel)));
+
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, activate_time);
+
+ return TRUE;
+}
+
+static gboolean
+panel_popup_menu_signal (PanelToplevel *toplevel)
+{
+ return panel_popup_menu (toplevel, 3, GDK_CURRENT_TIME);
+}
+
+static gboolean
+panel_button_press_event (PanelToplevel *toplevel,
+ GdkEventButton *event)
+{
+ if (event->button != 3)
+ return FALSE;
+
+ return panel_popup_menu (toplevel, event->button, event->time);
+}
+
+static gboolean
+panel_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ /*
+ * If the focus widget is a GtkSocket, i.e. the
+ * focus is in an applet in another process, then key
+ * bindings do not work. We get around this by
+ * activating the key bindings here.
+ */
+ if (GTK_IS_SOCKET (gtk_window_get_focus (GTK_WINDOW (widget))) &&
+ event->keyval == GDK_F10 &&
+ (event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_CONTROL_MASK)
+ return gtk_bindings_activate (GTK_OBJECT (widget),
+ event->keyval,
+ event->state);
+
+ return FALSE;
+}
+
+static gboolean
+set_background_image_from_uri (PanelToplevel *toplevel,
+ const char *uri)
+{
+ char *image;
+
+ if ( ! panel_profile_is_writable_background_type (toplevel) ||
+ ! panel_profile_is_writable_background_image (toplevel))
+ return FALSE;
+
+ if (!(image = g_filename_from_uri (uri, NULL, NULL)))
+ return FALSE;
+
+ panel_profile_set_background_image (toplevel, image);
+ panel_profile_set_background_type (toplevel, PANEL_BACK_IMAGE);
+
+ g_free (image);
+
+ return FALSE;
+}
+
+static gboolean
+set_background_color (PanelToplevel *toplevel,
+ guint16 *dropped)
+{
+ PanelColor color;
+
+ if (!dropped)
+ return FALSE;
+
+ if ( ! panel_profile_is_writable_background_type (toplevel) ||
+ ! panel_profile_is_writable_background_color (toplevel))
+ return FALSE;
+
+ color.gdk.red = dropped [0];
+ color.gdk.green = dropped [1];
+ color.gdk.blue = dropped [2];
+ color.alpha = 65535;
+
+ panel_profile_set_background_color (toplevel, &color);
+ panel_profile_set_background_type (toplevel, PANEL_BACK_COLOR);
+
+ return TRUE;
+}
+
+static gboolean
+drop_url (PanelWidget *panel,
+ int position,
+ const char *url)
+{
+ enum {
+ NETSCAPE_URL_URL,
+ NETSCAPE_URL_NAME
+ };
+ char **netscape_url;
+ char *name;
+ char *comment;
+
+ g_return_val_if_fail (url != NULL, FALSE);
+
+ if (!panel_profile_id_lists_are_writable ())
+ return FALSE;
+
+ netscape_url = g_strsplit (url, "\n", 2);
+ if (!netscape_url ||
+ PANEL_GLIB_STR_EMPTY (netscape_url[NETSCAPE_URL_URL])) {
+ g_strfreev (netscape_url);
+ return FALSE;
+ }
+
+ comment = g_strdup_printf (_("Open URL: %s"),
+ netscape_url[NETSCAPE_URL_URL]);
+
+ if (PANEL_GLIB_STR_EMPTY (netscape_url[NETSCAPE_URL_NAME]))
+ name = netscape_url[NETSCAPE_URL_URL];
+ else
+ name = netscape_url[NETSCAPE_URL_NAME];
+
+ panel_launcher_create_from_info (panel->toplevel, position, FALSE,
+ netscape_url[NETSCAPE_URL_URL],
+ name, comment, PANEL_ICON_REMOTE);
+
+ g_free (comment);
+ g_strfreev (netscape_url);
+
+ return TRUE;
+}
+
+static gboolean
+drop_menu (PanelWidget *panel,
+ int position,
+ const char *menu_filename,
+ const char *menu_path)
+{
+ if (!panel_profile_id_lists_are_writable ())
+ return FALSE;
+
+ return panel_menu_button_create (panel->toplevel,
+ position,
+ menu_filename,
+ menu_path,
+ menu_path != NULL,
+ NULL);
+
+}
+
+static gboolean
+drop_uri (PanelWidget *panel,
+ int position,
+ const char *uri,
+ const char *fallback_icon)
+{
+ char *name;
+ char *comment;
+ char *buf;
+ char *icon;
+ GFile *file;
+
+ if (!panel_profile_id_lists_are_writable ())
+ return FALSE;
+
+ name = panel_util_get_label_for_uri (uri);
+ icon = panel_util_get_icon_for_uri (uri);
+ if (!icon)
+ icon = g_strdup (fallback_icon);
+
+ /* FIXME: we might get icons like "folder-music" that might not exist in
+ * the icon theme. This would usually be okay if we could use fallback
+ * icons (and get "folder" this way). However, this is not possible for
+ * launchers: this could be an application that uses an icon named
+ * folder-magic-app, for which we don't want fallbacks. We just want to
+ * go to hicolor. */
+
+ file = g_file_new_for_uri (uri);
+ buf = g_file_get_parse_name (file);
+ g_object_unref (file);
+ /* Translators: %s is a URI */
+ comment = g_strdup_printf (_("Open '%s'"), buf);
+ g_free (buf);
+
+ panel_launcher_create_from_info (panel->toplevel, position, FALSE,
+ uri, name, comment, icon);
+
+ g_free (name);
+ g_free (comment);
+ g_free (icon);
+
+ return TRUE;
+}
+
+static gboolean
+drop_caja_desktop_uri (PanelWidget *panel,
+ int pos,
+ const char *uri)
+{
+ gboolean success;
+ const char *id;
+ const char *basename;
+
+ if (g_ascii_strncasecmp (uri, "x-caja-desktop:///",
+ strlen ("x-caja-desktop:///")) != 0)
+ return FALSE;
+
+ success = TRUE;
+ id = panel_profile_get_toplevel_id (panel->toplevel);
+ basename = uri + strlen ("x-caja-desktop:///");
+
+ if (strncmp (basename, "trash", strlen ("trash")) == 0)
+ mate_panel_applet_frame_create (panel->toplevel, pos,
+ "OAFIID:MATE_Panel_TrashApplet");
+ else if (strncmp (basename, "home", strlen ("home")) == 0)
+ panel_launcher_create_with_id (id, pos,
+ "caja-home.desktop");
+ else if (strncmp (basename, "computer", strlen ("computer")) == 0)
+ panel_launcher_create_with_id (id, pos,
+ "caja-computer.desktop");
+ else if (strncmp (basename, "network", strlen ("network")) == 0)
+ panel_launcher_create_with_id (id, pos,
+ "caja-scheme.desktop");
+ else
+ success = FALSE;
+
+ return success;
+}
+
+static gboolean
+drop_urilist (PanelWidget *panel,
+ int pos,
+ char *urilist)
+{
+ char **uris;
+ gboolean success;
+ int i;
+
+ uris = g_uri_list_extract_uris (urilist);
+
+ success = TRUE;
+ for (i = 0; uris[i]; i++) {
+ GFile *file;
+ GFileInfo *info;
+ const char *uri;
+
+ uri = uris[i];
+
+ if (g_ascii_strncasecmp (uri, "http:", strlen ("http:")) == 0 ||
+ g_ascii_strncasecmp (uri, "https:", strlen ("https:")) == 0 ||
+ g_ascii_strncasecmp (uri, "ftp:", strlen ("ftp:")) == 0 ||
+ g_ascii_strncasecmp (uri, "gopher:", strlen ("gopher:")) == 0 ||
+ g_ascii_strncasecmp (uri, "ghelp:", strlen ("ghelp:")) == 0 ||
+ g_ascii_strncasecmp (uri, "man:", strlen ("man:")) == 0 ||
+ g_ascii_strncasecmp (uri, "info:", strlen ("info:")) == 0) {
+ /* FIXME: probably do this only on link,
+ * in fact, on link always set up a link,
+ * on copy do all the other stuff. Or something. */
+ if ( ! drop_url (panel, pos, uri))
+ success = FALSE;
+ continue;
+ }
+
+ if (g_ascii_strncasecmp (uri, "x-caja-desktop:",
+ strlen ("x-caja-desktop:")) == 0) {
+ success = drop_caja_desktop_uri (panel, pos, uri);
+ continue;
+ }
+
+ file = g_file_new_for_uri (uri);
+ info = g_file_query_info (file,
+ "standard::type,"
+ "standard::content-type,"
+ "access::can-execute",
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ if (info) {
+ const char *mime;
+ GFileType type;
+ gboolean can_exec;
+
+ mime = g_file_info_get_content_type (info);
+ type = g_file_info_get_file_type (info);
+ can_exec = g_file_info_get_attribute_boolean (info,
+ G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE);
+
+ if (mime &&
+ g_str_has_prefix (mime, "image")) {
+ if (!set_background_image_from_uri (panel->toplevel, uri))
+ success = FALSE;
+ } else if (mime &&
+ (!strcmp (mime, "application/x-mate-app-info") ||
+ !strcmp (mime, "application/x-desktop") ||
+ !strcmp (mime, "application/x-kde-app-info"))) {
+ if (panel_profile_id_lists_are_writable ())
+ panel_launcher_create (panel->toplevel, pos, uri);
+ else
+ success = FALSE;
+ } else if (type != G_FILE_TYPE_DIRECTORY && can_exec) {
+ char *filename;
+
+ filename = g_file_get_path (file);
+
+ if (panel_profile_id_lists_are_writable ())
+ /* executable and local, so add a
+ * launcher with it */
+ ask_about_launcher (filename, panel,
+ pos, TRUE);
+ else
+ success = FALSE;
+ g_free (filename);
+ } else {
+ if (!drop_uri (panel, pos, uri,
+ PANEL_ICON_UNKNOWN))
+ success = FALSE;
+ }
+ } else {
+ if (!drop_uri (panel, pos, uri, PANEL_ICON_UNKNOWN))
+ success = FALSE;
+ }
+
+ g_object_unref (info);
+ g_object_unref (file);
+ }
+
+ g_strfreev (uris);
+
+ return success;
+}
+
+static gboolean
+drop_internal_icon (PanelWidget *panel,
+ int pos,
+ const char *icon_name,
+ int action)
+{
+ Launcher *old_launcher = NULL;
+
+ if (!icon_name)
+ return FALSE;
+
+ if (!panel_profile_id_lists_are_writable ())
+ return FALSE;
+
+ if (action == GDK_ACTION_MOVE)
+ old_launcher = find_launcher (icon_name);
+
+ if (!panel_launcher_create_copy (panel->toplevel, pos, icon_name))
+ return FALSE;
+
+ if (old_launcher && old_launcher->button) {
+ if (old_launcher->prop_dialog) {
+ g_signal_handler_disconnect (old_launcher->button,
+ old_launcher->destroy_handler);
+ launcher_properties_destroy (old_launcher);
+ }
+ panel_profile_delete_object (old_launcher->info);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+move_applet (PanelWidget *panel, int pos, int applet_index)
+{
+ GSList *applet_list;
+ AppletInfo *info;
+ GtkWidget *parent;
+
+ applet_list = mate_panel_applet_list_applets ();
+
+ info = g_slist_nth_data (applet_list, applet_index);
+
+ if ( ! mate_panel_applet_can_freely_move (info))
+ return FALSE;
+
+ if (pos < 0)
+ pos = 0;
+
+ parent = gtk_widget_get_parent (info->widget);
+
+ if (info != NULL &&
+ info->widget != NULL &&
+ parent != NULL &&
+ PANEL_IS_WIDGET (parent)) {
+ GSList *forb;
+ forb = g_object_get_data (G_OBJECT (info->widget),
+ MATE_PANEL_APPLET_FORBIDDEN_PANELS);
+ if ( ! g_slist_find (forb, panel))
+ panel_widget_reparent (PANEL_WIDGET (parent),
+ panel,
+ info->widget,
+ pos);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+drop_internal_applet (PanelWidget *panel, int pos, const char *applet_type,
+ int action)
+{
+ int applet_index = -1;
+ gboolean remove_applet = FALSE;
+ gboolean success = FALSE;
+
+ if (applet_type == NULL)
+ return FALSE;
+
+ if (sscanf (applet_type, "MENU:%d", &applet_index) == 1 ||
+ sscanf (applet_type, "DRAWER:%d", &applet_index) == 1) {
+ if (action != GDK_ACTION_MOVE)
+ g_warning ("Only MOVE supported for menus/drawers");
+ success = move_applet (panel, pos, applet_index);
+
+ } else if (strncmp (applet_type, "MENU:", strlen ("MENU:")) == 0) {
+ const char *menu;
+ const char *menu_path;
+
+ menu = &applet_type[strlen ("MENU:")];
+ menu_path = strchr (menu, '/');
+
+ if (!menu_path) {
+ if (strncmp (menu, "MAIN", strlen ("MAIN")) == 0)
+ success = drop_menu (panel, pos, NULL, NULL);
+ else
+ success = drop_menu (panel, pos, menu, NULL);
+ } else {
+ char *menu_filename;
+
+ menu_filename = g_strndup (menu, menu_path - menu);
+ menu_path++;
+ success = drop_menu (panel, pos,
+ menu_filename, menu_path);
+ g_free (menu_filename);
+ }
+
+ } else if (!strcmp (applet_type, "DRAWER:NEW")) {
+ if (panel_profile_id_lists_are_writable ()) {
+ panel_drawer_create (panel->toplevel, pos, NULL, FALSE, NULL);
+ success = TRUE;
+ } else {
+ success = FALSE;
+ }
+
+ } else if (!strncmp (applet_type, "ACTION:", strlen ("ACTION:"))) {
+ if (panel_profile_id_lists_are_writable ()) {
+ remove_applet = panel_action_button_load_from_drag (
+ panel->toplevel,
+ pos,
+ applet_type,
+ &applet_index);
+ success = TRUE;
+ } else {
+ success = FALSE;
+ }
+
+ } else if (!strcmp (applet_type, "MENUBAR:NEW")) {
+ if (panel_profile_id_lists_are_writable ()) {
+ panel_menu_bar_create (panel->toplevel, pos);
+ success = TRUE;
+ } else {
+ success = FALSE;
+ }
+
+ } else if (!strcmp(applet_type,"SEPARATOR:NEW")) {
+ if (panel_profile_id_lists_are_writable ()) {
+ panel_separator_create (panel->toplevel, pos);
+ success = TRUE;
+ } else {
+ success = FALSE;
+ }
+
+ } else if (!strcmp(applet_type,"LAUNCHER:ASK")) {
+ if (panel_profile_id_lists_are_writable ()) {
+ ask_about_launcher (NULL, panel, pos, TRUE);
+ success = TRUE;
+ } else {
+ success = FALSE;
+ }
+ }
+
+ if (remove_applet &&
+ action == GDK_ACTION_MOVE) {
+ AppletInfo *info;
+ GSList *applet_list;
+
+ applet_list = mate_panel_applet_list_applets ();
+
+ info = g_slist_nth_data (applet_list, applet_index);
+
+ if (info)
+ panel_profile_delete_object (info);
+ }
+
+ return success;
+}
+
+static GtkTargetList *
+get_target_list (void)
+{
+ static GtkTargetEntry drop_types [] = {
+ { "text/uri-list", 0, TARGET_URL },
+ { "x-url/http", 0, TARGET_NETSCAPE_URL },
+ { "x-url/ftp", 0, TARGET_NETSCAPE_URL },
+ { "_NETSCAPE_URL", 0, TARGET_NETSCAPE_URL },
+ { "application/x-panel-directory", 0, TARGET_DIRECTORY },
+ { "application/x-mate-panel-applet-iid", 0, TARGET_APPLET },
+ { "application/x-mate-panel-applet-internal", 0, TARGET_APPLET_INTERNAL },
+ { "application/x-panel-icon-internal", 0, TARGET_ICON_INTERNAL },
+ { "application/x-color", 0, TARGET_COLOR },
+ { "property/bgimage", 0, TARGET_BGIMAGE },
+ { "x-special/mate-reset-background", 0, TARGET_BACKGROUND_RESET },
+ };
+ static GtkTargetList *target_list = NULL;
+
+ if (!target_list) {
+ gint length = sizeof (drop_types) / sizeof (drop_types [0]);
+
+ target_list = gtk_target_list_new (drop_types, length);
+ }
+
+ return target_list;
+}
+
+gboolean
+panel_check_dnd_target_data (GtkWidget *widget,
+ GdkDragContext *context,
+ guint *ret_info,
+ GdkAtom *ret_atom)
+{
+ GList *l;
+
+ g_return_val_if_fail (widget, FALSE);
+
+ if (!PANEL_IS_TOPLEVEL (widget) &&
+ !BUTTON_IS_WIDGET (widget))
+ return FALSE;
+
+ if (!(gdk_drag_context_get_actions (context) & (GDK_ACTION_COPY|GDK_ACTION_MOVE)))
+ return FALSE;
+
+ for (l = gdk_drag_context_list_targets (context); l; l = l->next) {
+ GdkAtom atom;
+ guint info;
+
+ atom = GDK_POINTER_TO_ATOM (l->data);
+
+ if (gtk_target_list_find (get_target_list (), atom, &info)) {
+ if (ret_info)
+ *ret_info = info;
+
+ if (ret_atom)
+ *ret_atom = atom;
+ break;
+ }
+ }
+
+ return l ? TRUE : FALSE;
+}
+
+static void
+do_highlight (GtkWidget *widget, gboolean highlight)
+{
+ gboolean have_drag;
+
+ /* FIXME: what's going on here ? How are we highlighting
+ * the toplevel widget ? I don't think we are ...
+ */
+
+ have_drag = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
+ "have-drag"));
+ if(highlight) {
+ if(!have_drag) {
+ g_object_set_data (G_OBJECT (widget), "have-drag",
+ GINT_TO_POINTER (TRUE));
+ gtk_drag_highlight (widget);
+ }
+ } else {
+ if(have_drag) {
+ g_object_set_data (G_OBJECT (widget),
+ "have-drag", NULL);
+ gtk_drag_unhighlight (widget);
+ }
+ }
+}
+
+gboolean
+panel_check_drop_forbidden (PanelWidget *panel,
+ GdkDragContext *context,
+ guint info,
+ guint time_)
+{
+ if (!panel)
+ return FALSE;
+
+ if (panel_lockdown_get_locked_down ())
+ return FALSE;
+
+ if (info == TARGET_APPLET_INTERNAL) {
+ GtkWidget *source_widget;
+
+ source_widget = gtk_drag_get_source_widget (context);
+
+ if (BUTTON_IS_WIDGET (source_widget)) {
+ GSList *forb;
+
+ forb = g_object_get_data (G_OBJECT (source_widget),
+ MATE_PANEL_APPLET_FORBIDDEN_PANELS);
+
+ if (g_slist_find (forb, panel))
+ return FALSE;
+ }
+ }
+
+ if (info == TARGET_ICON_INTERNAL ||
+ info == TARGET_APPLET_INTERNAL) {
+ if (gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE)
+ gdk_drag_status (context, GDK_ACTION_MOVE, time_);
+ else
+ gdk_drag_status (context,
+ gdk_drag_context_get_suggested_action (context),
+ time_);
+
+ } else if (gdk_drag_context_get_actions (context) & GDK_ACTION_COPY)
+ gdk_drag_status (context, GDK_ACTION_COPY, time_);
+ else
+ gdk_drag_status (context,
+ gdk_drag_context_get_suggested_action (context),
+ time_);
+
+ return TRUE;
+
+}
+
+static gboolean
+drag_motion_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ PanelToplevel *toplevel;
+ PanelWidget *panel_widget;
+ guint info;
+
+ g_return_val_if_fail (PANEL_IS_TOPLEVEL (widget), FALSE);
+
+ if (!panel_check_dnd_target_data (widget, context, &info, NULL))
+ return FALSE;
+
+ toplevel = PANEL_TOPLEVEL (widget);
+ panel_widget = panel_toplevel_get_panel_widget (toplevel);
+
+ if (!panel_check_drop_forbidden (panel_widget, context, info, time))
+ return FALSE;
+
+ do_highlight (widget, TRUE);
+
+ panel_toplevel_unhide (toplevel);
+
+ return TRUE;
+}
+
+static gboolean
+drag_drop_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time,
+ Launcher *launcher)
+{
+ GdkAtom ret_atom = NULL;
+
+ if (!panel_check_dnd_target_data (widget, context, NULL, &ret_atom))
+ return FALSE;
+
+ gtk_drag_get_data (widget, context, ret_atom, time);
+
+ return TRUE;
+}
+
+static void
+drag_leave_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time,
+ Launcher *launcher)
+{
+ PanelToplevel *toplevel;
+
+ do_highlight (widget, FALSE);
+
+ toplevel = PANEL_TOPLEVEL (widget);
+ panel_toplevel_queue_auto_hide (toplevel);
+}
+
+void
+panel_receive_dnd_data (PanelWidget *panel,
+ guint info,
+ int pos,
+ GtkSelectionData *selection_data,
+ GdkDragContext *context,
+ guint time_)
+{
+ const guchar *data;
+ gboolean success = FALSE;
+
+ if (panel_lockdown_get_locked_down ()) {
+ gtk_drag_finish (context, FALSE, FALSE, time_);
+ return;
+ }
+
+ data = gtk_selection_data_get_data (selection_data);
+
+ switch (info) {
+ case TARGET_URL:
+ success = drop_urilist (panel, pos, (char *)data);
+ break;
+ case TARGET_NETSCAPE_URL:
+ success = drop_url (panel, pos, (char *)data);
+ break;
+ case TARGET_COLOR:
+ success = set_background_color (panel->toplevel, (guint16 *) data);
+ break;
+ case TARGET_BGIMAGE:
+ success = set_background_image_from_uri (panel->toplevel, (char *) data);
+ break;
+ case TARGET_BACKGROUND_RESET:
+ if (panel_profile_is_writable_background_type (panel->toplevel)) {
+ panel_profile_set_background_type (panel->toplevel, PANEL_BACK_NONE);
+ success = TRUE;
+ } else {
+ success = FALSE;
+ }
+ break;
+ case TARGET_DIRECTORY:
+ success = drop_uri (panel, pos, (char *)data,
+ PANEL_ICON_FOLDER);
+ break;
+ case TARGET_APPLET:
+ if (!gtk_selection_data_get_data (selection_data)) {
+ gtk_drag_finish (context, FALSE, FALSE, time_);
+ return;
+ }
+ if (panel_profile_id_lists_are_writable ()) {
+ mate_panel_applet_frame_create (panel->toplevel, pos, (char *) data);
+ success = TRUE;
+ } else {
+ success = FALSE;
+ }
+ break;
+ case TARGET_APPLET_INTERNAL:
+ success = drop_internal_applet (panel, pos, (char *)data,
+ gdk_drag_context_get_selected_action (context));
+ break;
+ case TARGET_ICON_INTERNAL:
+ success = drop_internal_icon (panel, pos, (char *)data,
+ gdk_drag_context_get_selected_action (context));
+ break;
+ default:
+ gtk_drag_finish (context, FALSE, FALSE, time_);
+ return;
+ }
+
+ gtk_drag_finish (context, success, FALSE, time_);
+}
+
+static void
+drag_data_recieved_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ PanelWidget *panel_widget;
+ int pos;
+
+ g_return_if_fail (PANEL_IS_TOPLEVEL (widget));
+
+ /* we use this only to really find out the info, we already
+ know this is an ok drop site and the info that got passed
+ to us is bogus (it's always 0 in fact) */
+ if (!panel_check_dnd_target_data (widget, context, &info, NULL)) {
+ gtk_drag_finish (context, FALSE, FALSE, time);
+ return;
+ }
+
+ panel_widget = panel_toplevel_get_panel_widget (PANEL_TOPLEVEL (widget));
+
+ pos = panel_widget_get_cursorloc (panel_widget);
+
+ /*
+ * -1 passed to mate_panel_applet_register will turn on
+ * the insert_at_pos flag for panel_widget_add_full,
+ * which will not place it after the first applet.
+ */
+ if(pos < 0)
+ pos = -1;
+ else if(pos > panel_widget->size)
+ pos = panel_widget->size;
+
+ panel_receive_dnd_data (
+ panel_widget, info, pos, selection_data, context, time);
+}
+
+static void
+panel_widget_setup(PanelWidget *panel)
+{
+ g_signal_connect (G_OBJECT(panel),
+ "applet_added",
+ G_CALLBACK(mate_panel_applet_added),
+ NULL);
+ g_signal_connect (G_OBJECT(panel),
+ "applet_removed",
+ G_CALLBACK(mate_panel_applet_removed),
+ NULL);
+ g_signal_connect (G_OBJECT(panel),
+ "applet_move",
+ G_CALLBACK(mate_panel_applet_move),
+ NULL);
+ g_signal_connect (G_OBJECT (panel),
+ "back_change",
+ G_CALLBACK (panel_back_change),
+ NULL);
+ g_signal_connect (G_OBJECT (panel),
+ "size_change",
+ G_CALLBACK (panel_size_change),
+ NULL);
+}
+
+PanelData *
+panel_setup (PanelToplevel *toplevel)
+{
+ PanelWidget *panel_widget;
+ PanelData *pd;
+
+ g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL);
+
+ panel_widget = panel_toplevel_get_panel_widget (toplevel);
+
+ pd = g_new0 (PanelData,1);
+ pd->menu = NULL;
+ pd->panel = GTK_WIDGET (toplevel);
+ pd->insertion_pos = -1;
+ pd->deactivate_idle = 0;
+
+ panel_list = g_slist_append (panel_list, pd);
+
+ g_object_set_data (G_OBJECT (toplevel), "PanelData", pd);
+
+ panel_lockdown_notify_add (G_CALLBACK (panel_recreate_context_menu),
+ pd);
+
+ panel_widget_setup (panel_widget);
+
+ g_signal_connect (toplevel, "drag_data_received",
+ G_CALLBACK (drag_data_recieved_cb), NULL);
+ g_signal_connect (toplevel, "drag_motion",
+ G_CALLBACK (drag_motion_cb), NULL);
+ g_signal_connect (toplevel, "drag_leave",
+ G_CALLBACK (drag_leave_cb), NULL);
+ g_signal_connect (toplevel, "drag_drop",
+ G_CALLBACK (drag_drop_cb), NULL);
+
+ gtk_drag_dest_set (GTK_WIDGET (toplevel), 0, NULL, 0, 0);
+
+ g_signal_connect (toplevel, "key-press-event",
+ G_CALLBACK (panel_key_press_event), NULL);
+ g_signal_connect (toplevel, "button-press-event",
+ G_CALLBACK (panel_button_press_event), NULL);
+ g_signal_connect (toplevel, "popup-menu",
+ G_CALLBACK (panel_popup_menu_signal), NULL);
+
+ g_signal_connect_swapped (toplevel, "notify::orientation",
+ G_CALLBACK (panel_orient_change), panel_widget);
+
+ g_signal_connect (toplevel, "destroy", G_CALLBACK (panel_destroy), pd);
+
+ return pd;
+}
+
+GdkScreen *
+panel_screen_from_panel_widget (PanelWidget *panel)
+{
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel), NULL);
+ g_return_val_if_fail (PANEL_IS_TOPLEVEL (panel->toplevel), NULL);
+
+ return gtk_window_get_screen (GTK_WINDOW (panel->toplevel));
+}
+
+gboolean
+panel_is_applet_right_stick (GtkWidget *applet)
+{
+ GtkWidget *parent;
+ PanelWidget *panel_widget;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (applet), FALSE);
+
+ parent = gtk_widget_get_parent (applet);
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE);
+
+ panel_widget = PANEL_WIDGET (parent);
+
+ if (!panel_toplevel_get_expand (panel_widget->toplevel))
+ return FALSE;
+
+ return panel_widget_is_applet_stuck (panel_widget, applet);
+}
+
+static void
+panel_delete_without_query (PanelToplevel *toplevel)
+{
+ PanelWidget *panel_widget;
+
+ panel_widget = panel_toplevel_get_panel_widget (toplevel);
+
+ if (panel_toplevel_get_is_attached (toplevel) &&
+ panel_widget->master_widget) {
+ AppletInfo *info;
+
+ info = g_object_get_data (G_OBJECT (panel_widget->master_widget),
+ "applet_info");
+
+ panel_profile_delete_object (info);
+ } else
+ panel_profile_delete_toplevel (toplevel);
+}
+
+static void
+panel_deletion_response (GtkWidget *dialog,
+ int response,
+ PanelToplevel *toplevel)
+{
+ if (response == GTK_RESPONSE_OK) {
+ panel_push_window_busy (dialog);
+ panel_delete_without_query (toplevel);
+ panel_pop_window_busy (dialog);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+panel_deletion_destroy_dialog (GtkWidget *widget,
+ PanelToplevel *toplevel)
+{
+ panel_toplevel_pop_autohide_disabler (toplevel);
+ g_object_set_data (G_OBJECT (toplevel), "panel-delete-dialog", NULL);
+}
+
+GtkWidget *
+panel_deletion_dialog (PanelToplevel *toplevel)
+{
+
+ GtkWidget *dialog;
+ char *text1;
+ char *text2;
+
+ if (panel_toplevel_get_is_attached (toplevel)) {
+ text1 = _("Delete this drawer?");
+ text2 = _("When a drawer is deleted, the drawer and its\n"
+ "settings are lost.");
+ } else {
+ text1 = _("Delete this panel?");
+ text2 = _("When a panel is deleted, the panel and its\n"
+ "settings are lost.");
+ }
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (toplevel),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ "%s", text1);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", text2);
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_DELETE, GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ gtk_window_set_screen (GTK_WINDOW (dialog),
+ gtk_window_get_screen (GTK_WINDOW (toplevel)));
+
+ gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
+
+ g_signal_connect (dialog, "destroy",
+ G_CALLBACK (panel_deletion_destroy_dialog),
+ toplevel);
+
+ g_object_set_data (G_OBJECT (toplevel), "panel-delete-dialog", dialog);
+ panel_toplevel_push_autohide_disabler (toplevel);
+
+ return dialog;
+}
+
+static void
+panel_query_deletion (PanelToplevel *toplevel)
+{
+ GtkWidget *dialog;
+
+ dialog = g_object_get_data (G_OBJECT (toplevel), "panel-delete-dialog");
+
+ if (dialog) {
+ gtk_window_present (GTK_WINDOW (dialog));
+ return;
+ }
+
+ dialog = panel_deletion_dialog (toplevel);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (panel_deletion_response),
+ toplevel);
+
+ g_signal_connect_object (toplevel, "destroy",
+ G_CALLBACK (gtk_widget_destroy),
+ dialog,
+ G_CONNECT_SWAPPED);
+
+ gtk_widget_show_all (dialog);
+}
+
+void
+panel_delete (PanelToplevel *toplevel)
+{
+ PanelWidget *panel_widget;
+
+ panel_widget = panel_toplevel_get_panel_widget (toplevel);
+
+ if (!panel_global_config_get_confirm_panel_remove () ||
+ !g_list_length (panel_widget->applet_list)) {
+ panel_delete_without_query (toplevel);
+ return;
+ }
+
+ panel_query_deletion (toplevel);
+}