/* * Copyright (C) 2007 OpenedHand Ltd. * Authored by: Rob Bradford * * This is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, version 2 of the License. * * This software is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "plugin.h" /* Little hack so we can build on Glib 2.12 and below */ #if ! GLIB_CHECK_VERSION (2, 14, 0) #define g_timeout_add_seconds(interval, function, data) g_timeout_add ((interval) * 1000, function, data) #endif #define PREFS_PROP_SDK_ROOT "sdk.root" #define PREFS_PROP_TRIPLET "sdk.triplet" #define PREFS_PROP_KERNEL "sdk.kernel" #define PREFS_PROP_ROOTFS "sdk.rootfs" #define UI_FILE ANJUTA_DATA_DIR"/ui/anjuta-plugin-sdk.ui" #define ICON_FILE "anjuta-plugin-sdk.png" #define ICON_PATH ANJUTA_IMAGE_DIR"/"ICON_FILE #define SSH_OPTIONS "-o", "CheckHostIP no", "-o", \ "StrictHostKeyChecking no", "-o", "UserKnownHostsFile /dev/null" #define QEMU_IP_ADDRESS "192.168.7.2" #define QEMU_SCRIPT "poky-qemu" #define CONFIGURE_COMMAND "./configure --host=%s" #define AUTOGEN_COMMAND "./autogen.sh --host=%s" #define DEPLOY_COMMAND "rsync " \ "-e 'ssh -o \"CheckHostIP no\" " \ "-o \"StrictHostKeyChecking no\" " \ "-o \"UserKnownHostsFile /dev/null\"' " \ "-avv %s/usr/ root@%s:/usr" #define REMOTE_COMMAND "ssh -o 'CheckHostIP no' " \ "-o 'StrictHostKeyChecking no' " \ "-o 'UserKnownHostsFile /dev/null' " \ "root@%s anjuta-remote-run %s" #define REMOTE_GDB_COMMAND "ssh -o 'CheckHostIP no' " \ "-o 'StrictHostKeyChecking no' " \ "-o 'UserKnownHostsFile /dev/null' " \ "root@%s anjuta-remote-run gdbserver 0.0.0.0:2345 %s" #define LOCAL_GDB_COMMAND "%s/bin/%s-gdb -x %s %s" #define GDB_SCRIPT "set solib-absolute-prefix %s\n" \ "target remote %s:2345\n" #define OPROFILEUI_COMMAND "oprofile-viewer -h %s -s %s" static gpointer anjuta_plugin_sdk_parent_class; /* Callback prototypes needed for actions */ static void action_deploy_activate_cb (GtkAction *action, gpointer userdata); static void action_start_qemu_activate_cb (GtkAction *action, gpointer userdata); static void action_shutdown_qemu_activate_cb (GtkAction *action, gpointer userdata); static void action_remote_run_activate_cb (GtkAction *action, gpointer userdata); static void action_remote_debug_activate_cb (GtkAction *action, gpointer userdata); static void action_remote_debug_stop_activate_cb (GtkAction *action, gpointer userdata); static void action_remote_profile_activate_cb (GtkAction *action, gpointer userdata); /* actions */ static GtkActionEntry actions_sdk[] = { { "ActionMenuTools", /* Action name */ NULL, /* Stock icon, if any */ N_("_Tools"), /* Display label */ NULL, /* Short-cut */ NULL, /* Tooltip */ NULL /* Callback */ }, { "ActionDeploy", /* Action name */ NULL, /* Stock icon, if any */ N_("Deploy"), /* Display label */ NULL, /* short-cut */ N_("Deploy"), /* Tooltip */ G_CALLBACK (action_deploy_activate_cb) /* action callback */ }, { "ActionStartQemu", /* Action name */ GTK_STOCK_EXECUTE, /* Stock icon, if any */ N_("Start QEMU"), /* Display label */ NULL, /* short-cut */ N_("Start QEMU"), /* Tooltip */ G_CALLBACK (action_start_qemu_activate_cb) /* action callback */ }, { "ActionShutdownQemu", GTK_STOCK_CLOSE, N_("Shutdown QEMU"), NULL, N_("Shutdown QEMU"), G_CALLBACK (action_shutdown_qemu_activate_cb) }, { "ActionRunRemote", GTK_STOCK_EXECUTE, N_("Run remote..."), NULL, N_("Run remote.."), G_CALLBACK (action_remote_run_activate_cb) }, { "ActionDebugRemote", GTK_STOCK_EXECUTE, N_("Debug remote..."), NULL, N_("Debug remote..."), G_CALLBACK (action_remote_debug_activate_cb) }, { "ActionStopRemoteDebugger", GTK_STOCK_CLOSE, N_("Stop debugger..."), NULL, N_("Stop debugger..."), G_CALLBACK (action_remote_debug_stop_activate_cb) }, { "ActionRemoteProfile", NULL, N_("Profile remote..."), NULL, N_("Profile remote..."), G_CALLBACK (action_remote_profile_activate_cb) } }; /* Misc callback prototypes */ static void message_view_buffer_flushed_cb (IAnjutaMessageView *view, gchar *data, gpointer userdata); static void qemu_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid, gint status, gulong time, gpointer userdata); static void remote_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid, gint status, gulong time, gpointer userdata); static void remote_gdb_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid, gint status, gulong time, gpointer userdata); static void oprofileui_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid, gint status, gulong time, gpointer userdata); /* Prototypes for deployment related activities */ static void deploy_set_state (AnjutaPluginSdk *sp, DeployState deploy_state); static void deploy_do_initial_state (AnjutaPluginSdk *sp); static void deploy_do_local_install (AnjutaPluginSdk *sp); static void deploy_do_copy (AnjutaPluginSdk *sp); static void deploy_do_delete (AnjutaPluginSdk *sp); static void deploy_do_finished (AnjutaPluginSdk *sp); static void deploy_do_error (AnjutaPluginSdk *sp); /* Callback fired when the launcher finishes */ static void deploy_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid, gint status, gulong time, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; switch (sp->deploy_state) { case DEPLOY_STATE_LOCAL_INSTALL: if (WEXITSTATUS (status) != 0) deploy_set_state (sp, DEPLOY_STATE_ERROR); else deploy_set_state (sp, DEPLOY_STATE_COPY); break; case DEPLOY_STATE_COPY: /* * don't check error code here because rysnc can sometimes get it * wrong */ deploy_set_state (sp, DEPLOY_STATE_DELETE); break; } } /* * Callback for when data is received by the launcher */ static void deploy_launcher_data_cb (AnjutaLauncher *launcher, AnjutaLauncherOutputType type, const gchar *chars, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; GError *error = NULL; if (sp->deploy_msg_view) { /* Append to the buffer for the message view to deal with the newlines */ ianjuta_message_view_buffer_append (sp->deploy_msg_view, chars, &error); if (error != NULL) { g_warning ("Error appending to message view: %s", error->message); g_clear_error (&error); } } } static void qemu_launcher_data_cb (AnjutaLauncher *launcher, AnjutaLauncherOutputType type, const gchar *chars, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; GError *error = NULL; if (sp->qemu_msg_view) { /* Append to the buffer for the message view to deal with the newlines */ ianjuta_message_view_buffer_append (sp->qemu_msg_view, chars, &error); if (error != NULL) { g_warning ("Error appending to message view: %s", error->message); g_clear_error (&error); } } } static void remote_gdb_launcher_data_cb (AnjutaLauncher *launcher, AnjutaLauncherOutputType type, const gchar *chars, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; GError *error = NULL; if (sp->remote_msg_view) { /* Append to the buffer for the message view to deal with the newlines */ ianjuta_message_view_buffer_append (sp->remote_msg_view, chars, &error); if (error != NULL) { g_warning ("Error appending to message view: %s", error->message); g_clear_error (&error); } } } /* Update the current state */ static void deploy_set_state (AnjutaPluginSdk *sp, DeployState deploy_state) { sp->deploy_state = deploy_state; switch (deploy_state) { case DEPLOY_STATE_INITIAL: deploy_do_initial_state (sp); break; case DEPLOY_STATE_LOCAL_INSTALL: deploy_do_local_install (sp); break; case DEPLOY_STATE_COPY: deploy_do_copy (sp); break; case DEPLOY_STATE_DELETE: deploy_do_delete (sp); break; case DEPLOY_STATE_FINISHED: deploy_do_finished (sp); break; case DEPLOY_STATE_ERROR: deploy_do_error (sp); break; } } /* DEPLOY_STATE_INITIAL */ static void deploy_do_initial_state (AnjutaPluginSdk *sp) { GError *error = NULL; gchar *project_root_dir = NULL; IAnjutaMessageManager *msg_manager = NULL; if (sp->project_root_uri) { project_root_dir = g_filename_from_uri (sp->project_root_uri, NULL, &error); if (!project_root_dir) { g_warning ("Error converting uri to directory name: %s", error->message); g_clear_error (&error); goto error; } } /* get the message view manager */ msg_manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (sp)->shell, IAnjutaMessageManager, &error); if (!msg_manager) { g_warning ("Error getting implementation of IAnjutaMessageManager: %s", error->message); g_clear_error (&error); goto error; } if (project_root_dir) { /* Make the deploy menu option insensitive */ gtk_action_set_sensitive (sp->deploy_action, FALSE); if (!sp->deploy_msg_view) { /* Create a new view */ sp->deploy_msg_view = ianjuta_message_manager_add_view (msg_manager, _("Deploy"), ICON_FILE, &error); if (!sp->deploy_msg_view) { g_warning ("Error getting view: %s", error->message); g_clear_error (&error); goto error; } g_signal_connect (sp->deploy_msg_view, "buffer-flushed", (GCallback)message_view_buffer_flushed_cb, sp); /* When the view is destroyed make the pointer to it null */ g_object_add_weak_pointer (G_OBJECT (sp->deploy_msg_view), (gpointer *)&sp->deploy_msg_view); } ianjuta_message_manager_set_current_view (msg_manager, sp->deploy_msg_view, &error); if (error != NULL) { g_warning ("Error setting current message view: %s", error->message); g_clear_error (&error); goto error; } if (!sp->deploy_launcher) { sp->deploy_launcher = anjuta_launcher_new (); g_signal_connect (sp->deploy_launcher, "child-exited", (GCallback)deploy_launcher_child_exited_cb, sp); } if (!sp->deploy_path) sp->deploy_path = g_build_filename (project_root_dir, ".deploy", NULL); deploy_set_state (sp, DEPLOY_STATE_LOCAL_INSTALL); } else { g_warning ("No project path. Unable to deploy."); } goto done; error: g_free (project_root_dir); gtk_action_set_sensitive (sp->deploy_action, TRUE); done: return; } /* DEPLOY_STATE_LOCAL_INSTALL */ static void deploy_do_local_install (AnjutaPluginSdk *sp) { gchar *deploy_cmd = NULL; deploy_cmd = g_strdup_printf ("make install DESTDIR=%s", sp->deploy_path); ianjuta_message_view_append (sp->deploy_msg_view, IANJUTA_MESSAGE_VIEW_TYPE_INFO, _("Installing into local deployment area"), "", NULL); if (anjuta_launcher_execute (sp->deploy_launcher, deploy_cmd, deploy_launcher_data_cb, sp)) { /* The next step in the state machine is dealt with by the callback */ } else { g_warning ("Error launching make install"); gtk_action_set_sensitive (sp->deploy_action, TRUE); } g_free (deploy_cmd); } /* DEPLOY_STATE_COPY */ static void deploy_do_copy (AnjutaPluginSdk *sp) { gchar *copy_cmd = NULL; copy_cmd = g_strdup_printf (DEPLOY_COMMAND, sp->deploy_path, QEMU_IP_ADDRESS); ianjuta_message_view_append (sp->deploy_msg_view, IANJUTA_MESSAGE_VIEW_TYPE_INFO, _("Copying files to target"), "", NULL); if (anjuta_launcher_execute (sp->deploy_launcher, copy_cmd, deploy_launcher_data_cb, sp)) { /* The next step in the state machine is dealt with by the callback */ } else { g_warning ("Error launching rsync copy to target"); gtk_action_set_sensitive (sp->deploy_action, TRUE); } g_free (copy_cmd); } /* DEPLOY_STATE_DELETE */ static void deploy_do_delete (AnjutaPluginSdk *sp) { GnomeVFSResult res; GnomeVFSURI *uri = NULL; GList *list = NULL; ianjuta_message_view_append (sp->deploy_msg_view, IANJUTA_MESSAGE_VIEW_TYPE_INFO, _("Deleting temporary deployment area"), "", NULL); if (sp->deploy_path) { uri = gnome_vfs_uri_new (sp->deploy_path); list = g_list_append (list, uri); res = gnome_vfs_xfer_delete_list (list, GNOME_VFS_XFER_ERROR_MODE_ABORT, GNOME_VFS_XFER_DELETE_ITEMS, NULL, NULL); if (res != GNOME_VFS_OK) { g_warning ("Error whilst deleting temporary deployment area: %s", gnome_vfs_result_to_string (res)); gnome_vfs_uri_unref (uri); deploy_set_state (sp, DEPLOY_STATE_ERROR); } gnome_vfs_uri_unref (uri); } deploy_set_state (sp, DEPLOY_STATE_FINISHED); } /* DEPLOY_STATE_FINISHED */ static void deploy_do_finished (AnjutaPluginSdk *sp) { ianjuta_message_view_append (sp->deploy_msg_view, IANJUTA_MESSAGE_VIEW_TYPE_INFO, _("Deployment finished"), "", NULL); gtk_action_set_sensitive (sp->deploy_action, TRUE); } /* DEPLOY_STATE_ERROR */ static void deploy_do_error (AnjutaPluginSdk *sp) { ianjuta_message_view_append (sp->deploy_msg_view, IANJUTA_MESSAGE_VIEW_TYPE_ERROR, _("Error during deployment"), "", NULL); gtk_action_set_sensitive (sp->deploy_action, TRUE); } /* End of deployment related functions */ /* Action callbacks */ static void action_shutdown_qemu_activate_cb (GtkAction *actio, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; gchar *args[] = { "ssh", SSH_OPTIONS, "root@"QEMU_IP_ADDRESS, "reboot", NULL}; if (!sp->remote_launcher) { sp->remote_launcher = anjuta_launcher_new (); g_signal_connect (sp->remote_launcher, "child-exited", (GCallback)remote_launcher_child_exited_cb, sp); } if (anjuta_launcher_execute_v (sp->remote_launcher, args, NULL, NULL)) { gtk_action_set_sensitive (sp->qemu_shutdown_action, FALSE); } else { g_warning ("Error whilst launching reboot (for shutdown) command"); } } static void action_remote_debug_stop_activate_cb (GtkAction *action, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; gchar *args[] = { "ssh", SSH_OPTIONS, "root@"QEMU_IP_ADDRESS, "killall gdbserver", NULL}; if (!sp->remote_launcher) { sp->remote_launcher = anjuta_launcher_new (); g_signal_connect (sp->remote_launcher, "child-exited", (GCallback)remote_launcher_child_exited_cb, sp); } if (anjuta_launcher_execute_v (sp->remote_launcher, args, NULL, NULL)) { gtk_action_set_sensitive (sp->remote_debug_stop_action, FALSE); } else { g_warning ("Error whilst launching command to kill gdbserver"); } } static void action_deploy_activate_cb (GtkAction *action, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; deploy_set_state (sp, DEPLOY_STATE_INITIAL); } static void action_start_qemu_activate_cb (GtkAction *action, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; GError *error = NULL; IAnjutaMessageManager *msg_manager = NULL; /* Get the message view manager */ msg_manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (sp)->shell, IAnjutaMessageManager, &error); if (!msg_manager) { g_warning ("Error getting implementation of IAnjutaMessageManager: %s", error->message); g_clear_error (&error); return; } if (!sp->qemu_msg_view) { /* Create a new view */ sp->qemu_msg_view = ianjuta_message_manager_add_view (msg_manager, _("QEMU"), ICON_FILE, &error); if (!sp->qemu_msg_view) { g_warning ("Error getting view: %s", error->message); g_clear_error (&error); return; } g_signal_connect (sp->qemu_msg_view, "buffer-flushed", (GCallback)message_view_buffer_flushed_cb, sp); /* When the view is destroyed make the pointer to it null */ g_object_add_weak_pointer (G_OBJECT (sp->qemu_msg_view), (gpointer *)&sp->qemu_msg_view); } ianjuta_message_manager_set_current_view (msg_manager, sp->qemu_msg_view, &error); if (error != NULL) { g_warning ("Error setting current message view: %s", error->message); g_clear_error (&error); return; } if (!sp->qemu_launcher) { sp->qemu_launcher = anjuta_launcher_new (); g_signal_connect (sp->qemu_launcher, "child-exited", (GCallback)qemu_launcher_child_exited_cb, sp); } if (sp->kernel && sp->rootfs) { gchar *args[] = {QEMU_SCRIPT, sp->kernel, sp->rootfs, NULL}; if (!anjuta_launcher_execute_v (sp->qemu_launcher, args, qemu_launcher_data_cb, sp)) { g_warning ("Error launching QEMU"); } else { gtk_action_set_sensitive (sp->qemu_start_action, FALSE); gtk_action_set_sensitive (sp->qemu_shutdown_action, TRUE); gtk_action_set_sensitive (sp->remote_run_action, TRUE); if (sp->triplet && sp->sdk_root) gtk_action_set_sensitive (sp->remote_debug_action, TRUE); if (anjuta_util_prog_is_installed ("oprofile-viewer", FALSE)) { gtk_action_set_sensitive (sp->remote_profile_action, TRUE); } /* Make the actions sensitive if we have a project root*/ if (sp->project_root_uri) { gtk_action_set_sensitive (sp->deploy_action, TRUE); } } } } static gint remote_debug_dialog (AnjutaPluginSdk *sp) { GtkWidget *dialog; GtkWidget *inner_vbox; GtkWidget *label; GtkWidget *entry; GtkWidget *hbox; GtkWidget *chooser; GtkSizeGroup *label_group; GtkSizeGroup *control_group; gint res; dialog = gtk_dialog_new_with_buttons (_("Debug remotely"), NULL, 0, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_EXECUTE, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); label_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); control_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); inner_vbox = gtk_vbox_new (FALSE, 6); hbox = gtk_hbox_new (FALSE, 6); label = gtk_label_new (_("Local executable:")); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_size_group_add_widget (label_group, label); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 2); chooser = gtk_file_chooser_button_new (_("Select the local executable"), GTK_FILE_CHOOSER_ACTION_OPEN); gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), sp->gdb_local_path); /* Don't grab keyboard focus on click */ gtk_file_chooser_button_set_focus_on_click (GTK_FILE_CHOOSER_BUTTON (chooser), FALSE); gtk_size_group_add_widget (control_group, chooser); gtk_box_pack_start (GTK_BOX (hbox), chooser, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, TRUE, 2); hbox = gtk_hbox_new (FALSE, 6); label = gtk_label_new (_("Remote command:")); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_size_group_add_widget (label_group, label); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 2); entry = gtk_entry_new (); /* Make hitting enter in the entry do the window default action */ gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); gtk_entry_set_text (GTK_ENTRY (entry), sp->gdb_remote_command); gtk_size_group_add_widget (control_group, entry); gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), inner_vbox, TRUE, TRUE, 2); /* * Grab the focus away explicitly, otherwise it goes onto the file chooser * button and then we don't get a working default behaviour for the dialog */ gtk_widget_grab_focus (entry); gtk_widget_show_all (inner_vbox); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); res = gtk_dialog_run (GTK_DIALOG (dialog)); switch (res) { case GTK_RESPONSE_ACCEPT: g_free (sp->gdb_remote_command); g_free (sp->gdb_local_path); sp->gdb_remote_command = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))); sp->gdb_local_path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); break; default: break; } gtk_widget_destroy (dialog); return res; } static gint remote_run_dialog (AnjutaPluginSdk *sp) { GtkWidget *dialog; GtkWidget *inner_vbox; GtkWidget *label; GtkWidget *hbox; GtkWidget *entry; gint res; dialog = gtk_dialog_new_with_buttons (_("Run remotely"), NULL, 0, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_EXECUTE, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); inner_vbox = gtk_vbox_new (FALSE, 6); hbox = gtk_hbox_new (FALSE, 6); label = gtk_label_new (_("Command to run: ")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 2); entry = gtk_entry_new (); /* Make hitting enter in the entry do the window default action */ gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); gtk_entry_set_text (GTK_ENTRY (entry), sp->remote_command); gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), inner_vbox, TRUE, TRUE, 2); gtk_widget_show_all (inner_vbox); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); res = gtk_dialog_run (GTK_DIALOG (dialog)); switch (res) { case GTK_RESPONSE_ACCEPT: g_free (sp->remote_command); sp->remote_command = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))); break; default: break; } gtk_widget_destroy (dialog); return res; } static void do_local_gdb (AnjutaPluginSdk *sp) { gchar *script_name = NULL; gint fd = 0; gchar *script_contents = NULL; GIOChannel *channel = NULL; GIOStatus status; IAnjutaTerminal *terminal = NULL; gchar *cmd = NULL; GError *error = NULL; gchar *cur_dir = NULL; gchar *gdb_prefix = NULL; /* * create a temporary files and write the client side gdb commands to it, * yes this is evil, no, i don't have a better solution right now */ fd = g_file_open_tmp (NULL, &script_name, &error); if (fd == -1) { g_warning ("Error when opening temporary script file: %s", error->message); return; } gdb_prefix = g_build_filename (sp->sdk_root, sp->triplet, NULL); script_contents = g_strdup_printf (GDB_SCRIPT, gdb_prefix, QEMU_IP_ADDRESS); channel = g_io_channel_unix_new (fd); status = g_io_channel_write_chars (channel, script_contents, -1, NULL, &error); if (status != G_IO_STATUS_NORMAL) { g_warning ("Error writing script content: %s", error->message); g_clear_error (&error); return; } if (g_io_channel_shutdown (channel, TRUE, &error) != G_IO_STATUS_NORMAL) { g_warning ("Errow whilst shutting down channel: %s", error->message); g_clear_error (&error); return; } g_io_channel_unref (channel); g_free (script_contents); g_free (gdb_prefix); terminal = anjuta_shell_get_interface (ANJUTA_PLUGIN (sp)->shell, IAnjutaTerminal, &error); if (terminal == NULL) { g_warning ("Error getting terminal interface from shell: %s", error->message); g_clear_error (&error); return; } cmd = g_strdup_printf (LOCAL_GDB_COMMAND, sp->sdk_root, sp->triplet, script_name, sp->gdb_local_path); cur_dir = g_get_current_dir (); ianjuta_terminal_execute_command (terminal, cur_dir, cmd, &error); if (error != NULL) { g_warning ("Error whilst launching local gdb command: %s", error->message); g_clear_error (&error); } g_free (script_name); g_free (cmd); g_free (cur_dir); } static gboolean remote_gdb_timeout_cb (gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; do_local_gdb (sp); return FALSE; } static void do_remote_gdb (AnjutaPluginSdk *sp) { IAnjutaMessageManager *msg_manager = NULL; gchar *cmd = NULL; GError *error = NULL; /* Create a launcher for running gdbserver on the remote device */ if (!sp->remote_gdb_launcher) { sp->remote_gdb_launcher = anjuta_launcher_new (); g_signal_connect (sp->remote_gdb_launcher, "child-exited", (GCallback)remote_gdb_launcher_child_exited_cb, sp); } /* Get the message view manager */ msg_manager = anjuta_shell_get_interface (ANJUTA_PLUGIN (sp)->shell, IAnjutaMessageManager, &error); if (!msg_manager) { g_warning ("Error getting implementation of IAnjutaMessageManager: %s", error->message); g_clear_error (&error); return; } if (!sp->remote_msg_view) { /* Create a new view */ sp->remote_msg_view = ianjuta_message_manager_add_view (msg_manager, _("Remote"), ICON_FILE, &error); if (!sp->remote_msg_view) { g_warning ("Error getting view: %s", error->message); g_clear_error (&error); return; } g_signal_connect (sp->remote_msg_view, "buffer-flushed", (GCallback)message_view_buffer_flushed_cb, sp); /* When the view is destroyed make the pointer to it null */ g_object_add_weak_pointer (G_OBJECT (sp->remote_msg_view), (gpointer *)&sp->remote_msg_view); } ianjuta_message_manager_set_current_view (msg_manager, sp->remote_msg_view, &error); if (error != NULL) { g_warning ("Error setting current message view: %s", error->message); g_clear_error (&error); return; } cmd = g_strdup_printf (REMOTE_GDB_COMMAND, QEMU_IP_ADDRESS, sp->gdb_remote_command); /* start the remote gdbserver */ if (anjuta_launcher_execute (sp->remote_gdb_launcher, cmd, remote_gdb_launcher_data_cb, sp)) { /* * Add a timeout for 8s to allow the gdbserver to startup (or perhaps it * might fail. if it fails then this timeout will be removed and the local * side of the debugging won't happen) */ sp->remote_gdb_timeout = g_timeout_add_seconds (8, remote_gdb_timeout_cb, sp); gtk_action_set_sensitive (sp->remote_debug_stop_action, TRUE); } g_free (cmd); } static void action_remote_debug_activate_cb (GtkAction *action, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; IAnjutaTerminal *terminal = NULL; GError *error = NULL; gchar *cur_dir = NULL; gchar *cmd = NULL; gint res = 0; terminal = anjuta_shell_get_interface (ANJUTA_PLUGIN (sp)->shell, IAnjutaTerminal, &error); if (terminal == NULL) { g_warning ("Error getting terminal interface from shell: %s", error->message); g_clear_error (&error); return; } cur_dir = g_get_current_dir (); res = remote_debug_dialog (sp); switch (res) { case GTK_RESPONSE_ACCEPT: do_remote_gdb (sp); gtk_action_set_sensitive (sp->remote_debug_action, FALSE); break; default: break; } g_free (cmd); g_free (cur_dir); } static void action_remote_run_activate_cb (GtkAction *action, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; IAnjutaTerminal *terminal = NULL; GError *error = NULL; gchar *cur_dir = NULL; gchar *cmd = NULL; gint res = 0; terminal = anjuta_shell_get_interface (ANJUTA_PLUGIN (sp)->shell, IAnjutaTerminal, &error); if (terminal == NULL) { g_warning ("Error getting terminal interface from shell: %s", error->message); g_clear_error (&error); return; } cur_dir = g_get_current_dir (); res = remote_run_dialog (sp); switch (res) { case GTK_RESPONSE_ACCEPT: cmd = g_strdup_printf (REMOTE_COMMAND, QEMU_IP_ADDRESS, sp->remote_command); ianjuta_terminal_execute_command (terminal, cur_dir, cmd, &error); break; default: break; } g_free (cmd); g_free (cur_dir); } static void action_remote_profile_activate_cb (GtkAction *action, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; gchar *cmd = NULL; gchar *search_path = NULL; if (!sp->oprofileui_launcher) { sp->oprofileui_launcher = anjuta_launcher_new (); g_signal_connect (sp->oprofileui_launcher, "child-exited", (GCallback)oprofileui_launcher_child_exited_cb, sp); } search_path = g_build_filename (sp->sdk_root, sp->triplet, NULL); cmd = g_strdup_printf (OPROFILEUI_COMMAND, QEMU_IP_ADDRESS, search_path); if (anjuta_launcher_execute (sp->oprofileui_launcher, cmd, NULL, NULL)) { gtk_action_set_sensitive (sp->remote_profile_action, FALSE); } else { g_warning ("Error launching OProfileUI"); } g_free (cmd); g_free (search_path); } /* Callback for when qemu launcher finished */ static void qemu_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid, gint status, gulong time, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; gtk_action_set_sensitive (sp->qemu_start_action, TRUE); gtk_action_set_sensitive (sp->qemu_shutdown_action, FALSE); /* Make the deploy insensitive */ gtk_action_set_sensitive (sp->deploy_action, FALSE); gtk_action_set_sensitive (sp->remote_debug_action, FALSE); gtk_action_set_sensitive (sp->remote_run_action, FALSE); gtk_action_set_sensitive (sp->remote_debug_stop_action, FALSE); gtk_action_set_sensitive (sp->remote_profile_action, FALSE); } static void remote_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid, gint status, gulong time, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; } static void remote_gdb_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid, gint status, gulong time, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; if (sp->triplet && sp->sdk_root && sp->qemu_launcher && anjuta_launcher_is_busy (sp->qemu_launcher)) { gtk_action_set_sensitive (sp->remote_debug_action, TRUE); } if (sp->remote_gdb_timeout) { g_source_remove (sp->remote_gdb_timeout); sp->remote_gdb_timeout = 0; } } static void oprofileui_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid, gint status, gulong time, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; if (sp->qemu_launcher && anjuta_launcher_is_busy (sp->qemu_launcher)) { if (anjuta_util_prog_is_installed ("oprofile-viewer", FALSE)) { gtk_action_set_sensitive (sp->remote_profile_action, TRUE); } } } /* * Callback that gets fired when data gets flushed in the view because it's * the end of line */ static void message_view_buffer_flushed_cb (IAnjutaMessageView *view, gchar *data, gpointer userdata) { /* Append to the message view */ ianjuta_message_view_append (view, IANJUTA_MESSAGE_VIEW_TYPE_NORMAL, data, "", NULL); } /* Update the path to remove or include our sdk bin directory */ static void update_path (AnjutaPluginSdk *sp) { char *path = NULL; gchar **pathv = NULL; gchar **new_pathv = NULL; gchar **path_it = NULL; gchar **new_path_it = NULL; gchar *new_path_component = NULL; if (sp->triplet != NULL && sp->sdk_root != NULL) new_path_component = g_build_filename (sp->sdk_root, "bin", NULL); /* get current path. do not free */ path = getenv ("PATH"); /* split old path up */ pathv = g_strsplit (path, ":", -1); /* allocate memory for new pathv */ new_pathv = g_malloc0 ((g_strv_length (pathv) + 2) * (sizeof (gchar *))); /* new pathv iterator */ new_path_it = new_pathv; /* insert at the front if we have something to insert */ if (new_path_component) { *new_path_it = new_path_component; new_path_it++; } /* iterate through */ for (path_it = pathv; *path_it != NULL; path_it++) { /* Check for the old component */ if (sp->path_component && g_str_equal (*path_it, sp->path_component)) { path_it++; /* skip over */ } *new_path_it = *path_it; new_path_it++; } /* Create our new path */ path = g_strjoinv (":", new_pathv); setenv ("PATH", path, 1); /* Save the component */ g_free (sp->path_component); sp->path_component = new_path_component; } /* * Add/remove/update the environment to reflect changes to the sdk root or * triplet */ static void cleanup_environment (AnjutaPluginSdk *sp) { update_path (sp); /* unset environment keys */ unsetenv ("PKG_CONFIG_SYSROOT_DIR"); unsetenv ("PKG_CONFIG_PATH"); unsetenv ("CONFIG_SITE"); } static void update_environment (AnjutaPluginSdk *sp) { gchar *tmp = NULL; if (sp->triplet == NULL || sp->sdk_root == NULL) { cleanup_environment (sp); return; } update_path (sp); tmp = g_build_filename (sp->sdk_root, sp->triplet, NULL); setenv ("PKG_CONFIG_SYSROOT_DIR", tmp, 1); g_free (tmp); tmp = g_build_filename (sp->sdk_root, sp->triplet, "lib", "pkgconfig", NULL); setenv ("PKG_CONFIG_PATH", tmp, 1); g_free (tmp); tmp = g_build_filename (sp->sdk_root, "site-config", NULL); setenv ("CONFIG_SITE", tmp, 1); g_free (tmp); } static void setup_buildable (AnjutaPluginSdk *sp) { gchar *command = NULL; GError *error = NULL; if (!sp->buildable) { sp->buildable = anjuta_shell_get_interface (ANJUTA_PLUGIN (sp)->shell, IAnjutaBuildable, &error); if (!sp->buildable) { g_warning ("Error whilst getting buildable interface: %s", error->message); g_clear_error (&error); return; } } /* For the configure option in the menu */ command = g_strdup_printf (CONFIGURE_COMMAND, sp->triplet); ianjuta_buildable_set_command (sp->buildable, IANJUTA_BUILDABLE_COMMAND_CONFIGURE, command, &error); if (error) { g_warning ("Error setting configure command: %s", error->message); g_clear_error (&error); } g_free (command); /* For the generate option in the menu */ command = g_strdup_printf (AUTOGEN_COMMAND, sp->triplet); ianjuta_buildable_set_command (sp->buildable, IANJUTA_BUILDABLE_COMMAND_GENERATE, command, &error); if (error) { g_warning ("Error setting autogen command: %s", error->message); g_clear_error (&error); } g_free (command); } /* Callbacks fired when preferences changed */ static void sdk_root_preference_notify_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; g_free (sp->sdk_root); sp->sdk_root = anjuta_preferences_get (sp->prefs, PREFS_PROP_SDK_ROOT); update_environment (sp); } static void triplet_preference_notify_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; g_free (sp->triplet); sp->triplet = anjuta_preferences_get (sp->prefs, PREFS_PROP_TRIPLET); update_environment (sp); setup_buildable (sp); } static void rootfs_preference_notify_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; g_free (sp->rootfs); sp->rootfs = anjuta_preferences_get (sp->prefs, PREFS_PROP_ROOTFS); if (sp->rootfs && sp->kernel) { gtk_action_set_sensitive (sp->qemu_start_action, TRUE); } } static void kernel_preference_notify_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; g_free (sp->kernel); sp->kernel = anjuta_preferences_get (sp->prefs, PREFS_PROP_KERNEL); if (sp->rootfs && sp->kernel) { gtk_action_set_sensitive (sp->qemu_start_action, TRUE); } } /* * Callbacks for when a value for "project_root_uri" is added to the shell aka * when a project is opened */ static void project_root_uri_value_added (AnjutaPlugin *plugin, const gchar *name, const GValue *value, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)plugin; g_free (sp->project_root_uri); sp->project_root_uri = g_value_dup_string (value); /* if qemu is already running then turn these actions on */ if (sp->qemu_launcher && anjuta_launcher_is_busy (sp->qemu_launcher)) { gtk_action_set_sensitive (sp->deploy_action, TRUE); } } static void project_root_uri_value_removed (AnjutaPlugin *plugin, const gchar *name, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)plugin; g_free (sp->project_root_uri); sp->project_root_uri = NULL; gtk_action_set_sensitive (sp->deploy_action, FALSE); } static void shell_session_load_cb (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; sp->remote_command = anjuta_session_get_string (session, "SDK", "Remote command"); sp->gdb_local_path = anjuta_session_get_string (session, "SDK", "Remote gdb local path"); sp->gdb_remote_command = anjuta_session_get_string (session, "SDK", "Remote gdb remote command"); } static void shell_session_save_cb (AnjutaShell *shell, AnjutaSessionPhase phase, AnjutaSession *session, gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; anjuta_session_set_string (session, "SDK", "Remote command", sp->remote_command); anjuta_session_set_string (session, "SDK", "Remote gdb local path", sp->gdb_local_path); anjuta_session_set_string (session, "SDK", "Remote gdb remote command", sp->gdb_remote_command); } static gboolean anjuta_plugin_sdk_activate (AnjutaPlugin *plugin) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)plugin; AnjutaUI *ui; GError *error = NULL; ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (plugin)->shell, NULL); sp->action_group = anjuta_ui_add_action_group_entries (ui, "ActionGroupSdk", _("SDK Operations"), actions_sdk, G_N_ELEMENTS (actions_sdk), GETTEXT_PACKAGE, TRUE, sp); sp->uiid = anjuta_ui_merge (ui, UI_FILE); sp->prefs = anjuta_shell_get_preferences (ANJUTA_PLUGIN (sp)->shell, NULL); sp->prefs_icon = gdk_pixbuf_new_from_file (ICON_PATH, NULL); /* Get actions, we need them for turning them on/off */ sp->qemu_start_action = anjuta_ui_get_action (ui, "ActionGroupSdk", "ActionStartQemu"); sp->qemu_shutdown_action = anjuta_ui_get_action (ui, "ActionGroupSdk", "ActionShutdownQemu"); sp->deploy_action = anjuta_ui_get_action (ui, "ActionGroupSdk", "ActionDeploy"); sp->remote_run_action = anjuta_ui_get_action (ui, "ActionGroupSdk", "ActionRunRemote"); sp->remote_debug_action = anjuta_ui_get_action (ui, "ActionGroupSdk", "ActionDebugRemote"); sp->remote_debug_stop_action = anjuta_ui_get_action (ui, "ActionGroupSdk", "ActionStopRemoteDebugger"); sp->remote_profile_action = anjuta_ui_get_action (ui, "ActionGroupSdk", "ActionRemoteProfile"); gtk_action_set_sensitive (sp->qemu_shutdown_action, FALSE); gtk_action_set_sensitive (sp->deploy_action, FALSE); gtk_action_set_sensitive (sp->remote_run_action, FALSE); gtk_action_set_sensitive (sp->remote_debug_action, FALSE); gtk_action_set_sensitive (sp->remote_debug_stop_action, FALSE); gtk_action_set_sensitive (sp->remote_profile_action, FALSE); sp->sdk_root_notifyid = anjuta_preferences_notify_add (sp->prefs, PREFS_PROP_SDK_ROOT, sdk_root_preference_notify_cb, sp, NULL); sp->triplet_notifyid = anjuta_preferences_notify_add (sp->prefs, PREFS_PROP_TRIPLET, triplet_preference_notify_cb, sp, NULL); sp->rootfs_notifyid = anjuta_preferences_notify_add (sp->prefs, PREFS_PROP_ROOTFS, rootfs_preference_notify_cb, sp, NULL); sp->kernel_notifyid = anjuta_preferences_notify_add (sp->prefs, PREFS_PROP_KERNEL, kernel_preference_notify_cb, sp, NULL); sp->sdk_root = anjuta_preferences_get (sp->prefs, PREFS_PROP_SDK_ROOT); sp->triplet = anjuta_preferences_get (sp->prefs, PREFS_PROP_TRIPLET); sp->kernel = anjuta_preferences_get (sp->prefs, PREFS_PROP_KERNEL); sp->rootfs = anjuta_preferences_get (sp->prefs, PREFS_PROP_ROOTFS); if (sp->kernel == NULL || sp->rootfs == NULL) { gtk_action_set_sensitive (sp->qemu_start_action, FALSE); } update_environment (sp); setup_buildable (sp); sp->project_root_uri_watch = anjuta_plugin_add_watch (plugin, "project_root_uri", (AnjutaPluginValueAdded) project_root_uri_value_added, (AnjutaPluginValueRemoved) project_root_uri_value_removed, sp); g_signal_connect (plugin->shell, "load-session", (GCallback)shell_session_load_cb, sp); g_signal_connect (plugin->shell, "save-session", (GCallback)shell_session_save_cb, sp); return TRUE; } static gboolean anjuta_plugin_sdk_deactivate (AnjutaPlugin *plugin) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)plugin; AnjutaUI *ui = NULL; GError *error = NULL; IAnjutaMessageManager *msg_manager = NULL; cleanup_environment (sp); ui = anjuta_shell_get_ui (plugin->shell, NULL); anjuta_ui_remove_action_group (ui, sp->action_group); anjuta_ui_unmerge (ui, sp->uiid); if (sp->deploy_msg_view) { ianjuta_message_manager_remove_view (msg_manager, sp->deploy_msg_view, NULL); sp->deploy_msg_view = NULL; } if (sp->qemu_msg_view) { ianjuta_message_manager_remove_view (msg_manager, sp->qemu_msg_view, NULL); sp->qemu_msg_view = NULL; } if (sp->remote_msg_view) { ianjuta_message_manager_remove_view (msg_manager, sp->remote_msg_view, NULL); sp->remote_msg_view = NULL; } if (sp->buildable) { ianjuta_buildable_reset_commands (sp->buildable, &error); if (error) { g_warning ("Error whilst resetting buildable commands: %s", error->message); g_clear_error (&error); } } anjuta_preferences_notify_remove (sp->prefs, sp->sdk_root_notifyid); anjuta_preferences_notify_remove (sp->prefs, sp->triplet_notifyid); anjuta_preferences_notify_remove (sp->prefs, sp->rootfs_notifyid); anjuta_preferences_notify_remove (sp->prefs, sp->kernel_notifyid); anjuta_plugin_remove_watch (plugin, sp->project_root_uri_watch, FALSE); g_signal_handlers_disconnect_by_func (plugin->shell, shell_session_load_cb, sp); g_signal_handlers_disconnect_by_func (plugin->shell, shell_session_save_cb, sp); /* * Do lots of things you'd normally expect to see in a dispose/finalize, * i.e. to free up memory but because a plugin won't get disposed/finalized * when being turned off we want to be nice and free up memory. */ if (sp->deploy_launcher) { g_object_unref (sp->deploy_launcher); sp->deploy_launcher = NULL; } if (sp->qemu_launcher) { g_object_unref (sp->qemu_launcher); sp->qemu_launcher = NULL; } if (sp->remote_launcher) { g_object_unref (sp->remote_launcher); sp->remote_launcher = NULL; } if (sp->remote_gdb_launcher) { g_object_unref (sp->remote_gdb_launcher); sp->remote_gdb_launcher = NULL; } if (sp->oprofileui_launcher) { g_object_unref (sp->oprofileui_launcher); sp->oprofileui_launcher = NULL; } if (sp->prefs_icon) { g_object_unref (sp->prefs_icon); sp->prefs_icon = NULL; } /* * Must set these to NULL because the plugin object might get reused after * deactivation. */ g_free (sp->sdk_root); g_free (sp->triplet); g_free (sp->kernel); g_free (sp->rootfs); g_free (sp->project_root_uri); g_free (sp->path_component); g_free (sp->gdb_local_path); g_free (sp->gdb_remote_command); g_free (sp->remote_command); sp->sdk_root = NULL; sp->triplet = NULL; sp->kernel = NULL; sp->rootfs = NULL; sp->project_root_uri = NULL; sp->path_component = NULL; sp->gdb_local_path = NULL; sp->gdb_remote_command = NULL; sp->remote_command = NULL; return TRUE; } static void anjuta_plugin_sdk_finalize (GObject *obj) { if (G_OBJECT_CLASS (anjuta_plugin_sdk_parent_class)->finalize) G_OBJECT_CLASS (anjuta_plugin_sdk_parent_class)->finalize (obj); } static void anjuta_plugin_sdk_dispose (GObject *obj) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)obj; if (G_OBJECT_CLASS (anjuta_plugin_sdk_parent_class)->dispose) G_OBJECT_CLASS (anjuta_plugin_sdk_parent_class)->dispose (obj); } static void anjuta_plugin_sdk_instance_init (GObject *obj) { } static void anjuta_plugin_sdk_class_init (GObjectClass *klass) { AnjutaPluginClass *plugin_class = ANJUTA_PLUGIN_CLASS (klass); anjuta_plugin_sdk_parent_class = g_type_class_peek_parent (klass); plugin_class->activate = anjuta_plugin_sdk_activate; plugin_class->deactivate = anjuta_plugin_sdk_deactivate; klass->finalize = anjuta_plugin_sdk_finalize; klass->dispose = anjuta_plugin_sdk_dispose; } static gboolean preferences_timeout_cb (gpointer userdata) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata; gchar *filename; filename = anjuta_preferences_get (ANJUTA_PREFERENCES (sp->prefs), PREFS_PROP_KERNEL); gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (sp->kernel_chooser), filename); g_free (filename); filename = anjuta_preferences_get (ANJUTA_PREFERENCES (sp->prefs), PREFS_PROP_ROOTFS); gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (sp->rootfs_chooser), filename); g_free (filename); return FALSE; } static void ipreferences_merge (IAnjutaPreferences *ipref, AnjutaPreferences *prefs, GError **error) { AnjutaPluginSdk *sp = (AnjutaPluginSdk *)ipref; GtkWidget *vbox; GtkSizeGroup *opts_labels_group; GtkSizeGroup *opts_fields_group; GtkSizeGroup *qemu_labels_group; GtkSizeGroup *qemu_fields_group; GtkWidget *frame; GtkWidget *inner_vbox; GtkWidget *hbox; GtkWidget *label; GtkWidget *chooser; GtkWidget *entry; GtkWidget *inner_alignment; gboolean res; gchar *filename = NULL; GtkWidget *dialog = NULL; dialog = anjuta_preferences_get_dialog (prefs); /* Create main vbox */ vbox = gtk_vbox_new (FALSE, 6); gtk_container_set_border_width (GTK_CONTAINER (vbox), 6); /* Frame for options */ frame = gtk_frame_new (_("Cross-compiler Options")); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 2); label = gtk_frame_get_label_widget (GTK_FRAME (frame)); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE); /* size groups for files */ opts_labels_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); opts_fields_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); /* Pack inner vbox */ inner_vbox = gtk_vbox_new (FALSE, 6); inner_alignment = gtk_alignment_new (0, 0.5, 1, 1); g_object_set (inner_alignment, "left-padding", 12, "top-padding", 6, NULL); gtk_container_add (GTK_CONTAINER (inner_alignment), inner_vbox); gtk_container_add (GTK_CONTAINER (frame), inner_alignment); /* Widgets for sdk root */ hbox = gtk_hbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, FALSE, 0); /* label */ label = gtk_label_new (_("SDK root: ")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_size_group_add_widget (opts_labels_group, label); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); /* chooser */ chooser = gtk_file_chooser_button_new (_("Select SDK root"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); gtk_size_group_add_widget (opts_fields_group, label); gtk_box_pack_start (GTK_BOX (hbox), chooser, TRUE, TRUE, 0); res = anjuta_preferences_register_property_raw ( ANJUTA_PREFERENCES (prefs), chooser, PREFS_PROP_SDK_ROOT, NULL, 0, ANJUTA_PROPERTY_OBJECT_TYPE_FOLDER, ANJUTA_PROPERTY_DATA_TYPE_TEXT); if (!res) g_warning ("Error adding preference for SDK root"); /* Widgets for toolchain triplet */ hbox = gtk_hbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, FALSE, 0); /* label */ label = gtk_label_new (_("Toolchain triplet: ")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_size_group_add_widget (opts_labels_group, label); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); /* entry */ entry = gtk_entry_new (); gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); gtk_size_group_add_widget (opts_fields_group, label); /* register prop */ res = anjuta_preferences_register_property_raw (ANJUTA_PREFERENCES (prefs), entry, PREFS_PROP_TRIPLET, NULL, 0, ANJUTA_PROPERTY_OBJECT_TYPE_ENTRY, ANJUTA_PROPERTY_DATA_TYPE_TEXT); if (!res) g_warning ("Error adding preference for triplet"); /* Frame for qemu */ frame = gtk_frame_new ("QEMU Options"); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 2); gtk_label_set_use_markup (GTK_LABEL (gtk_frame_get_label_widget (GTK_FRAME (frame))), TRUE); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE); /* size groups for files */ qemu_labels_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); qemu_fields_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); /* Pack inner vbox */ inner_vbox = gtk_vbox_new (FALSE, 6); inner_alignment = gtk_alignment_new (0, 0.5, 1, 1); g_object_set (inner_alignment, "left-padding", 12, "top-padding", 6, NULL); gtk_container_add (GTK_CONTAINER (inner_alignment), inner_vbox); gtk_container_add (GTK_CONTAINER (frame), inner_alignment); /* Widgets for kernel */ hbox = gtk_hbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, FALSE, 0); /* label */ label = gtk_label_new ("Kernel: "); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_size_group_add_widget (qemu_labels_group, label); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); /* chooser */ chooser = gtk_file_chooser_button_new (_("Select kernel file"), GTK_FILE_CHOOSER_ACTION_OPEN); gtk_box_pack_start (GTK_BOX (hbox), chooser, TRUE, TRUE, 0); gtk_size_group_add_widget (qemu_fields_group, chooser); anjuta_preferences_register_property_raw ( ANJUTA_PREFERENCES (prefs), chooser, PREFS_PROP_KERNEL, NULL, 0, ANJUTA_PROPERTY_OBJECT_TYPE_FILE, ANJUTA_PROPERTY_DATA_TYPE_TEXT); sp->kernel_chooser = chooser; /* Widgets for rootfs */ hbox = gtk_hbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, FALSE, 0); /* label */ label = gtk_label_new ("Root filesystem: "); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_size_group_add_widget (qemu_labels_group, label); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); /* chooser */ chooser = gtk_file_chooser_button_new (_("Select root filesystem file"), GTK_FILE_CHOOSER_ACTION_OPEN); gtk_box_pack_start (GTK_BOX (hbox), chooser, TRUE, TRUE, 0); gtk_size_group_add_widget (qemu_fields_group, chooser); sp->rootfs_chooser = chooser; anjuta_preferences_register_property_raw ( ANJUTA_PREFERENCES (prefs), chooser, PREFS_PROP_ROOTFS, NULL, 0, ANJUTA_PROPERTY_OBJECT_TYPE_FILE, ANJUTA_PROPERTY_DATA_TYPE_TEXT); /* add page */ gtk_widget_show_all (vbox); anjuta_preferences_dialog_add_page (ANJUTA_PREFERENCES_DIALOG (dialog), _("Poky SDK"), _("Poky SDK"), sp->prefs_icon, vbox); /* * This is a horrible hack around some kind of race condition that seems to * mean that the GtkFileChooserButton doesn't reflect the filename it is * given by the prefences code in Anjuta. Even if it just gets set here it * isn't guaranteed to work. This is the best option i've come up with. * * After 800ms fire a timeout that reads the values for the preferences and * then sets the widgets. It only needs to be done for those that are of * ANJUTA_PROPERTY_OBJECT_TYPE_FILE type. */ g_timeout_add (800, preferences_timeout_cb, sp); } static void ipreferences_unmerge (IAnjutaPreferences *ipref, AnjutaPreferences *prefs, GError **error) { GtkWidget *dialog = NULL; dialog = anjuta_preferences_get_dialog (prefs); /* remove page */ anjuta_preferences_dialog_remove_page (ANJUTA_PREFERENCES_DIALOG (dialog), _("Poky SDK")); } static void ipreferences_iface_init (IAnjutaPreferencesIface* iface) { iface->merge = ipreferences_merge; iface->unmerge = ipreferences_unmerge; } ANJUTA_PLUGIN_BEGIN (AnjutaPluginSdk, anjuta_plugin_sdk); ANJUTA_PLUGIN_ADD_INTERFACE(ipreferences, IANJUTA_TYPE_PREFERENCES); ANJUTA_PLUGIN_END; ANJUTA_SIMPLE_PLUGIN (AnjutaPluginSdk, anjuta_plugin_sdk);