b3bb157ad5
are almost complete (i.e. to handle all nitty gritty cases), but they seem to be working OK right now. SM should be much more stable now. Please tell me if you find any weird behavior - Federico 1999-03-30 Federico Mena Quintero <federico@nuclecu.unam.mx> * gdesktop-icon.c (desktop_icon_realize): Remove the WM_CLIENT_LEADER property from icon windows so that window managers will not store SM information for them. * gnome-open-dialog.c: Added missing #includes. * gdesktop-init.c (desktop_init_at): Removed an unused variable. * gdesktop.h: Added some missing prototypes. * gmain.h: Added some missing prototypes. * Makefile.in: Added gsession.[ch] to the list of sources. * gmain.c (create_panels): Consider whether we have a CORBA server and session management. * gdesktop.c: #include "gdesktop-init.h" * gdesktop.c: Added a missing cast to GNOME_DIALOG. * gmain.c (create_panels): Removed the run_desktop global variable. * glayout.c (create_container): Set the wmclass of the panel to include its unique ID. * gsession.[ch]: New file with the functions that deal with session management. * glayout.c (gnome_exit): Use session_set_restart(). * gcorba.c (corba_init): Now returns an int with an error value. (corba_init_server): Initialize the server properly. Fixed all the object implementation code. (corba_create_window): New function used to create a window with the CORBA server. * gmain.c (gnome_check_super_user): Now the check for running as root is done here. There should be no GUI code in src/. 1999-03-30 Federico Mena Quintero <federico@nuclecu.unam.mx> * dlg.c (dlg_run_done): Do not call the callback of a NULL current widget. * setup.h: Added missing prototype for setup_init(). * filegui.c (check_progress_buttons): Added a missing return value. * dlg.c (remove_widget): Added a missing return value. * main.c: Removed the global directory_list variable. Removed the main_corba_register_server() function. * main.h: Removed the global run_desktop variable. * panel.h: Now the panel structure has a unique numerical ID used for session management. * screen.c (panel_new): Maintain a unique ID for each panel. * main.c (maybe_display_linksdir): Handle display of the desktop init dir here. (main): Call gnome_check_super_user(). (init_corba_with_args): Call corba_init_server(). * main.c (init_corba_with_args): Do CORBA initialization here. Also removed the global force_activation option. 1999-03-30 Federico Mena Quintero <federico@nuclecu.unam.mx> * vfs.c (vfs_add_current_stamps): Only do stamping of the panels if they exist. * mcserv.c: #include <sys/wait.h> (get_client): Put `#ifdef __EMX__' around an otherwise-unused variable. * utilvfs.c (vfs_split_url): Fix NULL <-> 0 confusion when comparing characters. * ftpfs.c (retrieve_dir): Removed unused variable dot_dot_found. * extfs.c (extfs_init): Assign `key' to c, not `&key'.
640 строки
13 KiB
C
640 строки
13 KiB
C
/*
|
|
* Midnight Commander -- GNOME frontend
|
|
*
|
|
* Copyright (C) 1997, 1998 The Free Software Foundation
|
|
*
|
|
* Author: Miguel de Icaza (miguel@gnu.org)
|
|
*
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#define WANT_WIDGETS /* bleah */
|
|
#include "tty.h" /* for KEY_BACKSPACE */
|
|
#include "x.h"
|
|
#include "main.h"
|
|
#include "key.h"
|
|
#include "global.h"
|
|
#include "dir.h"
|
|
#include "panel.h"
|
|
#include "gscreen.h"
|
|
#include "gcmd.h"
|
|
#include "gcorba.h"
|
|
#include "gdesktop.h"
|
|
#include "gsession.h"
|
|
#include "command.h"
|
|
#include "cmd.h"
|
|
|
|
GdkColorContext *mc_cc;
|
|
|
|
#define MAX_COLOR_PAIRS 40
|
|
struct gmc_color_pairs_s gmc_color_pairs [MAX_COLOR_PAIRS];
|
|
|
|
char *default_edition_colors =
|
|
"normal=black:"
|
|
"selected=white,darkblue:"
|
|
"viewunderline=brightred,blue:"
|
|
"directory=blue:"
|
|
"markselect=yellow,darkblue:"
|
|
"marked=yellow,seagreen:"
|
|
"execute=slateblue:"
|
|
"link=green:"
|
|
"stalledlink=brightred:"
|
|
"device=magenta:"
|
|
"core=red:"
|
|
"menuhotsel=cyan,black:"
|
|
"errors=white,red:"
|
|
"reverse=black,lightcyan:"
|
|
"special=black";
|
|
|
|
int dialog_panel_callback (struct Dlg_head *h, int id, int msg);
|
|
|
|
/* The Dlg_head for the whole desktop */
|
|
Dlg_head *desktop_dlg;
|
|
|
|
/* Session client */
|
|
GnomeClient *session_client;
|
|
|
|
/* Used during argument processing */
|
|
extern int finish_program;
|
|
|
|
/* Whether the gmc server was present or not */
|
|
int corba_have_server = FALSE;
|
|
|
|
/* This is only used by the editor, so we provide a dummy implementation */
|
|
void
|
|
try_alloc_color_pair (char *str, char *str2)
|
|
{
|
|
}
|
|
|
|
void
|
|
init_pair (int index, GdkColor *fore, GdkColor *back)
|
|
{
|
|
if (index < 0 || index > MAX_COLOR_PAIRS){
|
|
printf ("init_pair called with invalid index\n");
|
|
exit (1);
|
|
}
|
|
gmc_color_pairs [index].fore = fore;
|
|
gmc_color_pairs [index].back = back;
|
|
}
|
|
|
|
void
|
|
get_color (char *cpp, GdkColor **colp)
|
|
{
|
|
GdkColor *new_color;
|
|
gint status;
|
|
|
|
new_color = g_new (GdkColor, 1);
|
|
gdk_color_parse (cpp, new_color);
|
|
new_color->pixel = 0;
|
|
status = 0;
|
|
gdk_color_context_get_pixels (mc_cc, &new_color->red, &new_color->green, &new_color->blue, 1,
|
|
&new_color->pixel, &status);
|
|
*colp = new_color;
|
|
}
|
|
|
|
static void
|
|
gmc_color_init (void)
|
|
{
|
|
mc_cc = gdk_color_context_new (gtk_widget_get_default_visual (),
|
|
gtk_widget_get_default_colormap ());
|
|
}
|
|
|
|
int
|
|
xtoolkit_init (int *argc, char *argv [])
|
|
{
|
|
gmc_color_init ();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
interactive_display (char *filename, char *node)
|
|
{
|
|
/* FIXME: Implement gnome version */
|
|
}
|
|
|
|
void
|
|
beep (void)
|
|
{
|
|
gdk_beep ();
|
|
}
|
|
|
|
void
|
|
xtoolkit_end (void)
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
|
|
/*
|
|
* Keystroke event handler for all of the Gtk widgets created by
|
|
* the GNOME Midnight Commander. A special case is handled at
|
|
* the top
|
|
*/
|
|
int
|
|
dialog_key_pressed (GtkWidget *win, GdkEventKey *event, Dlg_head *h)
|
|
{
|
|
GtkWidget *w;
|
|
static int on_escape;
|
|
int key;
|
|
|
|
/*
|
|
* Find out if the focused widget is an IconList and
|
|
* if so, check if it has a currently focused item is
|
|
* on editing mode as we do not want to handle key
|
|
* events while the icon name is being edited.
|
|
*/
|
|
w = win;
|
|
while (w && (GTK_IS_CONTAINER (w) && !GNOME_IS_ICON_LIST (w)))
|
|
w = GTK_CONTAINER (w)->focus_child;
|
|
|
|
if (w && GNOME_IS_ICON_LIST (w)){
|
|
GnomeCanvas *c = GNOME_CANVAS (w);
|
|
|
|
if (c->focused_item && GNOME_IS_ICON_TEXT_ITEM (c->focused_item)){
|
|
GnomeIconTextItem *i = GNOME_ICON_TEXT_ITEM (c->focused_item);
|
|
|
|
if (i->editing)
|
|
return FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
key = translate_gdk_keysym_to_curses (event);
|
|
if (key == -1)
|
|
return FALSE;
|
|
|
|
if (!on_escape){
|
|
if (key == 27){
|
|
on_escape = 1;
|
|
gtk_signal_emit_stop_by_name (GTK_OBJECT (win), "key_press_event");
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
if (key != 27){
|
|
if (key >= '0' && key <= '9')
|
|
key = KEY_F(key - '0');
|
|
else
|
|
key = ALT (key);
|
|
|
|
if (key == ALT('<'))
|
|
key = KEY_HOME;
|
|
if (key == ALT('>'))
|
|
key = KEY_END;
|
|
}
|
|
on_escape = 0;
|
|
}
|
|
|
|
if (dlg_key_event (h, key)){
|
|
gtk_signal_emit_stop_by_name (GTK_OBJECT (win), "key_press_event");
|
|
return TRUE;
|
|
} else
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
bind_gtk_keys (GtkWidget *w, Dlg_head *h)
|
|
{
|
|
gtk_signal_connect (GTK_OBJECT (w),
|
|
"key_press_event",
|
|
GTK_SIGNAL_FUNC (dialog_key_pressed),
|
|
h);
|
|
}
|
|
|
|
widget_data
|
|
xtoolkit_create_dialog (Dlg_head *h, int flags)
|
|
{
|
|
GtkWidget *win, *ted;
|
|
|
|
if (!(flags & DLG_NO_TOPLEVEL)){
|
|
if (flags & DLG_GNOME_APP)
|
|
win = gnome_app_new ("mc", h->name);
|
|
else {
|
|
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_MOUSE);
|
|
}
|
|
} else
|
|
win = 0;
|
|
|
|
h->grided = flags;
|
|
h->idle_fn_tag = -1;
|
|
if (!(flags & DLG_NO_TED)){
|
|
ted = gtk_ted_new_layout (h->name, LIBDIR "/layout");
|
|
gtk_container_add (GTK_CONTAINER (win), ted);
|
|
gtk_widget_show (ted);
|
|
|
|
bind_gtk_keys (GTK_WIDGET (ted), h);
|
|
}
|
|
if (win){
|
|
bind_gtk_keys (GTK_WIDGET (win), h);
|
|
}
|
|
return (widget_data) win;
|
|
}
|
|
|
|
/* Used to bind a window for an already created Dlg_head. This is
|
|
* used together with the DLG_NO_TOPLEVEL: the dialog is created
|
|
* with the DLG_NO_TOPLEVEL and later, when the window is created
|
|
* it is assigned with this routine
|
|
*/
|
|
void
|
|
x_dlg_set_window (Dlg_head *h, GtkWidget *win)
|
|
{
|
|
h->wdata = (widget_data) win;
|
|
bind_gtk_keys (GTK_WIDGET (win), h);
|
|
}
|
|
|
|
void
|
|
x_set_dialog_title (Dlg_head *h, char *title)
|
|
{
|
|
gtk_window_set_title (GTK_WINDOW (h->wdata), title);
|
|
}
|
|
|
|
widget_data
|
|
xtoolkit_get_main_dialog (Dlg_head *h)
|
|
{
|
|
GtkWidget *win;
|
|
|
|
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
return (widget_data) win;
|
|
}
|
|
|
|
/* Creates the containers */
|
|
widget_data
|
|
x_create_panel_container (int which)
|
|
{
|
|
GtkWidget *win;
|
|
|
|
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
return (widget_data) 0;
|
|
}
|
|
|
|
void
|
|
x_panel_container_show (widget_data wdata)
|
|
{
|
|
gtk_widget_show (GTK_WIDGET (wdata));
|
|
}
|
|
|
|
void
|
|
x_add_widget (Dlg_head *h, Widget_Item *w)
|
|
{
|
|
if (!(h->grided & DLG_NO_TED)){
|
|
GtkTed *ted = GTK_TED (GTK_BIN (h->wdata)->child);
|
|
|
|
gtk_ted_add (ted, GTK_WIDGET (w->widget->wdata), w->widget->tkname);
|
|
bind_gtk_keys (GTK_WIDGET (w->widget->wdata), h);
|
|
}
|
|
}
|
|
|
|
static int
|
|
gnome_dlg_send_destroy (GtkWidget *widget, GdkEvent *event, Dlg_head *h)
|
|
{
|
|
gtk_widget_hide (GTK_WIDGET (h->wdata));
|
|
h->ret_value = B_CANCEL;
|
|
dlg_stop (h);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
x_init_dlg (Dlg_head *h)
|
|
{
|
|
if (!(h->grided & DLG_NO_TED)){
|
|
GtkTed *ted = GTK_TED (GTK_BIN (h->wdata)->child);
|
|
Widget_Item *p, *first;
|
|
|
|
first = p = h->current;
|
|
do {
|
|
gtk_ted_add (ted, GTK_WIDGET (p->widget->wdata), p->widget->tkname);
|
|
bind_gtk_keys (GTK_WIDGET (p->widget->wdata), h);
|
|
p = p->next;
|
|
} while (p != first);
|
|
gtk_ted_prepare (ted);
|
|
|
|
if (!ted->need_gui){
|
|
gtk_grab_add (GTK_WIDGET (ted));
|
|
gtk_window_set_policy (GTK_WINDOW (h->wdata), 0, 0, 0);
|
|
}
|
|
gtk_widget_show (GTK_WIDGET (h->wdata));
|
|
}
|
|
gtk_signal_connect (GTK_OBJECT (h->wdata), "delete_event",
|
|
GTK_SIGNAL_FUNC (gnome_dlg_send_destroy), h);
|
|
x_focus_widget (h->current);
|
|
}
|
|
|
|
/*
|
|
* This function is invoked when the dialog is started to be
|
|
* destroyed, before any widgets have been destroyed.
|
|
*
|
|
* We only hide the toplevel Gtk widget to avoid the flickering
|
|
* of the destruction process
|
|
*/
|
|
void
|
|
x_destroy_dlg_start (Dlg_head *h)
|
|
{
|
|
gtk_widget_hide (GTK_WIDGET (h->wdata));
|
|
}
|
|
|
|
/*
|
|
* Called when the Dlg_head has been destroyed. This only cleans
|
|
* up/releases the frontend resources
|
|
*/
|
|
void
|
|
x_destroy_dlg (Dlg_head *h)
|
|
{
|
|
if (!(h->grided & DLG_NO_TED))
|
|
gtk_grab_remove (GTK_WIDGET (GTK_BIN (h->wdata)->child));
|
|
if (h->wdata){
|
|
gtk_widget_destroy (GTK_WIDGET(h->wdata));
|
|
h->wdata = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
gtkrundlg_event (Dlg_head *h)
|
|
{
|
|
gtk_main ();
|
|
}
|
|
|
|
void
|
|
edition_pre_exec ()
|
|
{
|
|
}
|
|
|
|
void
|
|
edition_post_exec ()
|
|
{
|
|
}
|
|
|
|
void
|
|
done_screen ()
|
|
{
|
|
}
|
|
|
|
void
|
|
setup_sigwinch ()
|
|
{
|
|
}
|
|
|
|
void
|
|
x_flush_events (void)
|
|
{
|
|
while (gtk_events_pending ())
|
|
gtk_main_iteration ();
|
|
}
|
|
|
|
static int
|
|
gnome_idle_handler (gpointer data)
|
|
{
|
|
Dlg_head *h = data;
|
|
|
|
if (h->send_idle_msg){
|
|
(*h->callback)(h, 0, DLG_IDLE);
|
|
return TRUE;
|
|
} else
|
|
return FALSE;
|
|
}
|
|
|
|
/* Turn on and off the idle message sending */
|
|
void
|
|
x_set_idle (Dlg_head *h, int enable_idle)
|
|
{
|
|
if (enable_idle){
|
|
if (h->idle_fn_tag != -1)
|
|
return;
|
|
h->idle_fn_tag = gtk_idle_add (gnome_idle_handler, h);
|
|
} else {
|
|
if (h->idle_fn_tag == -1)
|
|
return;
|
|
gtk_idle_remove (h->idle_fn_tag);
|
|
h->idle_fn_tag = -1;
|
|
gnome_idle_handler (h);
|
|
}
|
|
}
|
|
|
|
int
|
|
dialog_panel_callback (struct Dlg_head *h, int id, int msg)
|
|
{
|
|
WInput *in;
|
|
Widget_Item *dh;
|
|
void *current_widget; /* The current widget */
|
|
|
|
if (msg == DLG_KEY && id == '\n'){
|
|
current_widget = (void *) h->current->widget;
|
|
|
|
if (is_a_panel (current_widget))
|
|
return 0;
|
|
|
|
dh = h->current;
|
|
do {
|
|
if (is_a_panel (dh->widget)){
|
|
WPanel *p = (WPanel *) dh->widget;
|
|
|
|
if (current_widget == p->filter_w){
|
|
in = (WInput *) current_widget;
|
|
set_panel_filter_to (p, g_strdup (in->buffer));
|
|
return MSG_HANDLED;
|
|
}
|
|
|
|
if (current_widget == p->current_dir){
|
|
WInput *in = p->current_dir;
|
|
|
|
do_panel_cd (p, in->buffer, cd_parse_command);
|
|
assign_text (in, p->cwd);
|
|
update_input (in, 1);
|
|
|
|
return MSG_HANDLED;
|
|
}
|
|
}
|
|
dh = dh->next;
|
|
} while (dh != h->current);
|
|
}
|
|
|
|
if (msg == DLG_UNHANDLED_KEY || msg == DLG_HOTKEY_HANDLED)
|
|
return midnight_callback (h, id, msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Ugly function to support the hack described in non_corba_create_panels() */
|
|
static gint
|
|
idle_destroy_panel (gpointer data)
|
|
{
|
|
WPanel *panel;
|
|
|
|
panel = data;
|
|
gnome_close_panel (GTK_WIDGET (panel->widget.wdata), panel);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Initializes the desktop and creates the initial panels. This is to be used
|
|
* when we do not have a CORBA server.
|
|
*/
|
|
static void
|
|
non_corba_create_panels (void)
|
|
{
|
|
WPanel *panel;
|
|
|
|
desktop_init ();
|
|
gnome_init_panels ();
|
|
|
|
cmdline = command_new (0, 0, 0);
|
|
the_hint = label_new (0, 0, 0, NULL);
|
|
desktop_dlg = create_dlg (0, 0, 24, 80, 0,
|
|
dialog_panel_callback, "[panel]", "midnight", DLG_NO_TED);
|
|
|
|
session_load ();
|
|
|
|
/* The following is a hack. We have to have at least one panel for
|
|
* run_dlg() to be happy. So we destroy it in the idle loop if we
|
|
* didn't need it in the first place. This idle function is to be run
|
|
* at a higher priority than the one used in session_load().
|
|
*/
|
|
|
|
panel = new_panel_at (".");
|
|
gtk_idle_add_priority (GTK_PRIORITY_DEFAULT, idle_destroy_panel, panel);
|
|
panel->widget.options |= W_PANEL_HIDDEN;
|
|
|
|
run_dlg (desktop_dlg);
|
|
|
|
desktop_destroy ();
|
|
}
|
|
|
|
/*
|
|
* Only at startup we have a strange condition: if more than one
|
|
* panel is created, then the code hangs inside X, it keeps waiting
|
|
* for a reply for something in Imlib that never returns.
|
|
*
|
|
* Creating the panels on the idle loop takes care of this
|
|
*/
|
|
void
|
|
create_panels (void)
|
|
{
|
|
if (!corba_have_server)
|
|
non_corba_create_panels ();
|
|
else {
|
|
if (!nowindows)
|
|
corba_create_window ();
|
|
|
|
session_set_restart (FALSE);
|
|
}
|
|
}
|
|
|
|
void
|
|
gmc_do_quit (void)
|
|
{
|
|
/* FIXME: This wont get us out from a dialog box */
|
|
gtk_main_quit ();
|
|
quit = 1;
|
|
dlg_stop (desktop_dlg);
|
|
}
|
|
#if 0
|
|
static void
|
|
session_die (void)
|
|
{
|
|
gmc_do_quit ();
|
|
}
|
|
|
|
/*
|
|
* Save the session callback
|
|
*/
|
|
static int
|
|
session_save_state (GnomeClient *client, gint phase, GnomeRestartStyle save_style, gint shutdown,
|
|
GnomeInteractStyle interact_style, gint fast, gpointer client_data)
|
|
{
|
|
char *sess_id;
|
|
char **argv = g_malloc (sizeof (char *) * ((g_list_length (containers) * 3) + 2));
|
|
GList *l, *free_list = 0;
|
|
int i;
|
|
|
|
sess_id = gnome_client_get_id (client);
|
|
|
|
argv [0] = client_data;
|
|
for (i = 1, l = containers; l; l = l->next){
|
|
PanelContainer *pc = l->data;
|
|
char *geom;
|
|
|
|
geom = gnome_geometry_string (GTK_WIDGET (pc->panel->widget.wdata)->window);
|
|
|
|
argv [i++] = pc->panel->cwd;
|
|
argv [i++] = "--geometry";
|
|
argv [i++] = geom;
|
|
free_list = g_list_append (free_list, geom);
|
|
}
|
|
|
|
/* If no windows were open */
|
|
if (i == 1){
|
|
argv [i++] = "--nowindows";
|
|
}
|
|
|
|
argv [i] = NULL;
|
|
gnome_client_set_clone_command (client, i, argv);
|
|
gnome_client_set_restart_command (client, i, argv);
|
|
gnome_config_sync ();
|
|
|
|
for (l = free_list; l; l = l->next)
|
|
g_free (l->data);
|
|
g_list_free (free_list);
|
|
|
|
g_free (argv);
|
|
|
|
if (shutdown){
|
|
quit = 1;
|
|
dlg_stop (midnight_dlg);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
session_management_setup (char *name)
|
|
{
|
|
session_client = gnome_master_client ();
|
|
|
|
if (session_client){
|
|
gnome_client_set_restart_style (session_client,
|
|
finish_program ? GNOME_RESTART_NEVER : GNOME_RESTART_IMMEDIATELY);
|
|
gtk_signal_connect (GTK_OBJECT (session_client), "save_yourself",
|
|
GTK_SIGNAL_FUNC (session_save_state), name);
|
|
gtk_signal_connect (GTK_OBJECT (session_client), "die",
|
|
GTK_SIGNAL_FUNC (session_die), NULL);
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
* Configures the GtkWindow/GnomeDialog from a WPanel.
|
|
*
|
|
* This makes the window centered on the screen and binds it to
|
|
* its parent container for better window manager experience
|
|
*/
|
|
void
|
|
gmc_window_setup_from_panel (GnomeDialog *dialog, WPanel *panel)
|
|
{
|
|
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
|
|
gnome_dialog_set_parent (dialog, GTK_WINDOW (panel->xwindow));
|
|
}
|
|
|
|
/**
|
|
* gnome_check_super_user:
|
|
* @void:
|
|
*
|
|
* Puts out a warning if the user is running gmc as root. If the user selects
|
|
* Cancel, then gmc will terminate.
|
|
**/
|
|
void
|
|
gnome_check_super_user (void)
|
|
{
|
|
GtkWidget *warning_dlg;
|
|
GnomeClient *client;
|
|
|
|
if (geteuid () != 0)
|
|
return;
|
|
|
|
warning_dlg = gnome_message_box_new (
|
|
_("You are running the GNOME Midnight Commander as root. \n\n"
|
|
"You will not be protected from severly damaging your system."),
|
|
GNOME_MESSAGE_BOX_WARNING,
|
|
GNOME_STOCK_BUTTON_OK, NULL);
|
|
|
|
gnome_dialog_run (GNOME_DIALOG (warning_dlg));
|
|
}
|