/* AbiSource Program Utilities * Copyright (C) 1998 AbiSource, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include "ut_debugmsg.h" #include "ut_assert.h" #include "ut_string.h" #include"xav_View.h" #include"xap_Frame.h" #include"xap_App.h" #ifdef HAVE_GNOME #include #include #endif // default GTK message box button width, in GTK screen units (pixels) #define DEFAULT_BUTTON_WIDTH 85 /*****************************************************************/ static gboolean focus_in_event(GtkWidget *widget,GdkEvent */*event*/,gpointer /*user_data*/) { XAP_Frame *pFrame=(XAP_Frame *)gtk_object_get_data(GTK_OBJECT(widget), "frame"); UT_ASSERT(pFrame); if (pFrame->getCurrentView()) pFrame->getCurrentView()->focusChange(AV_FOCUS_NEARBY); return FALSE; } static gboolean destroy_event(GtkWidget *widget,GdkEvent */*event*/,gpointer /*user_data*/) { XAP_Frame *pFrame=(XAP_Frame *)gtk_object_get_data(GTK_OBJECT(widget), "frame"); if(pFrame == NULL) return FALSE; return FALSE; } static gboolean focus_out_event(GtkWidget *widget,GdkEvent */*event*/,gpointer /*user_data*/) { XAP_Frame *pFrame=(XAP_Frame *)gtk_object_get_data(GTK_OBJECT(widget), "frame"); if(pFrame == NULL) return FALSE; AV_View * pView = pFrame->getCurrentView(); if(pView!= NULL) { pView->focusChange(AV_FOCUS_NONE); } return FALSE; } static gboolean focus_out_event_Modeless(GtkWidget *widget,GdkEvent */*event*/,gpointer /*user_data*/) { XAP_App *pApp = (XAP_App *)gtk_object_get_data(GTK_OBJECT(widget), "pApp"); XAP_Frame *pFrame = pApp->getLastFocussedFrame(); if(pFrame ==(XAP_Frame *) NULL) { UT_uint32 nframes = pApp->getFrameCount(); if(nframes > 0 && nframes < 10) { pFrame = pApp->getFrame(0); } else { return FALSE; } } if(pFrame == (XAP_Frame *) NULL) return FALSE; AV_View * pView = pFrame->getCurrentView(); UT_ASSERT(pView); if(pView!= NULL) { pView->focusChange(AV_FOCUS_NONE); } return FALSE; } static gboolean focus_in_event_Modeless(GtkWidget *widget,GdkEvent */*event*/,gpointer /*user_data*/) { XAP_App *pApp=(XAP_App *)gtk_object_get_data(GTK_OBJECT(widget), "pApp"); XAP_Frame *pFrame= pApp->getLastFocussedFrame(); if(pFrame ==(XAP_Frame *) NULL) { UT_uint32 nframes = pApp->getFrameCount(); if(nframes > 0 && nframes < 10) { pFrame = pApp->getFrame(0); } else { return FALSE; } } if(pFrame == (XAP_Frame *) NULL) return FALSE; AV_View * pView = pFrame->getCurrentView(); if(pView!= NULL) { pView->focusChange(AV_FOCUS_MODELESS); } return FALSE; } static gboolean focus_in_event_ModelessOther(GtkWidget *widget,GdkEvent */*event*/,gboolean (*other_function)(void) ) { XAP_App *pApp=(XAP_App *)gtk_object_get_data(GTK_OBJECT(widget), "pApp"); XAP_Frame *pFrame= pApp->getLastFocussedFrame(); if(pFrame ==(XAP_Frame *) NULL) { UT_uint32 nframes = pApp->getFrameCount(); if(nframes > 0 && nframes < 10) { pFrame = pApp->getFrame(0); } else { return FALSE; } } if(pFrame == (XAP_Frame *) NULL) return FALSE; AV_View * pView = pFrame->getCurrentView(); if(pView!= NULL) { pView->focusChange(AV_FOCUS_MODELESS); (*other_function)(); } return FALSE; } void connectFocus(GtkWidget *widget,const XAP_Frame *frame) { gtk_object_set_data(GTK_OBJECT(widget), "frame", (void *)frame); gtk_signal_connect(GTK_OBJECT(widget), "focus_in_event", GTK_SIGNAL_FUNC(focus_in_event), NULL); gtk_signal_connect(GTK_OBJECT(widget), "focus_out_event", GTK_SIGNAL_FUNC(focus_out_event), NULL); gtk_signal_connect(GTK_OBJECT(widget), "destroy", GTK_SIGNAL_FUNC(destroy_event), NULL); } void connectFocusModelessOther(GtkWidget *widget,const XAP_App * pApp, gboolean(*other_function)(void)) { gtk_object_set_data(GTK_OBJECT(widget), "pApp", (void *)pApp); gtk_signal_connect(GTK_OBJECT(widget), "focus_in_event", GTK_SIGNAL_FUNC(focus_in_event_ModelessOther), (gpointer) other_function); gtk_signal_connect(GTK_OBJECT(widget), "focus_out_event", GTK_SIGNAL_FUNC(focus_out_event_Modeless), NULL); gtk_signal_connect(GTK_OBJECT(widget), "destroy", GTK_SIGNAL_FUNC(focus_out_event_Modeless), NULL); } void connectFocusModeless(GtkWidget *widget,const XAP_App * pApp) { gtk_object_set_data(GTK_OBJECT(widget), "pApp", (void *)pApp); gtk_signal_connect(GTK_OBJECT(widget), "focus_in_event", GTK_SIGNAL_FUNC(focus_in_event_Modeless), NULL); gtk_signal_connect(GTK_OBJECT(widget), "focus_out_event", GTK_SIGNAL_FUNC(focus_out_event_Modeless), NULL); gtk_signal_connect(GTK_OBJECT(widget), "destroy", GTK_SIGNAL_FUNC(destroy_event), NULL); } bool isTransientWindow(GtkWindow *window,GtkWindow *parent) { if(window) { while(window->transient_parent) { window=window->transient_parent; if(window==parent) return true; } } return false; } gint s_key_pressed(GtkWidget * /* widget */, GdkEventKey * e) { UT_ASSERT(e); guint key = e->keyval; // TODO this is hard coded, maybe fix it if (key == 'k' || key == GDK_Escape) { gtk_main_quit(); } return TRUE; } /* This is a small message box for startup warnings and/or errors. Please do NOT use this for normal system execution user messages; use the XAP_UnixDialog_MessageBox class for that. We can't use that here because there is no parent frame, etc. */ void messageBoxOK(const char * message) { // New GTK+ dialog window GtkWidget * dialog_window = gtk_dialog_new(); gtk_signal_connect_after (GTK_OBJECT (dialog_window), "destroy", NULL, NULL); gtk_signal_connect_after (GTK_OBJECT (dialog_window), "delete_event", GTK_SIGNAL_FUNC(gtk_main_quit), NULL); gtk_window_set_title(GTK_WINDOW(dialog_window), "AbiWord"); // don't let user shrink or expand, but auto-size to // contents initially gtk_window_set_policy(GTK_WINDOW(dialog_window), FALSE, FALSE, TRUE); // Intercept key strokes gtk_signal_connect(GTK_OBJECT(dialog_window), "key_press_event", GTK_SIGNAL_FUNC(s_key_pressed), NULL); // Add our label string to the dialog in the message area GtkWidget * label = gtk_label_new(message); gtk_misc_set_padding(GTK_MISC(label), 10, 10); gtk_box_pack_start(GTK_BOX(GTK_DIALOG (dialog_window)->vbox), label, TRUE, TRUE, 0); gtk_widget_show(label); GtkWidget * ok_label; GtkWidget * ok_button; guint ok_accel; // create the OK ok_label = gtk_label_new("SHOULD NOT APPEAR"); ok_accel = gtk_label_parse_uline(GTK_LABEL(ok_label), "O_K"); gtk_widget_show(ok_label); ok_button = gtk_button_new(); gtk_container_add(GTK_CONTAINER(ok_button), ok_label); gtk_signal_connect (GTK_OBJECT (ok_button), "clicked", GTK_SIGNAL_FUNC(gtk_main_quit), NULL); GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT); gtk_widget_set_usize(ok_button, DEFAULT_BUTTON_WIDTH, 0); // pack the OK gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_window)->action_area), ok_button, FALSE, FALSE, 0); gtk_widget_grab_default (ok_button); gtk_widget_show (ok_button); // set the size of the dialog to size with the label inside gtk_widget_size_request(dialog_window, &dialog_window->requisition); gtk_widget_set_usize(dialog_window, dialog_window->requisition.width + 40, 0); // center it (in what?) // GdkWindowPrivate * rootWindow = ::getRootWindow(dialog_window); // centerDialog((GdkWindow *) rootWindow, dialog_window); // gtk_window_set_transient_for(GTK_WINDOW(dialog_window), GTK_WINDOW(parent)); gtk_grab_add(GTK_WIDGET(dialog_window)); gtk_widget_show(dialog_window); gtk_main(); // clean up gtk_widget_destroy(GTK_WIDGET(dialog_window)); } GdkWindowPrivate * getRootWindow(GtkWidget * widget) { UT_ASSERT(widget); GdkWindowPrivate * priv = (GdkWindowPrivate *) widget->window; while (priv->parent && ((GdkWindowPrivate*) priv->parent)->parent) priv = (GdkWindowPrivate*) priv->parent; return (GdkWindowPrivate *) priv; } #ifndef HAVE_GNOME // plain, vanilla GTK+ version of this function void centerDialog(GtkWidget * parent, GtkWidget * child) { UT_ASSERT(parent); UT_ASSERT(child); gtk_window_set_transient_for(GTK_WINDOW(child), GTK_WINDOW(parent)); } #else // HAVE_GNOME // souped-up gnome version of this function void centerDialog(GtkWidget * parent, GtkWidget * child) { UT_ASSERT(parent); UT_ASSERT(child); // if it's a gnome dialog, we want this behavior if (GNOME_IS_DIALOG (child)) { gnome_dialog_set_parent (GNOME_DIALOG (child), GTK_WINDOW (parent)); } else { gtk_window_set_transient_for(GTK_WINDOW(child), GTK_WINDOW(parent)); } gnome_window_icon_set_from_default (GTK_WINDOW(child)); } #endif gint searchCList(GtkCList * clist, char * compareText) { UT_ASSERT(clist); // if text is null, it's not found if (!compareText) return -1; gchar * text[2] = {NULL, NULL}; for (gint i = 0; i < clist->rows; i++) { gtk_clist_get_text(clist, i, 0, text); if (text && text[0]) if (!UT_stricmp(text[0], compareText)) return i; } return -1; } /**************************************************************************** Written by: Stephen Hack date: Thu Oct 14 1999 Purpose To recursivily change the labels in a window (any container) from the windows & to GTK+'s underline format Can support multiple &'s, to get an & into the document, enter \& Usage fix_label( GtkWidget *window ) Compile time Options FIXLBL_DBG if defined, will print out a nested listing of all labels ***************************************************************************/ #include #include static const gchar KEY_ACCEL_GROUP[] = "ACCEL_GROUP"; #define DBG(a) {a} /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Data types * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ struct fix_label_data { int depth; GtkWidget *topwindow; GtkWidget *accel_ctrl; gchar *accel_sig; GtkAccelGroup *accel_group; }; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Prototypes * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static void on_notebook_switch_page( GtkNotebook *notebook, GtkNotebookPage *page, gint page_num, gpointer user_data ); static void process_notebook_page( GtkWidget *notebook, GtkWidget *page, struct fix_label_data *data ); static void fix_label_callback( GtkWidget *widget, gpointer _data ); //static void fix_label( GtkWidget *widget ); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Call back routine for switching accelerator groups * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static void on_notebook_switch_page (GtkNotebook *notebook, GtkNotebookPage *page, gint page_num, gpointer user_data) { GtkAccelGroup *oldaccel, *newaccel; GtkWindow *topwindow = (GtkWindow *)user_data; UT_ASSERT(topwindow && GTK_IS_WINDOW(topwindow)); UT_ASSERT(notebook && GTK_IS_NOTEBOOK(notebook)); UT_ASSERT(page && page->child && GTK_IS_OBJECT(page->child)); if ( GTK_OBJECT_DESTROYED(notebook) ) return ; oldaccel = (GtkAccelGroup *)gtk_object_get_data( GTK_OBJECT(notebook), KEY_ACCEL_GROUP ); newaccel = (GtkAccelGroup *)gtk_object_get_data( GTK_OBJECT(page->child), KEY_ACCEL_GROUP ); if ( oldaccel ) gtk_window_remove_accel_group( topwindow, oldaccel ); gtk_window_add_accel_group( topwindow, newaccel ); gtk_object_set_data(GTK_OBJECT(notebook), KEY_ACCEL_GROUP, newaccel ); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * To process a notebook page * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static void process_notebook_page( GtkWidget *notebook, GtkWidget *page, struct fix_label_data *data ) { GtkAccelGroup *newgroup; struct fix_label_data newdata; UT_ASSERT(notebook && page && data && data->topwindow); UT_ASSERT( GTK_IS_NOTEBOOK(notebook) ); UT_ASSERT( GTK_IS_WIDGET(page) ); memcpy( &newdata, data, sizeof(struct fix_label_data)); newgroup = gtk_accel_group_new(); UT_ASSERT(newgroup); gtk_object_set_data( GTK_OBJECT(page), KEY_ACCEL_GROUP, (gpointer)newgroup ); newdata.accel_group = newgroup; fix_label_callback( page, &newdata ); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * The recursive call back function for gtk_container_for_all * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #ifdef TRACE # undef TRACE #endif #ifdef DBG_FIX_LABEL # define TRACE(a) { for ( i = 0; i < data->depth; i++ ) printf(" "); \ printf a; printf("\n"); } #else # define TRACE(a) #endif static void fix_label_callback( GtkWidget *widget, gpointer _data ) { struct fix_label_data *data = (struct fix_label_data *)_data; struct fix_label_data newdata; int i, pageindex; gchar *str; gchar *newlbl; guint accelch; gpointer accel_group; GtkWidget *w, *accel_tie; char *dbg_str; UT_ASSERT(widget && _data); memcpy( &newdata, _data, sizeof(struct fix_label_data) ); newdata.depth = data->depth + 1; newdata.accel_ctrl = widget; dbg_str = "garbage"; if ( GTK_IS_BUTTON(widget) ) { newdata.accel_sig = "clicked"; DBG(dbg_str = "button";) } else { // we can't find what type to set accels to, then use parent newdata.accel_ctrl = data->accel_ctrl; newdata.accel_sig = data->accel_sig; DBG(dbg_str = "container";) } // if it's a containter, go deeper if ( GTK_IS_NOTEBOOK(widget) ) { TRACE(("NOTEBOOK")); for ( pageindex = 0; (w = gtk_notebook_get_nth_page( GTK_NOTEBOOK(widget), pageindex)) != 0; pageindex++ ) { TRACE(("Page %i", pageindex)); UT_ASSERT( data->topwindow ); process_notebook_page( widget, w, &newdata ); if ( pageindex == 0 ) { accel_group = gtk_object_get_data( GTK_OBJECT(w), KEY_ACCEL_GROUP); gtk_object_set_data( GTK_OBJECT(widget), KEY_ACCEL_GROUP, accel_group ); gtk_window_add_accel_group( GTK_WINDOW(data->topwindow), (GtkAccelGroup *)accel_group); } } /* set the signal handler to change to accel groups */ gtk_signal_connect (GTK_OBJECT(widget), "switch_page", GTK_SIGNAL_FUNC (on_notebook_switch_page), data->topwindow ); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * handler for an option menu */ else if ( GTK_IS_OPTION_MENU( widget ) ) { TRACE(("found option menu " )); accel_tie = (GtkWidget *)gtk_object_get_data( GTK_OBJECT(widget), "accel-tie"); if ( accel_tie ) { UT_ASSERT( GTK_IS_LABEL(accel_tie) ); } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * default handler for a 'container' */ else if ( GTK_IS_CONTAINER( widget ) ) { /* go deeper */ TRACE(("found %s - ", dbg_str )); gtk_container_forall( GTK_CONTAINER(widget), fix_label_callback, (gpointer *)&newdata ); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * handle a label */ else if ( GTK_IS_LABEL( widget ) ) { gtk_label_get( GTK_LABEL(widget), &str ); UT_ASSERT(str); TRACE(("found label [%s] ", str )); /* convert the &'s into _'s . Also handle \& as &'s */ accelch = 0; newlbl = UT_strdup(str); UT_ASSERT(newlbl); for ( i = 0; newlbl[i] != 0; i++ ) { if ( newlbl[i] == '&' ) { if ( i > 0 && newlbl[i-1] == '\\' ) { newlbl[i-1] = '&'; strcpy( &newlbl[i], &newlbl[i+1]); i--; } else newlbl[i] = '_'; } } /* underline the words */ accelch = gtk_label_parse_uline(GTK_LABEL(widget), newlbl); /* added an accelerator if need be */ if ( accelch != GDK_VoidSymbol && data->accel_ctrl && data->accel_group ) { gtk_widget_add_accelerator (data->accel_ctrl, data->accel_sig, data->accel_group, accelch, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); } if ( newlbl ) free(newlbl); } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * the actual exported call * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ void createLabelAccelerators( GtkWidget *widget ) { struct fix_label_data data = { 0, 0, 0, 0, 0 }; data.depth = 0; data.accel_group = gtk_accel_group_new(); data.topwindow = widget; fix_label_callback( widget, &data ); gtk_window_add_accel_group (GTK_WINDOW (widget), data.accel_group); } #ifdef HAVE_GNOME void setDefaultButton (GnomeDialog * dlg, int which) { gnome_dialog_set_default (dlg, which); #if 0 gnome_dialog_grab_focus (dlg, which); gnome_dialog_set_sensitive (dlg, which, TRUE); #endif } #endif /*! * For a parented/displayed widget, this will just return * gtk_widget_ensure_style(w). For a non-displayed widgets, * This will return a valid GtkStyle for that widget */ GtkStyle * get_ensured_style (GtkWidget * w) { GtkStyle * style = NULL; GtkWidget * hidden_window = NULL; if (w->parent == NULL) { hidden_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_container_add (GTK_CONTAINER (hidden_window), w); } gtk_widget_ensure_style (w); gtk_widget_realize (w); style = gtk_widget_get_style (w); UT_ASSERT(style); if (hidden_window) { // now we destroy the hidden window gtk_container_remove (GTK_CONTAINER(hidden_window), w); gtk_widget_destroy (hidden_window); } return style; } GtkWidget *createDrawingArea () { GtkWidget *area; gtk_widget_push_visual (gdk_rgb_get_visual ()); gtk_widget_push_colormap (gdk_rgb_get_cmap ()); area = gtk_drawing_area_new (); gtk_widget_pop_colormap (); gtk_widget_pop_visual (); return area; }