#include #include #include #include #include #include #if defined(WIN32) # include # define HAVE_WIN32 #else # include # define HAVE_X #endif #if defined(__SOLARIS__) || defined(__hpux) # include "../include/os.h" #endif #include "guiutils.h" #include "images/icon_browse_20x20.xpm" /* * Root GdkWindow: */ static GdkWindow *gui_window_root = NULL; /* * Default GTK Style: */ static GtkStyle *gui_style_default = NULL; /* * GtkInvisible Toplevel Widget: * * For grabbing and blocking input in GUIBlockInput(). */ static GtkWidget *gui_invisible_blocker_widget = NULL; static gint gui_block_input_level = 0; /* * DDE Owner Callback Data: */ typedef struct { GtkWidget *w; /* Owner GtkWidget */ GdkAtom target_atom; /* GdkTarget */ GdkAtom type_atom; /* GdkSelectionType */ guint selection_clear_event_id, selection_get_id; gpointer data; /* Data (coppied) */ gint length; /* Data length in bytes */ } gui_dde_owner_struct; #define GUI_DDE_OWNER(p) ((gui_dde_owner_struct *)(p)) #define GUI_DDE_OWNER_DATA_KEY "gui_dde_owner" /* * DND Callback Data: * * Used for callback data in GUIDND*CB() functions. */ typedef struct { GdkDragAction default_action_same, /* Action to use if same widget */ default_action; /* Action for all other cases */ } gui_dnd_cb_struct; #define GUI_DND_CB(p) ((gui_dnd_cb_struct *)(p)) /* * DND Icon Widget: * * Initialized on first call to GUIDNDSetDragIcon() and used in * GUIDNDDragBeginCB() and GUIDNDDragReceivedCB(). */ typedef struct { GtkWidget *toplevel, *icon_pm; gint x, /* Hot spot */ y, width, /* Size */ height; } gui_dnd_icon_struct; #define GUI_DND_ICON(p) ((gui_dnd_icon_struct *)(p)) static gui_dnd_icon_struct gui_dnd_icon; /* * Banner Data: */ #define GUI_BANNER_DATA_KEY "gui_banner_data" /* * Button Data: * * For recording widgets on buttons and toggle buttons, stored as * the object's user data. */ typedef struct { GtkWidget *button, /* GtkButton */ *main_box, /* GtkBox */ *label, /* GtkLabel */ *pixmap, /* GtkPixmap */ *arrow; /* GtkArrow */ gchar *label_text; /* Copy of label text */ const guint8 **icon_data; /* Shared icon data */ GtkArrowType arrow_type; } gui_button_data_struct; #define GUI_BUTTON_DATA(p) ((gui_button_data_struct *)(p)) #define GUI_BUTTON_DATA_KEY "gui_button_data" /* * Pullout Data: */ #define GUI_PULLOUT_DATA_KEY "gui_pullout_data" /* * Combo Data: */ #define GUI_COMBO_DATA_KEY "gui_combo_data" /* * Menu Item Data: * * For recording widgets on menu items, stored as the object's * user data. */ typedef struct { GtkWidget *menu_item, *label, *accel_label, *pixmap; gchar *label_text, /* Copy of label text */ *accel_text; /* Copy of accel label text */ const guint8 **icon_data; /* Shared icon data */ guint accel_key, accel_mods; } gui_menu_item_data_struct; #define GUI_MENU_ITEM_DATA(p) ((gui_menu_item_data_struct *)(p)) #define GUI_MENU_ITEM_DATA_KEY "gui_menu_item_data" #define GUI_MENU_ITEM_CLIENT_DATA_KEY "gui_menu_item_client_data" /* * Tool Tips Group: * * Used as the tool tips group for all GUI*() functions. */ static GtkTooltips *gui_tooltips = NULL; static gboolean gui_tooltips_state; /* Global enabled or disabled */ static gchar *GUIGetKeyName(guint key); static void GUIDDEOwnerDestroyCB(gpointer data); static gboolean GUIDDESelectionClearEventCB( GtkWidget *widget, GdkEventSelection *event, gpointer data ); static void GUIDDESelectionGetCB( GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint t, gpointer data ); static void GUIDDESelectionReceivedCB( GtkWidget *widget, GtkSelectionData *selection_data, guint t, gpointer data ); static void GUIDNDDragBeginCB( GtkWidget *widget, GdkDragContext *dc, gpointer data ); static gboolean GUIDNDDragMotionCB( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t, gpointer data ); static gboolean GUIDNDDragDropCB( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t, gpointer data ); static void GUIDNDDragReceivedCB( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, gpointer data ); static void GUIDNDDragEndCB( GtkWidget *widget, GdkDragContext *dc, gpointer data ); static void GUIButtonDataDestroyCB(gpointer data); static gint GUIBannerEventCB( GtkWidget *widget, GdkEvent *event, gpointer data ); static void GUIBannerDataDestroyCB(gpointer data); static void GUIComboActivateCB(GtkWidget *widget, gpointer data); static void GUIComboChangedCB(GtkWidget *widget, gpointer data); static void GUIComboDataDestroyCB(gpointer data); static void GUIMenuActivateCB(gpointer data); static void GUIMenuClientDataDestroyCB(gpointer data); static void GUIMenuDataDestroyCB(gpointer data); static void GUIPullOutDataDestroyCB(gpointer data); static void GUIPullOutDrawHandleDrawCB( GtkWidget *widget, GdkRectangle *area, gpointer data ); static gint GUIPullOutDrawHandleCB( GtkWidget *widget, GdkEvent *event, gpointer data ); static gint GUIPullOutPullOutBtnCB( GtkWidget *widget, GdkEvent *event, gpointer data ); static gint GUIPullOutCloseCB(GtkWidget *widget, GdkEvent *event, gpointer data); /* GtkRcStyle Utilities */ GtkRcStyle *GUIRCStyleCopy(const GtkRcStyle *rcstyle); void GUIRCStyleSetRecursive(GtkWidget *w, GtkRcStyle *rcstyle); /* Geometry */ GdkGeometryFlags GUIParseGeometry( const gchar *s, gint *x, gint *y, gint *width, gint *height ); gboolean GUICListGetCellGeometry( GtkCList *clist, gint column, gint row, gint *x, gint *y, gint *width, gint *height ); gint GUICTreeNodeRow(GtkCTree *ctree, GtkCTreeNode *node); static void GUICTreeNodeDeltaRowsIterate( GtkCTree *ctree, GtkCTreeNode *node, GtkCTreeNode *end, gint *row_count, gboolean *end_found ); gint GUICTreeNodeDeltaRows( GtkCTree *ctree, GtkCTreeNode *start, /* Use NULL for first/toplevel node */ GtkCTreeNode *end ); void GUIGetWindowRootPosition( GdkWindow *window, gint *x, gint *y ); void GUIGetPositionRoot( GdkWindow *w, gint x, gint y, gint *rx, gint *ry ); /* String Utilities */ void GUIGetTextBounds( GdkFont *font, const gchar *text, gint text_length, GdkTextBounds *bounds ); void GUIGetStringBounds( GdkFont *font, const gchar *string, GdkTextBounds *bounds ); /* GdkGC Utilities */ GdkGC *GDK_GC_NEW(void); /* GdkWindow utilities */ gint GUIWindowGetRefCount(GdkWindow *window); /* WM Utilities */ void GUISetWMIcon(GdkWindow *window, guint8 **data); void GUISetWMIconFile(GdkWindow *window, const gchar *filename); /* GtkWindow Utilities */ void GUIWindowApplyArgs(GtkWindow *w, gint argc, gchar **argv); /* GtkCTree Utilities */ gboolean GUICTreeOptimizeExpandPosition( GtkCTree *ctree, GtkCTreeNode *node /* Expanded parent node */ ); /* GdkBitmap */ GdkBitmap *GUICreateBitmapFromDataRGBA( gint width, gint height, gint bpl, const guint8 *rgba, guint8 threshold, GdkWindow *window ); /* Pixmap Utilities */ GdkPixmap *GDK_PIXMAP_NEW(gint width, gint height); GdkPixmap *GDK_PIXMAP_NEW_FROM_XPM_DATA( GdkBitmap **mask_rtn, guint8 **data ); GdkPixmap *GDK_PIXMAP_NEW_FROM_XPM_FILE( GdkBitmap **mask_rtn, const gchar *filename ); GtkWidget *gtk_pixmap_new_from_xpm_d( GdkWindow *window, GdkColor *transparent_color, guint8 **data ); GtkWidget *GUICreateMenuItemIcon(guint8 **icon_data); /* Widget & Window Mapping */ void GUIWidgetMapRaise(GtkWidget *w); void GUIWindowMinimize(GtkWindow *window); /* Tool Tips */ static void GUICreateGlobalTooltips(void); void GUISetWidgetTip(GtkWidget *w, const gchar *tip); void GUIShowTipsNow(GtkWidget *w); void GUISetGlobalTipsState(gboolean state); /* Buttons With Icon & Label */ void GUIButtonChangeLayout( GtkWidget *w, gboolean show_pixmap, gboolean show_label ); void GUIButtonLabelUnderline(GtkWidget *w, guint c); void GUIButtonPixmapUpdate( GtkWidget *w, guint8 **icon, const gchar *label ); void GUIButtonArrowUpdate( GtkWidget *w, GtkArrowType arrow_type, gint arrow_width, gint arrow_height, const gchar *label ); GtkWidget *GUIButtonGetMainBox(GtkWidget *w); GtkWidget *GUIButtonGetLabel(GtkWidget *w); GtkWidget *GUIButtonGetPixmap(GtkWidget *w); GtkWidget *GUIButtonGetArrow(GtkWidget *w); gchar *GUIButtonGetLabelText(GtkWidget *w); static GtkWidget *GUIButtonPixmapLabelHV( guint8 **icon, const gchar *label, GtkWidget **label_rtn, gboolean horizontal ); GtkWidget *GUIButtonPixmapLabelH( guint8 **icon, const gchar *label, GtkWidget **label_rtn ); GtkWidget *GUIButtonPixmapLabelV( guint8 **icon, const gchar *label, GtkWidget **label_rtn ); GtkWidget *GUIButtonPixmap(guint8 **icon); /* Buttons With Arrow & Label */ static GtkWidget *GUIButtonArrowLabelHV( GtkArrowType arrow_type, gint arrow_width, gint arrow_height, const gchar *label, GtkWidget **label_rtn, gboolean horizontal ); GtkWidget *GUIButtonArrowLabelH( GtkArrowType arrow_type, gint arrow_width, gint arrow_height, const gchar *label, GtkWidget **label_rtn ); GtkWidget *GUIButtonArrowLabelV( GtkArrowType arrow_type, gint arrow_width, gint arrow_height, const gchar *label, GtkWidget **label_rtn ); GtkWidget *GUIButtonArrow( GtkArrowType arrow_type, gint arrow_width, gint arrow_height ); /* Toggle Buttons With Icon & Label */ static GtkWidget *GUIToggleButtonPixmapLabelHV( guint8 **icon, const gchar *label, GtkWidget **label_rtn, gboolean horizontal ); GtkWidget *GUIToggleButtonPixmapLabelH( guint8 **icon, const gchar *label, GtkWidget **label_rtn ); GtkWidget *GUIToggleButtonPixmapLabelV( guint8 **icon, const gchar *label, GtkWidget **label_rtn ); GtkWidget *GUIToggleButtonPixmap(guint8 **icon); /* Prompts With Icon, Label, Entry, and Browse */ static GtkWidget *GUIPromptBarOrBrowse( guint8 **icon, const gchar *label, gpointer *label_rtn, gpointer *entry_rtn, gpointer *browse_rtn ); GtkWidget *GUIPromptBarWithBrowse( guint8 **icon, const gchar *label, gpointer *label_rtn, gpointer *entry_rtn, gpointer *browse_rtn, gpointer browse_data, void (*browse_cb)(GtkWidget *, gpointer) ); GtkWidget *GUIPromptBar( guint8 **icon, const gchar *label, gpointer *label_rtn, gpointer *entry_rtn ); /* Dynamic Data Exchange */ void GUIDDESetBinary( GtkWidget *w, /* Owner widget */ GdkAtom selection_atom, /* Can be GDK_NONE */ gulong t, /* Time */ const guint8 *data, gint length ); guint8 *GUIDDEGetBinary( GtkWidget *w, /* Widget making request */ GdkAtom selection_atom, /* Can be GDK_NONE */ gulong t, /* Time */ gint *length ); void GUIDDESetString( GtkWidget *w, /* Owner widget */ GdkAtom selection_atom, /* Can be GDK_NONE */ gulong t, /* Time */ const gchar *data ); gchar *GUIDDEGetString( GtkWidget *w, /* Widget making request */ GdkAtom selection_atom, /* Can be GDK_NONE */ gulong t /* Time */ ); /* Drag & Drop Utilities */ void GUIDNDSetSrc( void *w, const void *drag_type, int ndrag_types, unsigned int actions, unsigned int buttons, void (*begin_cb)(GtkWidget *, GdkDragContext *, gpointer), void (*request_data_cb)(GtkWidget *, GdkDragContext *, GtkSelectionData *, guint, guint, gpointer), void (*delete_data_cb)(GtkWidget *, GdkDragContext *, gpointer), void (*end_cb)(GtkWidget *, GdkDragContext *, gpointer), gpointer client_data ); void GUIDNDSetTar( void *w, const void *drag_type, int ndrag_types, unsigned int actions, unsigned int default_action_same, unsigned int default_action, void (*recieved_data_cb)(GtkWidget *, GdkDragContext *, gint, gint, GtkSelectionData *, guint, guint, gpointer ), gpointer client_data ); void GUIDNDSetDragIcon( GdkPixmap *pixmap, GdkBitmap *mask, gint hot_x, gint hot_y ); /* Banners */ GtkWidget *GUIBannerCreate( const gchar *label, const gchar *font_name, GdkColor color_fg, GdkColor color_bg, GtkJustification justify, /* One of GTK_JUSTIFY_* */ gboolean expand ); void GUIBannerDraw(GtkWidget *w); /* Combo With Label, Combo, Initial Value, and Initial List */ GtkWidget *GUIComboCreate( const gchar *label, /* Label */ const gchar *text, /* Entry Value */ GList *list, /* Combo List */ gint max_items, /* Maximum Items In Combo List */ gpointer *combo_rtn, /* GtkCombo Return */ gpointer data, void (*func_cb)(GtkWidget *w, gpointer), void (*list_change_cb)(GtkWidget *, gpointer, GList *) ); void GUIComboActivateValue(GtkWidget *w, const gchar *value); void GUIComboAddItem(GtkWidget *w, const gchar *value); GList *GUIComboGetList(GtkWidget *w); void GUIComboSetList(GtkWidget *w, GList *list); void GUIComboClearAll(GtkWidget *w); /* Menu Bar & Menu Item */ GtkWidget *GUIMenuBarCreate(GtkAccelGroup **accelgrp_rtn); GtkWidget *GUIMenuCreateTearOff(void); GtkWidget *GUIMenuCreate(void); GtkWidget *GUIMenuItemCreate( GtkWidget *menu, gui_menu_item_type type, /* One of GUI_MENU_ITEM_TYPE_* */ GtkAccelGroup *accelgrp, guint8 **icon, const gchar *label, guint accel_key, guint accel_mods, gpointer *functional_widget_rtn, gpointer data, void (*func_cb)(GtkWidget *w, gpointer) ); void GUISetMenuItemDefault(GtkWidget *w); void GUISetMenuItemCrossingCB( GtkWidget *w, gint (*enter_cb)(GtkWidget *, GdkEvent *, gpointer), gpointer enter_data, gint (*leave_cb)(GtkWidget *, GdkEvent *, gpointer), gpointer leave_data ); GtkWidget *GUIMenuAddToMenuBar( GtkWidget *menu_bar, GtkWidget *menu, const gchar *label, gui_menu_bar_item_alignment align ); void GUIMenuItemSetLabel(GtkWidget *menu_item, const gchar *label); void GUIMenuItemSetPixmap(GtkWidget *menu_item, guint8 **icon_data); void GUIMenuItemSetAccelKey( GtkWidget *menu_item, GtkAccelGroup *accelgrp, guint accel_key, guint accel_mods ); void GUIMenuItemSetCheck( GtkWidget *menu_item, gboolean active, gboolean emit ); gboolean GUIMenuItemGetCheck(GtkWidget *menu_item); GtkWidget *GUIMenuAddToMenuBarPixmapH( GtkWidget *menu_bar, GtkWidget *menu, const gchar *label, guint8 **icon_data, gui_menu_bar_item_alignment align ); void GUIMenuItemSetSubMenu( GtkWidget *menu_item, GtkWidget *sub_menu ); /* Pull Out Window */ void *GUIPullOutCreateH( void *parent_box, int homogeneous, int spacing, /* Of client vbox */ int expand, int fill, int padding, /* Of holder hbox */ int toplevel_width, int toplevel_height, void *pull_out_client_data, void (*pull_out_cb)(void *, void *), void *push_in_client_data, void (*push_in_cb)(void *, void *) ); void *GUIPullOutGetToplevelWindow( void *client_box, int *x, int *y, int *width, int *height ); void GUIPullOutPullOut(void *client_box); void GUIPullOutPushIn(void *client_box); #ifndef ISBLANK # define ISBLANK(c) (((c) == ' ') || ((c) == '\t')) #endif #define ATOI(s) (((s) != NULL) ? atoi(s) : 0) #define ATOL(s) (((s) != NULL) ? atol(s) : 0) #define ATOF(s) (((s) != NULL) ? atof(s) : 0.0f) #define STRDUP(s) (((s) != NULL) ? g_strdup(s) : NULL) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h))) #define STRLEN(s) (((s) != NULL) ? strlen(s) : 0) #define STRISEMPTY(s) (((s) != NULL) ? (*(s) == '\0') : TRUE) static gchar *G_STRCAT(gchar *s, const gchar *s2) { if(s != NULL) { if(s2 != NULL) { gchar *sr = g_strconcat(s, s2, NULL); g_free(s); s = sr; } } else { if(s2 != NULL) s = STRDUP(s2); else s = STRDUP(""); } return(s); } /* * Returns a statically allocated string describing the specified * key. */ static gchar *GUIGetKeyName(guint key) { switch(key) { case GDK_BackSpace: return("BackSpace"); case GDK_Tab: return("Tab"); case GDK_Linefeed: return("LineFeed"); case GDK_Clear: return("Clear"); case GDK_Return: return("Return"); case GDK_Pause: return("Pause"); case GDK_Scroll_Lock: return("ScrollLock"); case GDK_Sys_Req: return("SysReq"); case GDK_Escape: return("Escape"); case GDK_space: return("Space"); case GDK_Delete: return("Delete"); case GDK_Home: return("Home"); case GDK_Left: return("Left"); case GDK_Right: return("Right"); case GDK_Down: return("Down"); case GDK_Up: return("Up"); case GDK_Page_Up: return("PageUp"); case GDK_Page_Down: return("PageDown"); case GDK_End: return("End"); case GDK_Begin: return("Begin"); case GDK_Select: return("Select"); case GDK_Print: return("Print"); case GDK_Execute: return("Execute"); case GDK_Insert: return("Insert"); case GDK_Undo: return("Undo"); case GDK_Redo: return("Redo"); case GDK_Menu: return("Menu"); case GDK_Find: return("Find"); case GDK_Cancel: return("Cancel"); case GDK_Help: return("Help"); case GDK_Break: return("Break"); case GDK_Num_Lock: return("NumLock"); case GDK_KP_Space: return("KPSpace"); case GDK_KP_Tab: return("KBTab"); case GDK_KP_Enter: return("KPEnter"); case GDK_KP_F1: return("KPF1"); case GDK_KP_F2: return("KPF2"); case GDK_KP_F3: return("KPF3"); case GDK_KP_F4: return("KPF4"); case GDK_KP_Home: return("KPHome"); case GDK_KP_Left: return("KPLeft"); case GDK_KP_Up: return("KPUp"); case GDK_KP_Right: return("KPRight"); case GDK_KP_Down: return("KPDown"); case GDK_KP_Page_Up: return("KPPageUp"); case GDK_KP_Page_Down: return("KPPageDown"); case GDK_KP_End: return("KPEnd"); case GDK_KP_Begin: return("KPBegin"); case GDK_KP_Insert: return("KPInsert"); case GDK_KP_Delete: return("KPDelete"); case GDK_KP_Equal: return("KPEqual"); case GDK_KP_Multiply: return("KPMultiply"); case GDK_KP_Add: return("KPAdd"); case GDK_KP_Separator: return("KPSeparator"); case GDK_KP_Subtract: return("KPSubtract"); case GDK_KP_Decimal: return("KPDecimal"); case GDK_KP_Divide: return("KPDivide"); case GDK_KP_0: return("KP0"); case GDK_KP_1: return("KP1"); case GDK_KP_2: return("KP2"); case GDK_KP_3: return("KP3"); case GDK_KP_4: return("KP4"); case GDK_KP_5: return("KP5"); case GDK_KP_6: return("KP6"); case GDK_KP_7: return("KP7"); case GDK_KP_8: return("KP8"); case GDK_KP_9: return("KP9"); case GDK_F1: return("F1"); case GDK_F2: return("F2"); case GDK_F3: return("F3"); case GDK_F4: return("F4"); case GDK_F5: return("F5"); case GDK_F6: return("F6"); case GDK_F7: return("F7"); case GDK_F8: return("F8"); case GDK_F9: return("F9"); case GDK_F10: return("F10"); case GDK_F11: return("F11"); case GDK_F12: return("F12"); case GDK_F13: return("F13"); case GDK_F14: return("F14"); case GDK_F15: return("F15"); case GDK_F16: return("F16"); case GDK_F17: return("F17"); case GDK_F18: return("F18"); case GDK_F19: return("F19"); case GDK_F20: return("F20"); case GDK_F21: return("F21"); case GDK_F22: return("F22"); case GDK_F23: return("F23"); case GDK_F24: return("F24"); case GDK_F25: return("F25"); case GDK_F26: return("F26"); case GDK_F27: return("F27"); case GDK_F28: return("F28"); case GDK_F29: return("F29"); case GDK_F30: return("F30"); case GDK_Shift_L: return("ShiftL"); case GDK_Shift_R: return("ShiftR"); case GDK_Control_L: return("ControlL"); case GDK_Control_R: return("ControlR"); case GDK_Caps_Lock: return("CapsLock"); case GDK_Shift_Lock: return("ShiftLock"); case GDK_Meta_L: return("MetaL"); case GDK_Meta_R: return("MetaR"); case GDK_Alt_L: return("AltL"); case GDK_Alt_R: return("AltR"); case GDK_Super_L: return("SuperL"); case GDK_Super_R: return("SuperR"); case GDK_Hyper_L: return("HyperL"); case GDK_Hyper_R: return("HyperR"); default: return(""); } } /* * Blocks input for the given GtkWindow if block is set to TRUE * or else allows input again if block is set to FALSE. */ void GUIBlockInput(GtkWidget *w, gboolean block) { GtkWidget *invis; if((w != NULL) ? !GTK_IS_WINDOW(w) : TRUE) return; /* Create the GtkInvisible blocker widget as needed */ invis = gui_invisible_blocker_widget; if(invis == NULL) { gui_invisible_blocker_widget = invis = gtk_invisible_new(); if(invis == NULL) return; } /* Block input? */ if(block) { /* Increase block input level and check if it is the first * blocking level */ gui_block_input_level++; if(gui_block_input_level == 1) { /* This is the first blocking level, so we need to map * the GtkInvisible and grab it so that input will be * blocked */ gtk_widget_show(invis); if(gtk_grab_get_current() != invis) gtk_grab_add(invis); } } else { /* Decrease block input level and check if it is the last * blocking level */ gui_block_input_level--; if(gui_block_input_level == 0) { if(gtk_grab_get_current() == invis) gtk_grab_remove(invis); gtk_widget_hide(invis); } /* Sanitize block input level underflows */ if(gui_block_input_level < 0) { gui_block_input_level = 0; g_printerr( "GUIBlockInput(): Block level underflow to level %i.\n", gui_block_input_level ); } } } /* * DDE Owner data "destroy" signal callback. */ static void GUIDDEOwnerDestroyCB(gpointer data) { GtkWidget *w; gui_dde_owner_struct *owner = GUI_DDE_OWNER(data); if(owner == NULL) return; w = owner->w; g_free(owner->data); owner->data = NULL; owner->length = 0; GTK_SIGNAL_DISCONNECT(w, owner->selection_clear_event_id) GTK_SIGNAL_DISCONNECT(w, owner->selection_get_id) g_free(owner); } /* * DDE GtkWidget "selection_clear_event" signal callback. */ static gboolean GUIDDESelectionClearEventCB( GtkWidget *widget, GdkEventSelection *event, gpointer data ) { gui_dde_owner_struct *owner = GUI_DDE_OWNER(data); if((widget == NULL) || (event == NULL) || (owner == NULL)) return(FALSE); /* Remove owner data and disconnect signals since this widget * is no longer responsible for sending out DDE data */ gtk_object_remove_data( GTK_OBJECT(widget), GUI_DDE_OWNER_DATA_KEY ); return(TRUE); } /* * DDE GtkWidget "selection_get" signal callback. */ static void GUIDDESelectionGetCB( GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint t, gpointer data ) { GdkAtom target; gui_dde_owner_struct *owner = GUI_DDE_OWNER(data); if((widget == NULL) || (selection_data == NULL) || (owner == NULL) ) return; /* Handle by owner's selection target type */ target = owner->target_atom; /* GdkBitmap */ if(target == GDK_TARGET_BITMAP) { /* TODO */ } /* GdkColormap */ else if(target == GDK_TARGET_COLORMAP) { /* TODO */ } /* GdkDrawable */ else if(target == GDK_TARGET_DRAWABLE) { /* TODO */ } /* GdkPixmap */ else if(target == GDK_TARGET_PIXMAP) { /* TODO */ } /* String (latin-1 characters) */ else if(target == GDK_TARGET_STRING) { gtk_selection_data_set( selection_data, owner->type_atom, 8, owner->data, owner->length ); } } /* * DDE GtkWidget "selection_received" signal callback. */ static void GUIDDESelectionReceivedCB( GtkWidget *widget, GtkSelectionData *selection_data, guint t, gpointer data ) { GdkAtom type; GtkSelectionData *sel_rtn = (GtkSelectionData *)data; if((widget == NULL) || (selection_data == NULL) || (sel_rtn == NULL) ) return; /* Already got data? */ if(sel_rtn->data != NULL) return; /* Mark that the selection was received on the callback data */ sel_rtn->length = 0; /* No data? */ if((selection_data->data == NULL) || (selection_data->length <= 0) ) return; /* Begin handling selection data by its type */ sel_rtn->type = type = selection_data->type; /* Atoms List */ if(type == GDK_SELECTION_TYPE_ATOM) { gchar *s = NULL; gint i, m = selection_data->length / sizeof(GdkAtom); gchar *name; GdkAtom *atoms = (GdkAtom *)selection_data->data; for(i = 0; i < m; i++) { name = gdk_atom_name(atoms[i]); if(name != NULL) { s = G_STRCAT(s, name); if(i < (m - 1)) s = G_STRCAT(s, " "); g_free(name); } } sel_rtn->data = s; sel_rtn->length = STRLEN(s); /* Change the return type to string */ sel_rtn->type = GDK_SELECTION_TYPE_STRING; } /* GdkBitmap */ else if(type == GDK_SELECTION_TYPE_BITMAP) { /* TODO */ } /* GdkColormap */ else if(type == GDK_SELECTION_TYPE_COLORMAP) { /* TODO */ } /* GdkDrawable */ else if(type == GDK_SELECTION_TYPE_DRAWABLE) { /* TODO */ } /* Integer */ else if(type == GDK_SELECTION_TYPE_INTEGER) { gint len = sel_rtn->length = selection_data->length; sel_rtn->data = g_malloc(len); memcpy(sel_rtn->data, selection_data->data, len); } /* GdkPixmap */ else if(type == GDK_SELECTION_TYPE_PIXMAP) { /* TODO */ } /* GdkWindow */ else if(type == GDK_SELECTION_TYPE_WINDOW) { /* TODO */ } /* String (latin-1 characters) */ else if(type == GDK_SELECTION_TYPE_STRING) { gint len = sel_rtn->length = selection_data->length; gchar *s = (gchar *)g_malloc(len + 1); memcpy(s, selection_data->data, len); s[len] = '\0'; sel_rtn->data = s; } } /* * DND drag begin callback, this function is called at the start * of a drag. * * The given data is always NULL for now. */ static void GUIDNDDragBeginCB( GtkWidget *widget, GdkDragContext *dc, gpointer data ) { gui_dnd_icon_struct *dnd_icon = &gui_dnd_icon; if((widget == NULL) || (dc == NULL)) return; /* Set the DND Icon if it is available */ if(dnd_icon->toplevel != NULL) gtk_drag_set_icon_widget( dc, dnd_icon->toplevel, dnd_icon->x, dnd_icon->y ); /* Stop the signal so that other callbacks do not override * what we have set here */ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "drag_begin" ); } /* * DND drag motion callback, this function will basically * handle the change of default action on the given destination * widget. * * The given data is assumed to be a gui_dnd_cb_struct *. */ static gboolean GUIDNDDragMotionCB( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t, gpointer data ) { gboolean same_widget; GtkWidget *src_widget, *tar_widget; GdkDragAction action; gui_dnd_cb_struct *cb_data = GUI_DND_CB(data); if((dc == NULL) || (cb_data == NULL)) return(FALSE); /* Get source widget and target widgets */ src_widget = gtk_drag_get_source_widget(dc); tar_widget = widget; /* Set marker for if the source and target widgets are the same */ same_widget = (src_widget == tar_widget) ? TRUE : FALSE; /* Get default action from cb_data structure, if source and * target are the same widget then use default_action_same * otherwise use default_action */ action = same_widget ? cb_data->default_action_same : cb_data->default_action; /* Respond with default drag action (status) * * First we check the dc's list of actions, if the list only * contains move or copy then we select just that, otherwise * we return with our default suggested action * * If no valid actions are listed then we respond with 0 */ /* Only move? */ if(dc->actions == GDK_ACTION_MOVE) gdk_drag_status(dc, GDK_ACTION_MOVE, t); /* Only copy? */ else if(dc->actions == GDK_ACTION_COPY) gdk_drag_status(dc, GDK_ACTION_COPY, t); /* Only link? */ else if(dc->actions == GDK_ACTION_LINK) gdk_drag_status(dc, GDK_ACTION_LINK, t); /* Other action, check if listed in our actions list? */ else if(dc->actions & action) gdk_drag_status(dc, action, t); /* All else respond with 0 */ else gdk_drag_status(dc, 0, t); /* Is target widget valid and sensitive? */ if((tar_widget != NULL) ? GTK_WIDGET_SENSITIVE(tar_widget) : FALSE) { /* Set target widget into focus as needed */ if(!GTK_WIDGET_HAS_FOCUS(tar_widget) && GTK_WIDGET_CAN_FOCUS(tar_widget) ) gtk_widget_grab_focus(tar_widget); /* Handle rest by the target widget's type */ /* Target widget is a GtkCTree? */ if(GTK_IS_CTREE(tar_widget)) { /* Reference it as a GtkCList */ GtkCList *clist = (GtkCList *)tar_widget; gint row, column; /* Update flags as needed */ clist->flags |= GTK_CLIST_DRAW_DRAG_LINE; clist->flags |= GTK_CLIST_DRAW_DRAG_RECT; /* Calculate column row from x and y coordinates */ if(!gtk_clist_get_selection_info( clist, x, y - ((clist->flags & GTK_CLIST_SHOW_TITLES) ? clist->column_title_area.height + clist->column_title_area.y : 0), &row, &column )) { row = -1; column = -1; } #if 0 i = 0; glist = clist->row_list; while(glist != NULL) { if(i == row) { row_ptr = (GtkCListRow *)glist->data; break; } i++; glist = g_list_next(glist); } if(row_ptr != NULL) gtk_signal_emit_by_name( GTK_OBJECT(tar_widget), "draw_drag_highlight", row_ptr, row, GTK_CLIST_DRAG_INTO ); #endif /* Change in drag position? */ if(row != clist->focus_row) { clist->focus_row = row; gtk_widget_queue_draw(tar_widget); } } /* Target widget is a GtkCList? */ else if(GTK_IS_CLIST(tar_widget)) { GtkCList *clist = (GtkCList *)tar_widget; gint row, column; /* Update flags as needed */ clist->flags |= GTK_CLIST_DRAW_DRAG_LINE; clist->flags |= GTK_CLIST_DRAW_DRAG_RECT; /* Calculate column row from x and y coordinates */ if(!gtk_clist_get_selection_info( clist, x, y - ((clist->flags & GTK_CLIST_SHOW_TITLES) ? clist->column_title_area.height + clist->column_title_area.y : 0), &row, &column )) { row = -1; column = -1; } /* Change in drag position? */ if(row != clist->focus_row) { clist->focus_row = row; gtk_widget_queue_draw(tar_widget); } } } return(FALSE); } /* * DND drag drop callback. * * The given data is assumed to be a gui_dnd_cb_struct *. */ static gboolean GUIDNDDragDropCB( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t, gpointer data ) { gui_dnd_cb_struct *cb_data = GUI_DND_CB(data); if((dc == NULL) || (cb_data == NULL)) return(FALSE); return(FALSE); } /* * DND drag data received callback. * * The given data is assumed to be a gui_dnd_cb_struct *. */ static void GUIDNDDragReceivedCB( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, gpointer data ) { gui_dnd_cb_struct *cb_data = GUI_DND_CB(data); if((dc == NULL) || (cb_data == NULL)) return; } /* * DND drag end callback, this function will reset the target * widget as needed and clean up any additional resources. * * The given data is always NULL for now. */ static void GUIDNDDragEndCB( GtkWidget *widget, GdkDragContext *dc, gpointer data ) { gboolean same_widget; GtkWidget *src_widget, *tar_widget; if(dc == NULL) return; /* Get source widget and target widgets */ src_widget = gtk_drag_get_source_widget(dc); tar_widget = widget; /* Set marker for if the source and target widgets are the same */ same_widget = (src_widget == tar_widget) ? TRUE : FALSE; /* Is target widget valid and sensitive? */ if((tar_widget != NULL) ? GTK_WIDGET_SENSITIVE(tar_widget) : FALSE) { /* Handle rest by the target widget's type */ /* Is target widget a ctree? */ if(GTK_IS_CTREE(tar_widget)) { GtkCList *clist = GTK_CLIST(tar_widget); clist->flags &= ~GTK_CLIST_DRAW_DRAG_LINE; clist->flags &= ~GTK_CLIST_DRAW_DRAG_RECT; gtk_widget_queue_draw(tar_widget); } /* Is target widget a clist? */ else if(GTK_IS_CLIST(tar_widget)) { GtkCList *clist = GTK_CLIST(tar_widget); clist->flags &= ~GTK_CLIST_DRAW_DRAG_LINE; clist->flags &= ~GTK_CLIST_DRAW_DRAG_RECT; gtk_widget_queue_draw(tar_widget); } } } /* * Button data destroy callback. */ static void GUIButtonDataDestroyCB(gpointer data) { gui_button_data_struct *btn_data = GUI_BUTTON_DATA(data); if(btn_data == NULL) return; g_free(btn_data->label_text); g_free(btn_data); } /* * Banner event signal callback. */ static gint GUIBannerEventCB( GtkWidget *widget, GdkEvent *event, gpointer data ) { gint status = FALSE; const gchar *label; GdkFont *font; GtkJustification justify; GdkEventConfigure *configure; GdkEventExpose *expose; gpointer *cb_data = (gpointer *)data; if((widget == NULL) || (event == NULL) || (cb_data == NULL)) return(status); label = (const gchar *)cb_data[0]; justify = (GtkJustification)cb_data[1]; font = (GdkFont *)cb_data[2]; switch((gint)event->type) { case GDK_CONFIGURE: configure = (GdkEventConfigure *)event; status = TRUE; break; case GDK_EXPOSE: expose = (GdkEventExpose *)event; GUIBannerDraw(widget); status = TRUE; break; } return(status); } /* * Banner data destroy callback. */ static void GUIBannerDataDestroyCB(gpointer data) { gchar *label; GtkJustification justify; GdkFont *font; gpointer *cb_data = (gpointer *)data; if(cb_data == NULL) return; label = (gchar *)cb_data[0]; justify = (GtkJustification)cb_data[1]; font = (GdkFont *)cb_data[2]; g_free(label); GDK_FONT_UNREF(font) g_free(cb_data); } /* * GtkCombo "activate" signal callback. * * First it will update the glist for the combo box and update * the the combo's list. Then call (if not NULL) the specified * activate callback function. */ static void GUIComboActivateCB(GtkWidget *widget, gpointer data) { gint max_items; GtkWidget *parent, *wlabel; GtkCombo *combo; GList *glist_in; gpointer client_data; void (*func_cb)(GtkWidget *, gpointer); void (*list_change_cb)(GtkWidget *, gpointer, GList *); gchar *new_value; gpointer *cb_data = (gpointer *)data; if((widget == NULL) || (cb_data == NULL)) return; /* Parse callback data, format is: * * table Parent table that holds combo and label * label Label (may be NULL) * combo This combo widget * GList Contains list of strings in combo list * max_items Max items allowed in combo list * client_data Calling function set callback data * func_cb Calling function set callback function * list_change_cb Calling function set list change function * NULL */ parent = (GtkWidget *)(cb_data[0]); wlabel = (GtkWidget *)(cb_data[1]); combo = (GtkCombo *)(cb_data[2]); glist_in = (GList *)(cb_data[3]); max_items = (gint)(cb_data[4]); client_data = (gpointer)(cb_data[5]); func_cb = cb_data[6]; list_change_cb = cb_data[7]; if(combo == NULL) return; /* Get new value string from combo's entry widget */ new_value = gtk_entry_get_text(GTK_ENTRY(combo->entry)); /* Make a duplicate of the recieved value or NULL if it is not * available */ new_value = STRDUP(new_value); if(new_value == NULL) return; /* Add the new value to the combo box list, this will only * be added if value is not already in the list. Excess items * may be truncated if adding this item would cause items to * exceed the set max items on the combo box * * List change callback will be called if the value was input * to the combo box's list */ GUIComboAddItem((gpointer)combo, new_value); /* Call activate function */ if(func_cb != NULL) func_cb( (GtkWidget *)combo, /* Combo */ client_data /* Data */ ); /* Free new_value which we duplicated */ g_free(new_value); } /* * GtkCombo "changed" signal callback. */ static void GUIComboChangedCB(GtkWidget *widget, gpointer data) { GList *glist; GtkCombo *combo; gpointer client_data; void (*list_change_cb)(GtkWidget *, gpointer, GList *); gpointer *cb_data = (gpointer *)data; if((widget == NULL) || (cb_data == NULL)) return; /* Parse callback data, format is: * * table Parent table that holds combo and label * label Label (may be NULL) * combo This combo widget * GList Contains list of strings in combo list * max_items Max items allowed in combo list * client_data Calling function set callback data * func_cb Calling function set callback function * list_change_cb Calling function set list change function * NULL */ combo = (GtkCombo *)(cb_data[2]); glist = (GList *)cb_data[3]; client_data = cb_data[5]; list_change_cb = cb_data[7]; /* Call list change function */ if(list_change_cb != NULL) list_change_cb( (GtkWidget *)combo, /* Combo */ client_data, /* Data */ glist /* List */ ); } /* * Combo data destroy callback. */ static void GUIComboDataDestroyCB(gpointer data) { GtkWidget *parent, *wlabel; GtkCombo *combo; GList *glist; gint max_items; gpointer client_data; void (*func_cb)(GtkWidget *, gpointer); void (*list_change_cb)(GtkWidget *, gpointer, GList *); gpointer *cb_data = (gpointer *)data; if(cb_data == NULL) return; /* Parse callback data, format is: * * table Parent table that holds combo and label * label Label (may be NULL) * combo This combo widget * GList Contains list of strings in combo list * max_items Max items allowed in combo list * client_data Calling function set callback data * func_cb Calling function set callback function * list_change_cb Calling function set list change function * NULL */ parent = (GtkWidget *)(cb_data[0]); wlabel = (GtkWidget *)(cb_data[1]); combo = (GtkCombo *)(cb_data[2]); glist = (GList *)(cb_data[3]); max_items = (gint)(cb_data[4]); client_data = (gpointer)(cb_data[5]); func_cb = cb_data[6]; list_change_cb = cb_data[7]; /* Do not call list change callback function on destroy */ /* Begin deallocating data referenced on callback data */ /* Delete list */ if(glist != NULL) { g_list_foreach(glist, (GFunc)g_free, NULL); g_list_free(glist); glist = NULL; } /* Delete callback data */ g_free(data); } /* * Local menu item activate callback, this function will * take the given data pointer as a dynamically allocated * (void **). */ static void GUIMenuActivateCB(gpointer data) { gint argc = 3; GtkWidget *functional_widget; gpointer client_data; void (*func_cb)(GtkWidget *, gpointer); gpointer *cb_data = (gpointer *)data; if(cb_data == NULL) return; /* Data Format: * * w Functional Widget * client_data Data * func_cb Callback Function * NULL */ functional_widget = (GtkWidget *)((argc > 0) ? cb_data[0] : NULL); client_data = ((argc > 1) ? cb_data[1] : NULL); func_cb = ((argc > 2) ? cb_data[2] : NULL); if(func_cb != NULL) func_cb( functional_widget, /* Functional Widget */ client_data /* Data */ ); } /* * Menu item client data destroy callback. */ static void GUIMenuClientDataDestroyCB(gpointer data) { gpointer *mi_client_data = (gpointer *)data; g_free(mi_client_data); } /* * Menu item data destroy callback. */ static void GUIMenuDataDestroyCB(gpointer data) { gui_menu_item_data_struct *mi = GUI_MENU_ITEM_DATA(data); if(mi == NULL) return; g_free(mi->label_text); g_free(mi->accel_text); g_free(mi); } /* * Pullout data destroy callback. */ static void GUIPullOutDataDestroyCB(gpointer data) { GtkWidget *client_hbox, *holder_hbox, *toplevel; gpointer *cb_data = (gpointer *)data; if(cb_data != NULL) { /* Format is as follows (12 arguments): * * client_hbox * holder_hbox * holder_window * holder_window_x * holder_window_y * holder_window_width * holder_window_height * in_place (1 if true) * pull_out_client_data * pull_out_cb * push_in_client_data * push_in_cb */ client_hbox = (GtkWidget *)cb_data[0]; holder_hbox = (GtkWidget *)cb_data[1]; toplevel = (GtkWidget *)cb_data[2]; /* Destroy the toplevel window */ if(toplevel != NULL) { GTK_WIDGET_DESTROY(toplevel) cb_data[2] = toplevel = NULL; } } g_free(cb_data); } /* * Pull out draw handle for signal "draw". */ static void GUIPullOutDrawHandleDrawCB( GtkWidget *widget, GdkRectangle *area, gpointer data ) { GdkWindow *window; GtkStyle *style; if(gui_style_default == NULL) gui_style_default = gtk_widget_get_default_style(); if((widget != NULL) ? GTK_WIDGET_NO_WINDOW(widget) : TRUE) return; window = widget->window; if(window == NULL) return; style = gtk_widget_get_style(widget); if(style == NULL) style = gui_style_default; if(style == NULL) return; gdk_window_clear(window); #ifndef HAVE_WIN32 gtk_draw_handle( style, window, GTK_STATE_NORMAL, /* State type */ GTK_SHADOW_OUT, /* Shadow type */ 0, 0, widget->allocation.width, widget->allocation.height, GTK_ORIENTATION_HORIZONTAL ); #endif } /* * Pull out draw handle callback for signal "expose_event". * * This redraws the handle graphics on the given widget. */ static gint GUIPullOutDrawHandleCB( GtkWidget *widget, GdkEvent *event, gpointer data ) { if((widget != NULL) ? GTK_WIDGET_NO_WINDOW(widget) : TRUE) return(TRUE); gtk_widget_queue_draw(widget); return(TRUE); } /* * Pull out button callback. */ static gint GUIPullOutPullOutBtnCB( GtkWidget *widget, GdkEvent *event, gpointer data ) { GtkWidget *client_hbox, *holder_hbox, *toplevel; gpointer *cb_data = (gpointer *)data; gint holder_window_width, holder_window_height; gpointer pull_out_client_data; void (*pull_out_cb)(gpointer, gpointer); if(cb_data != NULL) { /* Format is as follows (12 arguments): * * client_hbox * holder_hbox * holder_window * holder_window_x * holder_window_y * holder_window_width * holder_window_height * in_place (1 if true). * pull_out_client_data * pull_out_cb * push_in_client_data * push_in_cb */ client_hbox = (GtkWidget *)cb_data[0]; holder_hbox = (GtkWidget *)cb_data[1]; toplevel = (GtkWidget *)cb_data[2]; holder_window_width = (gint)cb_data[5]; holder_window_height = (gint)cb_data[6]; pull_out_client_data = cb_data[8]; pull_out_cb = cb_data[9]; /* Create toplevel window as needed */ if(toplevel == NULL) { GtkWidget *w; toplevel = w = gtk_window_new(GTK_WINDOW_TOPLEVEL); cb_data[2] = (gpointer)w; gtk_widget_realize(w); gtk_widget_set_usize( w, (holder_window_width <= 0) ? -1 : holder_window_width, (holder_window_height <= 0) ? -1 : holder_window_height ); gtk_window_set_policy( GTK_WINDOW(w), TRUE, TRUE, FALSE ); gtk_signal_connect( GTK_OBJECT(w), "delete_event", GTK_SIGNAL_FUNC(GUIPullOutCloseCB), (gpointer)cb_data ); } /* Reparent client_hbox to toplevel window */ if((client_hbox != NULL) && (toplevel != NULL)) { gtk_widget_show(toplevel); if((GTK_WIDGET_FLAGS(client_hbox) & GTK_NO_REPARENT)) g_printerr("Cannot reparent.\n"); else gtk_widget_reparent(client_hbox, toplevel); } /* Hide holder hbox */ if(holder_hbox != NULL) gtk_widget_hide(holder_hbox); /* Mark in callback data that its been `pulled out' */ cb_data[7] = (gpointer)0; /* Call pull out callback? */ if(pull_out_cb != NULL) pull_out_cb(client_hbox, pull_out_client_data); } return(TRUE); } /* * Close (push in) callback. */ static gint GUIPullOutCloseCB(GtkWidget *widget, GdkEvent *event, gpointer data) { GtkWidget *client_hbox, *holder_hbox, *toplevel; gpointer *cb_data = (gpointer *)data; gpointer push_in_client_data; void (*push_in_cb)(gpointer, gpointer); if(cb_data != NULL) { /* Format is as follows (12 arguments): * * client_hbox * holder_hbox * holder_window * holder_window_x * holder_window_y * holder_window_width * holder_window_height * in_place (1 if true). * pull_out_client_data * pull_out_cb * push_in_client_data * push_in_cb */ client_hbox = (GtkWidget *)cb_data[0]; holder_hbox = (GtkWidget *)cb_data[1]; toplevel = (GtkWidget *)cb_data[2]; push_in_client_data = cb_data[10]; push_in_cb = cb_data[11]; /* Reparent client_hbox to holder_hbox */ if((client_hbox != NULL) && (holder_hbox != NULL)) { gtk_widget_show(holder_hbox); if((GTK_WIDGET_FLAGS(client_hbox) & GTK_NO_REPARENT)) g_printerr("Cannot reparent.\n"); else gtk_widget_reparent(client_hbox, holder_hbox); } /* Hide toplevel */ if(toplevel != NULL) gtk_widget_hide(toplevel); /* Mark in callback data that its been `pushed in' */ cb_data[7] = (gpointer)1; /* Call push in callback? */ if(push_in_cb != NULL) push_in_cb(client_hbox, push_in_client_data); } return(TRUE); } /* * Creates a new GtkRcStyle based on the given GtkRcStyle. */ GtkRcStyle *GUIRCStyleCopy(const GtkRcStyle *rcstyle) { #if (GTK_MAJOR_VERSION >= 2) return((rcstyle != NULL) ? gtk_rc_style_copy(rcstyle) : NULL); #else gint i; const GtkRcStyle *src_style = rcstyle; GtkRcStyle *tar_style; if(src_style == NULL) return(NULL); tar_style = gtk_rc_style_new(); tar_style->name = STRDUP(src_style->name); tar_style->font_name = STRDUP(src_style->font_name); tar_style->fontset_name = STRDUP(src_style->fontset_name); for(i = 0; i < 5; i++) { tar_style->bg_pixmap_name[i] = STRDUP(src_style->bg_pixmap_name[i]); tar_style->color_flags[i] = src_style->color_flags[i]; memcpy(&tar_style->fg[i], &src_style->fg[i], sizeof(GdkColor)); memcpy(&tar_style->bg[i], &src_style->bg[i], sizeof(GdkColor)); memcpy(&tar_style->text[i], &src_style->text[i], sizeof(GdkColor)); memcpy(&tar_style->base[i], &src_style->base[i], sizeof(GdkColor)); } tar_style->engine = src_style->engine; tar_style->engine_data = src_style->engine_data; #endif return(tar_style); } /* * Sets the widget's rc style and all of its child widgets. */ void GUIRCStyleSetRecursive(GtkWidget *w, GtkRcStyle *rcstyle) { if((w == NULL) || (rcstyle == NULL)) return; gtk_widget_modify_style(w, rcstyle); if(GTK_IS_CONTAINER(w)) gtk_container_forall( GTK_CONTAINER(w), (GtkCallback)GUIRCStyleSetRecursive, rcstyle ); } /* * Parses the geometry string s. * * Returns a set of GdkGeometryFlags flags. */ GdkGeometryFlags GUIParseGeometry( const gchar *s, gint *x, gint *y, gint *width, gint *height ) { GdkGeometryFlags status = 0x00000000; if(x != NULL) *x = 0; if(y != NULL) *y = 0; if(width != NULL) *width = 0; if(height != NULL) *height = 0; if(s == NULL) return(status); /* Seek past initial spaces and '=' deliminator (if any) */ while(ISBLANK(*s)) s++; while(*s == '=') s++; while(ISBLANK(*s)) s++; /* String at width and height arguments? */ if((*s != '+') && (*s != '-')) { /* Parse width value */ if((width != NULL) && (*s != '\0')) { *width = ATOI(s); status |= GDK_GEOMETRY_WIDTH; } /* Begin seeking to next argument */ if(*s != '\0') s++; while((toupper(*s) != 'X') && (*s != '\0')) s++; while((toupper(*s) == 'X') || ISBLANK(*s)) s++; /* Parse height value */ if((height != NULL) && (*s != '\0')) { *height = ATOI(s); status |= GDK_GEOMETRY_HEIGHT; } /* Begin seeking to next argument (probably an offset * value) */ if(*s != '\0') s++; while((*s != '+') && (*s != '-') && (*s != '\0')) s++; } /* String seeked to the offsets arguments? */ if((*s == '+') || (*s == '-')) { /* Seek past '+' character as needed and get x offset * value */ if(*s == '+') s++; if((x != NULL) && (*s != '\0')) { *x = ATOI(s); status |= GDK_GEOMETRY_X; } /* Begin seeking to next argument */ if(*s != '\0') s++; while((*s != '+') && (*s != '-') && (*s != '\0')) s++; /* Seek past '+' character as needed and get y offset * value */ if(*s == '+') s++; if((y != NULL) && (*s != '\0')) { *y = ATOI(s); status |= GDK_GEOMETRY_Y; } } return(status); } /* * Gets the geometry of the given GtkCList cell specified by column * and row. * * Returns TRUE if the cell geometry was obtained or FALSE on * failed match or error. */ gboolean GUICListGetCellGeometry( GtkCList *clist, gint column, gint row, gint *x, gint *y, gint *width, gint *height ) { gint i, cx, cy, cwidth, cheight; GList *glist; const GtkAdjustment *hadj, *vadj; const GtkCListRow *row_ptr; const GtkCListColumn *column_ptr; if(x != NULL) *x = 0; if(y != NULL) *y = 0; if(width != NULL) *width = 0; if(height != NULL) *height = 0; if(clist == NULL) return(FALSE); hadj = clist->hadjustment; vadj = clist->vadjustment; /* Given row and column in bounds? */ if((column < 0) || (column >= clist->columns)) return(FALSE); if((row < 0) || (row >= clist->rows)) return(FALSE); /* Get cy and cheight */ cy = 0; cheight = 0; glist = clist->row_list; for(i = 0; glist != NULL; i++) { row_ptr = (const GtkCListRow *)glist->data; if(row_ptr != NULL) { const GtkCellText *cell_text_ptr; const GtkCellPixmap *cell_pixmap_ptr; const GtkCellPixText *cell_pixtext_ptr; const GtkCellWidget *cell_widget_ptr; const GtkCell *cell_ptr = row_ptr->cell; cheight = clist->row_height; if(cell_ptr != NULL) { switch(cell_ptr->type) { case GTK_CELL_TEXT: cell_text_ptr = (GtkCellText *)cell_ptr; cheight = MAX(cell_text_ptr->vertical, cheight); break; case GTK_CELL_PIXMAP: cell_pixmap_ptr = (GtkCellPixmap *)cell_ptr; cheight = MAX(cell_pixmap_ptr->vertical, cheight); break; case GTK_CELL_PIXTEXT: cell_pixtext_ptr = (GtkCellPixText *)cell_ptr; cheight = MAX(cell_pixtext_ptr->vertical, cheight); break; case GTK_CELL_WIDGET: cell_widget_ptr = (GtkCellWidget *)cell_ptr; cheight = MAX(cell_widget_ptr->vertical, cheight); break; case GTK_CELL_EMPTY: cheight = 0; break; } } cheight += 1; /* Need to add 1 pixel for cell borders */ if(i == row) break; cy += cheight; } glist = g_list_next(glist); } /* Get cx and cwidth */ cx = 0; cwidth = 0; if(clist->column != NULL) { for(i = 0; i < clist->columns; i++) { column_ptr = &clist->column[i]; if(column_ptr == NULL) continue; /* Get width of this column plus margins */ cwidth = column_ptr->width + 7; if(i == column) break; cx += cwidth; } } /* Offset cx and cy with scroll adjustments */ if(hadj != NULL) cx = cx - (gint)(hadj->value - hadj->lower); if(vadj != NULL) cy = cy - (gint)(vadj->value - vadj->lower); /* Update returns */ if(x != NULL) *x = cx; if(y != NULL) *y = cy; if(width != NULL) *width = cwidth; if(height != NULL) *height = cheight; return(TRUE); } /* * Returns the row index of the specified node. */ gint GUICTreeNodeRow(GtkCTree *ctree, GtkCTreeNode *node) { gint row; GList *glist; GtkCList *clist; GtkCTreeRow *row_ptr; if((ctree == NULL) || (node == NULL)) return(-1); clist = GTK_CLIST(ctree); row_ptr = GTK_CTREE_ROW(node); if(row_ptr == NULL) return(FALSE); /* Count rows until we encounter the specified node's row */ for(glist = clist->row_list, row = 0; glist != NULL; glist = g_list_next(glist), row++ ) { if(row_ptr == (GtkCTreeRow *)glist->data) break; } return((glist != NULL) ? row : -1); } /* * Used by GUICTreeNodeDeltaRows(). */ static void GUICTreeNodeDeltaRowsIterate( GtkCTree *ctree, GtkCTreeNode *node, GtkCTreeNode *end, gint *row_count, gboolean *end_found ) { GtkCTreeRow *row_ptr; while((node != NULL) && !(*end_found)) { /* Found end node? */ if(node == end) { *end_found = TRUE; break; } /* Count this node */ *row_count = *row_count + 1; row_ptr = GTK_CTREE_ROW(node); if(row_ptr == NULL) break; /* Count child nodes only if expanded */ if(row_ptr->expanded && !row_ptr->is_leaf) { GUICTreeNodeDeltaRowsIterate( ctree, row_ptr->children, end, row_count, end_found ); if(*end_found) break; } /* Get next sibling */ node = row_ptr->sibling; } } /* * Returns the number of rows between the GtkCTree nodes. */ gint GUICTreeNodeDeltaRows( GtkCTree *ctree, GtkCTreeNode *start, /* Use NULL for first/toplevel node */ GtkCTreeNode *end ) { gboolean end_found = FALSE; gint row_count = 0; if((ctree == NULL) || (end == NULL)) return(row_count); if(start == NULL) start = gtk_ctree_node_nth(ctree, 0); GUICTreeNodeDeltaRowsIterate( ctree, start, end, &row_count, &end_found ); return(row_count); } /* * Returns the coordinate position for the specified GdkWindow * relative to the root GdkWindow. */ void GUIGetWindowRootPosition( GdkWindow *window, gint *x, gint *y ) { gint cx, cy; GdkWindow *cur_w = window, *root_w; if(x != NULL) *x = 0; if(y != NULL) *y = 0; if(cur_w == NULL) return; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); root_w = gui_window_root; if(root_w == NULL) return; while(cur_w != root_w) { gdk_window_get_position(cur_w, &cx, &cy); if(x != NULL) *x += cx; if(y != NULL) *y += cy; cur_w = gdk_window_get_parent(cur_w); } } /* * Converts the coordinates x and y (relative to the window w) * be relative to the root window. */ void GUIGetPositionRoot( GdkWindow *w, gint x, gint y, gint *rx, gint *ry ) { GdkWindow *cur = w, *root_w; gint cx, cy; if(rx != NULL) *rx = 0; if(ry != NULL) *ry = 0; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); root_w = gui_window_root; if((cur == NULL) || (root_w == NULL)) return; while((cur != root_w) && (cur != NULL)) { gdk_window_get_position(cur, &cx, &cy); x += cx; y += cy; cur = gdk_window_get_parent(cur); } if(rx != NULL) *rx = x; if(ry != NULL) *ry = y; } /* * Gets the text bounds. */ void GUIGetTextBounds( GdkFont *font, const gchar *text, gint text_length, GdkTextBounds *bounds ) { if((font == NULL) || (text == NULL) || (bounds == NULL)) { if(bounds != NULL) memset(bounds, 0x00, sizeof(GdkTextBounds)); return; } gdk_text_extents( font, text, text_length, &bounds->lbearing, &bounds->rbearing, &bounds->width, &bounds->ascent, &bounds->descent ); } /* * Gets the string bounds. */ void GUIGetStringBounds( GdkFont *font, const gchar *string, GdkTextBounds *bounds ) { GUIGetTextBounds(font, string, STRLEN(string), bounds); } /* * Creates a new GC */ GdkGC *GDK_GC_NEW(void) { if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); return(gdk_gc_new(gui_window_root)); } /* * Gets the GdkWindow's reference count. */ gint GUIWindowGetRefCount(GdkWindow *window) { #if defined(WIN32) return((window != NULL) ? 1 : 0); #else return((window != NULL) ? ((GdkWindowPrivate *)window)->ref_count : 0 ); #endif } /* * Sets the WM icon for the GdkWindow w based on the specified XPM * data. */ void GUISetWMIcon(GdkWindow *window, guint8 **data) { GdkBitmap *mask; GdkPixmap *pixmap; if((window == NULL) || (data == NULL)) return; /* Load icon pixmap and mask */ pixmap = GDK_PIXMAP_NEW_FROM_XPM_DATA(&mask, data); if(pixmap != NULL) { /* Set WM icon * * Note that gdk_window_set_icon() will take care of * unref'ing the pixmap and mask */ gdk_window_set_icon(window, NULL, pixmap, mask); } } /* * Sets the WM icon for the GdkWindow w based on the specified XPM * file. */ void GUISetWMIconFile(GdkWindow *window, const gchar *filename) { GdkBitmap *mask; GdkPixmap *pixmap; if((window == NULL) || STRISEMPTY(filename)) return; /* Load icon pixmap and mask */ pixmap = GDK_PIXMAP_NEW_FROM_XPM_FILE(&mask, filename); if(pixmap != NULL) { /* Set WM icon * * Note that gdk_window_set_icon() will take care of * unref'ing the pixmap and mask */ gdk_window_set_icon(window, NULL, pixmap, mask); } } /* * Applies the command line arguments to the GtkWindow. * * Command line arguments that will be applied are as follows: * * --title Set WM title bar title * --class <class> Set WM class * --icon <filename> Set WM icon * --icon-name <name> Set WM icon's name * --font-name <font> Set font * --font * -fn * --foreground-color <color> Set foreground color * -fg * --background-color <color> Set background color * -bg * --text-color <color> Set text color * --base-color <color> Set base color * --background-pixmap <filename> Set background pixmap * --bg-pixmap * --sforeground-color <color> Set selected foreground color * -sfg * --sbackground-color <color> Set selected background color * -sbg * --stext-color <color> Set selected text color * --sbase-color <color> Set selected base color * --sbackground-pixmap <filename> Set selected background pixmap * --sbg-pixmap * --geometry <geometry> Set geometry * --iconic Startup iconified * */ void GUIWindowApplyArgs(GtkWindow *w, gint argc, gchar **argv) { gint i; gboolean arg_on; const gchar *arg, *argp; gchar *title = NULL, *wmclass = NULL, *icon = NULL, *icon_name = NULL; GdkGeometryFlags geometry_flags = 0x00000000; GdkRectangle *geometry = NULL; gboolean iconic = FALSE; GtkRcStyle *rcstyle = NULL; GdkWindow *window; #define NEW_RCSTYLE_AS_NEEDED { \ if(rcstyle == NULL) \ rcstyle = gtk_rc_style_new(); \ } if((w == NULL) || (argc <= 0) || (argv == NULL)) return; if(!GTK_IS_WINDOW(GTK_WIDGET(w)) || GTK_WIDGET_NO_WINDOW(GTK_WIDGET(w)) ) return; window = GTK_WIDGET(w)->window; if(window == NULL) return; /* Iterate through arguments and gather values to be applied to * the GtkWindow */ for(i = 0; i < argc; i++) { arg = argv[i]; if(STRISEMPTY(arg)) continue; /* If the argument does not start with a '-' character then * we can skip the checking of the argument for convience */ if((*arg != '-') && (*arg != '+')) continue; /* If arg is prefixed with a '+' character then set arg_on * to TRUE so that toggle arguments can know to enable or * disable */ arg_on = (*arg == '+') ? TRUE : FALSE; /* Get argp to seek past the '-' characters in arg */ argp = arg; while((*argp == '-') || (*argp == '+')) argp++; #define PRINT_REQUIRES_ARG(_a_) { \ g_printerr( \ "%s: Requires argument.\n", \ (_a_) \ ); \ } /* Handle by argument */ /* Title */ if(!g_strcasecmp(argp, "title")) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { g_free(title); title = STRDUP(arg); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Class */ else if(!g_strcasecmp(argp, "class")) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { g_free(wmclass); wmclass = STRDUP(arg); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Icon */ else if(!g_strcasecmp(argp, "icon")) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { g_free(icon); icon = STRDUP(arg); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Icon Name */ else if(!g_strcasecmp(argp, "icon-name")) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { g_free(icon_name); icon_name = STRDUP(arg); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Font */ else if(!g_strcasecmp(argp, "font-name") || !g_strcasecmp(argp, "font") || !g_strcasecmp(argp, "fn") ) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { NEW_RCSTYLE_AS_NEEDED g_free(rcstyle->font_name); rcstyle->font_name = STRDUP(arg); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Foreground Color */ else if(!g_strcasecmp(argp, "foreground-color") || !g_strcasecmp(argp, "foreground") || !g_strcasecmp(argp, "fg") ) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GdkColor *c; GtkStateType state = GTK_STATE_NORMAL; NEW_RCSTYLE_AS_NEEDED rcstyle->color_flags[state] |= GTK_RC_FG; c = &rcstyle->fg[state]; gdk_color_parse(arg, c); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Background Color */ else if(!g_strcasecmp(argp, "background-color") || !g_strcasecmp(argp, "background") || !g_strcasecmp(argp, "bg") ) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GdkColor *c; GtkStateType state = GTK_STATE_NORMAL; NEW_RCSTYLE_AS_NEEDED rcstyle->color_flags[state] |= GTK_RC_BG; c = &rcstyle->bg[state]; gdk_color_parse(arg, c); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Text Color */ else if(!g_strcasecmp(argp, "text-color")) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GdkColor *c; GtkStateType state = GTK_STATE_NORMAL; NEW_RCSTYLE_AS_NEEDED rcstyle->color_flags[state] |= GTK_RC_TEXT; c = &rcstyle->text[state]; gdk_color_parse(arg, c); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Base Color */ else if(!g_strcasecmp(argp, "base-color")) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GdkColor *c; GtkStateType state = GTK_STATE_NORMAL; NEW_RCSTYLE_AS_NEEDED rcstyle->color_flags[state] |= GTK_RC_BASE; c = &rcstyle->base[state]; gdk_color_parse(arg, c); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Background Pixmap */ else if(!g_strcasecmp(argp, "background-pixmap") || !g_strcasecmp(argp, "bg-pixmap") ) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GtkStateType state = GTK_STATE_NORMAL; NEW_RCSTYLE_AS_NEEDED g_free(rcstyle->bg_pixmap_name[state]); rcstyle->bg_pixmap_name[state] = STRDUP(arg); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Selected Foreground Color */ else if(!g_strcasecmp(argp, "sforeground-color") || !g_strcasecmp(argp, "sforeground") || !g_strcasecmp(argp, "sfg") ) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GdkColor *c; GtkStateType state = GTK_STATE_SELECTED; NEW_RCSTYLE_AS_NEEDED rcstyle->color_flags[state] |= GTK_RC_FG; c = &rcstyle->fg[state]; gdk_color_parse(arg, c); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Selected Background Color */ else if(!g_strcasecmp(argp, "sbackground-color") || !g_strcasecmp(argp, "sbackground") || !g_strcasecmp(argp, "sbg") ) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GdkColor *c; GtkStateType state = GTK_STATE_SELECTED; NEW_RCSTYLE_AS_NEEDED rcstyle->color_flags[state] |= GTK_RC_BG; c = &rcstyle->bg[state]; gdk_color_parse(arg, c); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Selected Text Color */ else if(!g_strcasecmp(argp, "stext-color")) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GdkColor *c; GtkStateType state = GTK_STATE_SELECTED; NEW_RCSTYLE_AS_NEEDED rcstyle->color_flags[state] |= GTK_RC_TEXT; c = &rcstyle->text[state]; gdk_color_parse(arg, c); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Selected Base Color */ else if(!g_strcasecmp(argp, "sbase-color")) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GdkColor *c; GtkStateType state = GTK_STATE_SELECTED; NEW_RCSTYLE_AS_NEEDED rcstyle->color_flags[state] |= GTK_RC_BASE; c = &rcstyle->base[state]; gdk_color_parse(arg, c); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Selected Background Pixmap */ else if(!g_strcasecmp(argp, "sbackground-pixmap") || !g_strcasecmp(argp, "sbg-pixmap") ) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { GtkStateType state = GTK_STATE_SELECTED; NEW_RCSTYLE_AS_NEEDED g_free(rcstyle->bg_pixmap_name[state]); rcstyle->bg_pixmap_name[state] = STRDUP(arg); } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Geometry */ else if(!g_strcasecmp(argp, "geometry")) { i++; arg = (i < argc) ? argv[i] : NULL; if(arg != NULL) { gint x, y, width, height; GdkGeometryFlags flags = gdk_parse_geometry( arg, &x, &y, &width, &height ); geometry_flags = flags; if(flags) { GdkRectangle *rect = geometry; if(rect == NULL) geometry = rect = (GdkRectangle *)g_malloc0( sizeof(GdkRectangle) ); rect->x = (flags & GDK_GEOMETRY_X) ? x : 0; rect->y = (flags & GDK_GEOMETRY_Y) ? y : 0; rect->width = (flags & GDK_GEOMETRY_WIDTH) ? width : 0; rect->height = (flags & GDK_GEOMETRY_HEIGHT) ? height : 0; } } else { PRINT_REQUIRES_ARG(argv[i - 1]) } } /* Iconic */ else if(!g_strcasecmp(argp, "iconic")) { iconic = TRUE; } #undef PRINT_REQUIRES_ARG } /* Begin applying values */ /* Set title? */ if(title != NULL) { gtk_window_set_title(w, title); } /* Set class? */ if(wmclass != NULL) { #if 0 TODO: Should not set this after GtkWindow has been realized gtk_window_set_wmclass(w, wmclass, wmclass); #endif } /* Set icon? */ if(icon != NULL) { GUISetWMIconFile(window, icon); } /* Set icon name? */ if(icon_name != NULL) { gdk_window_set_icon_name(window, icon_name); } /* Set geometry? */ if(geometry_flags && (geometry != NULL)) { GdkGeometryFlags flags = geometry_flags; GdkRectangle *rect = geometry; if((flags & GDK_GEOMETRY_X) || (flags & GDK_GEOMETRY_Y)) gtk_widget_set_uposition( GTK_WIDGET(w), rect->x, rect->y ); if((flags & GDK_GEOMETRY_WIDTH) || (flags & GDK_GEOMETRY_HEIGHT)) gtk_widget_set_usize( GTK_WIDGET(w), (flags & GDK_GEOMETRY_WIDTH) ? rect->width : -1, (flags & GDK_GEOMETRY_HEIGHT) ? rect->height : -1 ); } /* Iconic? */ if(iconic) { /* TODO */ } /* Set rc style? */ if(rcstyle != NULL) { gtk_widget_modify_style_recursive( GTK_WIDGET(w), rcstyle ); } g_free(title); g_free(wmclass); g_free(icon); g_free(icon_name); GTK_RC_STYLE_UNREF(rcstyle); g_free(geometry); #undef NEW_RCSTYLE_AS_NEEDED } /* * Sets the GtkCTree's position to optimize the viewing of all * child nodes of the given node. * * Returns TRUE if the position has changed. */ gboolean GUICTreeOptimizeExpandPosition( GtkCTree *ctree, GtkCTreeNode *node /* Expanded parent node */ ) { gboolean need_scroll = FALSE; gint row_height, rows_visible, child_rows; GtkCList *clist; GtkCTreeRow *row_ptr; GtkCTreeNode *cur_node, *last_child_node, *scroll_end_node = NULL; if((ctree == NULL) || (node == NULL)) return(FALSE); /* Get clist information */ clist = GTK_CLIST(ctree); if(clist->columns <= 0) return(FALSE); if(GTK_CLIST_ROW_HEIGHT_SET(clist)) row_height = clist->row_height + 1; /* Assume uniform spaced * rows and include border */ else row_height = 20; if(row_height <= 0) return(FALSE); rows_visible = clist->clist_window_height / row_height; if(rows_visible <= 0) return(FALSE); /* Get first child of expanded node */ last_child_node = NULL; child_rows = 1; /* Include parent */ row_ptr = GTK_CTREE_ROW(node); cur_node = (row_ptr != NULL) ? row_ptr->children : NULL; while(cur_node != NULL) { last_child_node = cur_node; child_rows++; if(child_rows > rows_visible) { need_scroll = TRUE; break; } row_ptr = GTK_CTREE_ROW(cur_node); cur_node = (row_ptr != NULL) ? row_ptr->sibling : NULL; } /* Check if last child node is visible */ if(!need_scroll && (last_child_node != NULL)) { const gint rows = GUICTreeNodeDeltaRows( ctree, NULL, node) + child_rows, y = (rows * row_height) - (gint)GTK_ADJUSTMENT_GET_VALUE(clist->vadjustment); if(y > clist->clist_window_height) { need_scroll = TRUE; scroll_end_node = gtk_ctree_node_nth(ctree, rows - 1); } } /* Need to scroll? */ if(need_scroll) { if(scroll_end_node != NULL) gtk_ctree_node_moveto( ctree, scroll_end_node, -1, 1.0f, 0.0f /* Row align, column align */ ); else gtk_ctree_node_moveto( ctree, node, -1, 0.0f, 0.0f /* Row align, column align */ ); return(TRUE); } else { return(FALSE); } } /* * Creates a bitmap from the given RGBA data * * Only the alpha byte will be used to create the bitmap. * * An alpha byte value greater than or equal to the value * specified by threshold will set a 1 bit in the bitmap and a * value less will set a 0 bit. * * If bytes per line bpl is -1, then it will be automatically * calculated. */ GdkBitmap *GUICreateBitmapFromDataRGBA( gint width, gint height, gint bpl, const guint8 *rgba, guint8 threshold, GdkWindow *window ) { const gint bpp = 4; gint xbm_bpl; guint8 *xbm_data; const guint8 *src_ptr; gint x, y; GdkBitmap *bitmap; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); if(window == NULL) window = gui_window_root; if((rgba == NULL) || (width <= 0) || (height <= 0)) return(NULL); /* Calculate bytes per line, the number of bytes to be able to * hold one whole line of bits */ xbm_bpl = (width / 8) + ((width % 8) ? 1 : 0); if(bpl < 0) bpl = width * bpp; if(bpl <= 0) return(NULL); /* Allocate bitmap */ xbm_data = (guint8 *)g_malloc0( xbm_bpl * height * sizeof(guint8) ); if(xbm_data == NULL) return(NULL); /* Begin converting the RGBA data to the bitmap data */ for(y = 0; y < height; y++) { for(x = 0; x < width; x++) { src_ptr = &rgba[ (y * bpl) + (x * bpp) ]; /* Alpha value greater or equal to threshold? */ if(src_ptr[3] >= threshold) xbm_data[ (y * xbm_bpl) + (x / 8) ] |= (guint8)(1 << (x % 8)); } } /* Create bitmap */ bitmap = gdk_bitmap_create_from_data( window, xbm_data, width, height ); g_free(xbm_data); /* No longer needed */ return(bitmap); } /* * Creates a new GdkPixmap of the specified size and current * depth. */ GdkPixmap *GDK_PIXMAP_NEW(gint width, gint height) { if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); if((width <= 0) || (height <= 0)) return(NULL); return(gdk_pixmap_new(gui_window_root, width, height, -1)); } /* * Creates a new GdkPixmap from the specified XPM data. */ GdkPixmap *GDK_PIXMAP_NEW_FROM_XPM_DATA( GdkBitmap **mask_rtn, guint8 **data ) { GdkPixmap *pixmap; GdkBitmap *mask; GdkWindow *window; GtkStyle *style; if(mask_rtn != NULL) *mask_rtn = NULL; if(data == NULL) return(NULL); if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); if(gui_style_default == NULL) gui_style_default = gtk_widget_get_default_style(); window = gui_window_root; style = gui_style_default; /* Create a new pixmap from data */ pixmap = gdk_pixmap_create_from_xpm_d( window, &mask, (style != NULL) ? &style->bg[GTK_STATE_NORMAL] : NULL, (gchar **)data ); if(pixmap == NULL) return(NULL); if(mask_rtn != NULL) *mask_rtn = mask; else GDK_BITMAP_UNREF(mask); return(pixmap); } /* * Creates a new GdkPixmap from the specified XPM file. */ GdkPixmap *GDK_PIXMAP_NEW_FROM_XPM_FILE( GdkBitmap **mask_rtn, const gchar *filename ) { GdkPixmap *pixmap; GdkBitmap *mask; GdkWindow *window; GtkStyle *style; if(mask_rtn != NULL) *mask_rtn = NULL; if(STRISEMPTY(filename)) return(NULL); if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); if(gui_style_default == NULL) gui_style_default = gtk_widget_get_default_style(); window = gui_window_root; style = gui_style_default; /* Create a new pixmap from file */ pixmap = gdk_pixmap_create_from_xpm( window, &mask, (style != NULL) ? &style->bg[GTK_STATE_NORMAL] : NULL, filename ); if(pixmap == NULL) return(NULL); if(mask_rtn != NULL) *mask_rtn = mask; else GDK_BITMAP_UNREF(mask); return(pixmap); } /* * Creates a new GtkPixmap from the given XPM data. */ GtkWidget *gtk_pixmap_new_from_xpm_d( GdkWindow *window, GdkColor *transparent_color, guint8 **data ) { GdkPixmap *pixmap; GdkBitmap *mask; GtkWidget *w; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); if(gui_style_default == NULL) gui_style_default = gtk_widget_get_default_style(); if(window == NULL) window = gui_window_root; if(transparent_color == NULL) { GtkStyle *style = gui_style_default; if(style != NULL) transparent_color = &style->bg[GTK_STATE_NORMAL]; } /* Load pixmap and mask */ pixmap = gdk_pixmap_create_from_xpm_d( window, &mask, transparent_color, (gchar **)data ); if(pixmap != NULL) { /* Create new GtkPixmap from the loaded pixmap and mask */ w = gtk_pixmap_new(pixmap, mask); } else { w = NULL; } /* Unref pixmap and mask pair, they are no longer needed */ GDK_PIXMAP_UNREF(pixmap); GDK_BITMAP_UNREF(mask); return(w); } /* * Creates a new GtkPixmap from the given XPM data. */ GtkWidget *GUICreateMenuItemIcon(guint8 **icon_data) { gint width = 0, height = 0; GdkWindow *window; GdkPixmap *pixmap = NULL; GdkBitmap *mask = NULL; GtkStyle *style; GtkWidget *w = NULL; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); if(gui_style_default == NULL) gui_style_default = gtk_widget_get_default_style(); window = gui_window_root; style = gui_style_default; /* If no icon data specified, then use default empty icon */ if(icon_data == NULL) { gchar *bitmap_data; /* Set width and height of blank icon */ width = GUI_MENU_ITEM_DEF_HEIGHT; height = width; /* Allocate tempory bitmap data and create the GdkBitmap mask */ bitmap_data = (gchar *)g_malloc0( (((width / 8) + 1) * height) * sizeof(gchar) ); if(bitmap_data != NULL) mask = gdk_bitmap_create_from_data( window, bitmap_data, width, height ); else mask = NULL; /* Delete tempory bitmap data, it is no longer needed */ g_free(bitmap_data); /* Create blank GdkPixmap */ pixmap = gdk_pixmap_new( window, width, height, -1 ); /* Pixmap created successfully? */ if(pixmap != NULL) { /* Create a GtkPixmap based on new pixmap and mask pair */ w = gtk_pixmap_new(pixmap, mask); } } else { /* Create pixmap and mask pair from given data */ pixmap = gdk_pixmap_create_from_xpm_d( window, &mask, (style != NULL) ? &style->bg[GTK_STATE_NORMAL] : NULL, (gchar **)icon_data ); /* Pixmap created successfully? */ if(pixmap != NULL) { /* Create a GtkPixmap based on new pixmap and mask pair */ w = gtk_pixmap_new(pixmap, mask); /* Get size of newly loaded pixmap */ gdk_window_get_size((GdkWindow *)pixmap, &width, &height); } } /* Unref pixmap and mask pair, they are no longer needed */ GDK_PIXMAP_UNREF(pixmap); GDK_BITMAP_UNREF(mask); return(w); } /* * Maps the GtkWidget. * * If the GtkWidget is a GtkWindow then it will be raised. */ void GUIWidgetMapRaise(GtkWidget *w) { if(w == NULL) return; gtk_widget_show(w); if(GTK_IS_WINDOW(w)) gdk_window_raise(w->window); } /* * Minimizes (iconifies) the GtkWindow. */ void GUIWindowMinimize(GtkWindow *window) { #ifdef _XLIB_H_ Display *dpy; Window xwin; GdkWindow *win; gint scr_num; if(window == NULL) return; if(!GTK_WIDGET_REALIZED(GTK_WIDGET(window))) return; win = GTK_WIDGET(window)->window; if(win == NULL) return; dpy = GDK_WINDOW_XDISPLAY(win); xwin = GDK_WINDOW_XWINDOW(win); if((dpy == NULL) || (xwin == None)) return; scr_num = DefaultScreen(dpy); XIconifyWindow(dpy, xwin, scr_num); #endif /* _XLIB_H_ */ } /* * Creates the global gui_tooltips widget for controlling the * enabled/disabled state of all tooltips set by these functions. * * When the global gui_tooltips widget is first created, the * tooltips will be enabled and gui_tooltips_state will be reset * to TRUE. */ static void GUICreateGlobalTooltips(void) { /* Need to create global gui_tooltips widget? */ if(gui_tooltips == NULL) { GtkWidget *w = (GtkWidget *)gtk_tooltips_new(); gui_tooltips = (GtkTooltips *)w; if(w != NULL) { gtk_tooltips_enable(GTK_TOOLTIPS(w)); gui_tooltips_state = TRUE; } } } /* * Sets the tip for the given widget w, if the widget w already * has a tip set then it will be changed to the new value. * * If tip is NULL then no tip will be set on the given widget. */ void GUISetWidgetTip(GtkWidget *w, const gchar *tip) { if(w == NULL) return; /* Create global tooltips as needed */ GUICreateGlobalTooltips(); if(gui_tooltips == NULL) return; if(tip != NULL) { gtk_tooltips_set_tip( gui_tooltips, /* Our tooltips group */ w, tip, NULL ); } else { gtk_tooltips_set_tip( gui_tooltips, /* Our tooltips group */ w, NULL, NULL ); } } /* * Makes the tooltip associated with the given widget shown * immediatly if the widget has a tip defined. Also requires * that the global gui_tooltips_state be TRUE, otherwise * this function does nothing. */ void GUIShowTipsNow(GtkWidget *w) { GdkEventCrossing e; GdkWindow *window; if((w == NULL) || !gui_tooltips_state) return; if(GTK_WIDGET_NO_WINDOW(w)) return; else window = w->window; if(window == NULL) return; /* Send a fake enter notify event to make widget think * its time to show the tooltips. Note that the widget * should be watching for the enter_notify_event. */ e.type = GDK_ENTER_NOTIFY; e.window = window; e.send_event = 1; /* True if we're sending event */ e.subwindow = window; e.time = GDK_CURRENT_TIME; e.x = 0.0; e.y = 0.0; e.x_root = 0.0; e.y_root = 0.0; e.mode = GDK_CROSSING_NORMAL; e.detail = GDK_NOTIFY_ANCESTOR; e.focus = TRUE; /* Focus */ e.state = 0; /* Key modifiers */ gdk_event_put((GdkEvent *)&e); } /* * Enables/disables global tooltips state. */ void GUISetGlobalTipsState(gboolean state) { /* Create global tooltips as needed */ GUICreateGlobalTooltips(); if(gui_tooltips == NULL) return; if(state) gtk_tooltips_enable(gui_tooltips); else gtk_tooltips_disable(gui_tooltips); /* Update global tool tips state */ gui_tooltips_state = (state) ? TRUE : FALSE; } /* * Changes the button layout. * * The button must be one created by GUIButtonPixmap*() * or GUIToggleButtonPixmap*(). */ void GUIButtonChangeLayout( GtkWidget *w, gboolean show_pixmap, gboolean show_label) { gui_button_data_struct *btn_data = GUI_BUTTON_DATA( GTK_OBJECT_GET_DATA(w, GUI_BUTTON_DATA_KEY) ); if(btn_data == NULL) return; w = btn_data->label; if(w != NULL) { if(show_label) gtk_widget_show(w); else gtk_widget_hide(w); } w = btn_data->pixmap; if(w != NULL) { if(show_pixmap) gtk_widget_show(w); else gtk_widget_hide(w); } w = btn_data->arrow; if(w != NULL) { if(show_pixmap) gtk_widget_show(w); else gtk_widget_hide(w); } } /* * Underlines the specified character in the button's label. */ void GUIButtonLabelUnderline(GtkWidget *w, guint c) { gui_button_data_struct *btn_data = GUI_BUTTON_DATA( GTK_OBJECT_GET_DATA(w, GUI_BUTTON_DATA_KEY) ); if(btn_data == NULL) return; if((btn_data->label != NULL) && (btn_data->label_text != NULL)) { GtkWidget *w = btn_data->label; const gchar *text = btn_data->label_text; gchar *s, *pattern = STRDUP(text); gint i = (gint)toupper((gint)c); for(s = pattern; *s != '\0'; s++) { if((gint)toupper((gint)*s) == i) { *s = '_'; i = '\0'; } else { *s = ' '; } } gtk_label_set_pattern(GTK_LABEL(w), pattern); g_free(pattern); } } /* * Changes the button's icon and/or label. * * If any value is NULL then it will not be modified. * * The button must be one returned from GUIButtonPixmap*() * or GUIToggleButtonPixmap*(). */ void GUIButtonPixmapUpdate( GtkWidget *w, guint8 **icon, const gchar *label ) { GtkWidget *parent; gui_button_data_struct *btn_data = GUI_BUTTON_DATA( GTK_OBJECT_GET_DATA(w, GUI_BUTTON_DATA_KEY) ); if(btn_data == NULL) return; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); parent = btn_data->main_box; if(parent == NULL) return; /* Update icon? */ if((icon != NULL) && ((const guint8 **)icon != btn_data->icon_data) ) { GtkStyle *style = gtk_widget_get_style(btn_data->button); GdkWindow *window = gui_window_root; if((style != NULL) && (window != NULL)) { GdkBitmap *mask; GdkPixmap *pixmap = gdk_pixmap_create_from_xpm_d( window, &mask, &style->bg[GTK_STATE_NORMAL], (gchar **)icon ); if(pixmap != NULL) { gint width, height; gdk_window_get_size(pixmap, &width, &height); /* Record icon data pointer */ btn_data->icon_data = (const guint8 **)icon; /* Set new icon pixmap */ w = btn_data->pixmap; if(w != NULL) { gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask); } else { btn_data->pixmap = w = gtk_pixmap_new(pixmap, mask); gtk_box_pack_start(GTK_BOX(parent), w, TRUE, FALSE, 0); gtk_widget_show(w); } if(w != NULL) { gtk_widget_set_usize( w, width + (2 * 0), height + (2 * 0) ); } /* Unref the loaded pixmap and mask pair, they are * no longer needed */ GDK_PIXMAP_UNREF(pixmap); GDK_BITMAP_UNREF(mask); } } } /* Update label text? */ if(label != NULL) { w = btn_data->label; if(w != NULL) { /* Change in label text? */ if((btn_data->label_text != NULL) ? strcmp(btn_data->label_text, label) : TRUE ) { /* Set new label text */ g_free(btn_data->label_text); btn_data->label_text = STRDUP(label); gtk_label_set_text(GTK_LABEL(w), btn_data->label_text); } } } } /* * Changes the button's arrow and/or label. */ void GUIButtonArrowUpdate( GtkWidget *w, GtkArrowType arrow_type, gint arrow_width, gint arrow_height, const gchar *label ) { GtkWidget *parent; gui_button_data_struct *btn_data = GUI_BUTTON_DATA( GTK_OBJECT_GET_DATA(w, GUI_BUTTON_DATA_KEY) ); if(btn_data == NULL) return; parent = btn_data->main_box; if(parent == NULL) return; /* Update arrow? */ if(arrow_type >= 0) { w = btn_data->arrow; if(w != NULL) { if(btn_data->arrow_type != arrow_type) { btn_data->arrow_type = arrow_type; gtk_arrow_set( GTK_ARROW(w), btn_data->arrow_type, GTK_SHADOW_OUT ); } gtk_widget_set_usize(w, arrow_width, arrow_height); } } /* Update label text? */ if(label != NULL) { w = btn_data->label; if(w != NULL) { /* Change in label text? */ if((btn_data->label_text != NULL) ? strcmp(btn_data->label_text, label) : TRUE ) { /* Set new label text */ g_free(btn_data->label_text); btn_data->label_text = STRDUP(label); gtk_label_set_text(GTK_LABEL(w), btn_data->label_text); } } } } /* * Gets the button's main GtkBox. */ GtkWidget *GUIButtonGetMainBox(GtkWidget *w) { gui_button_data_struct *btn_data = GUI_BUTTON_DATA( GTK_OBJECT_GET_DATA(w, GUI_BUTTON_DATA_KEY) ); return((btn_data != NULL) ? btn_data->main_box : NULL); } /* * Gets the button's GtkLabel. */ GtkWidget *GUIButtonGetLabel(GtkWidget *w) { gui_button_data_struct *btn_data = GUI_BUTTON_DATA( GTK_OBJECT_GET_DATA(w, GUI_BUTTON_DATA_KEY) ); return((btn_data != NULL) ? btn_data->label : NULL); } /* * Gets the button's GtkPixmap. */ GtkWidget *GUIButtonGetPixmap(GtkWidget *w) { gui_button_data_struct *btn_data = GUI_BUTTON_DATA( GTK_OBJECT_GET_DATA(w, GUI_BUTTON_DATA_KEY) ); return((btn_data != NULL) ? btn_data->pixmap : NULL); } /* * Gets the button's GtkArrow. */ GtkWidget *GUIButtonGetArrow(GtkWidget *w) { gui_button_data_struct *btn_data = GUI_BUTTON_DATA( GTK_OBJECT_GET_DATA(w, GUI_BUTTON_DATA_KEY) ); return((btn_data != NULL) ? btn_data->arrow : NULL); } /* * Gets the button's label text. */ gchar *GUIButtonGetLabelText(GtkWidget *w) { gui_button_data_struct *btn_data = GUI_BUTTON_DATA( GTK_OBJECT_GET_DATA(w, GUI_BUTTON_DATA_KEY) ); return((btn_data != NULL) ? btn_data->label_text : NULL); } /* * GtkButton creation nexus. */ static GtkWidget *GUIButtonPixmapLabelHV( guint8 **icon, const gchar *label, GtkWidget **label_rtn, gboolean horizontal ) { const gint border = (label != NULL) ? 1 : 0; GtkWidget *w, *parent; gui_button_data_struct *btn_data; if(label_rtn != NULL) *label_rtn = NULL; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); /* Create callback data */ btn_data = GUI_BUTTON_DATA( g_malloc0(sizeof(gui_button_data_struct)) ); /* Create button */ btn_data->button = w = gtk_button_new(); gtk_object_set_data_full( GTK_OBJECT(w), GUI_BUTTON_DATA_KEY, btn_data, GUIButtonDataDestroyCB ); parent = w; /* Create main box */ if(horizontal) w = gtk_hbox_new(FALSE, 0); else w = gtk_vbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(w), 0); gtk_container_add(GTK_CONTAINER(parent), w); gtk_widget_show(w); btn_data->main_box = parent = w; /* Create icon? */ if(icon != NULL) { GdkWindow *window = gui_window_root; GtkStyle *style = gtk_widget_get_style(btn_data->button); if(style != NULL) { GdkBitmap *mask; GdkPixmap *pixmap = gdk_pixmap_create_from_xpm_d( window, &mask, &style->bg[GTK_STATE_NORMAL], (gchar **)icon ); if(pixmap != NULL) { gint width, height; gdk_window_get_size(pixmap, &width, &height); btn_data->icon_data = (const guint8 **)icon; btn_data->pixmap = w = gtk_pixmap_new(pixmap, mask); gtk_widget_set_usize( w, width + (2 * 0), height + (2 * 0) ); gtk_box_pack_start( GTK_BOX(parent), w, TRUE, FALSE, border ); gtk_widget_show(w); GDK_PIXMAP_UNREF(pixmap); GDK_BITMAP_UNREF(mask); } } } /* Create label? */ if(label != NULL) { btn_data->label_text = STRDUP(label); btn_data->label = w = gtk_label_new(btn_data->label_text); if(label_rtn != NULL) *label_rtn = w; gtk_label_set_justify( GTK_LABEL(w), horizontal ? GTK_JUSTIFY_LEFT : GTK_JUSTIFY_CENTER ); gtk_box_pack_start( GTK_BOX(parent), w, TRUE, FALSE, border ); gtk_widget_show(w); } return(btn_data->button); } /* * Creates a horizonal GtkButton with the specified icon and * label. */ GtkWidget *GUIButtonPixmapLabelH( guint8 **icon, const gchar *label, GtkWidget **label_rtn ) { return(GUIButtonPixmapLabelHV(icon, label, label_rtn, 1)); } /* * Creates a vertical GtkButton with the specified icon and * label. */ GtkWidget *GUIButtonPixmapLabelV( guint8 **icon, const gchar *label, GtkWidget **label_rtn ) { return(GUIButtonPixmapLabelHV(icon, label, label_rtn, 0)); } /* * Creates a GtkButton with the specified icon. */ GtkWidget *GUIButtonPixmap(guint8 **icon) { return( GUIButtonPixmapLabelH(icon, NULL, NULL) ); } /* * GtkButton with Arrow creation nexus. */ static GtkWidget *GUIButtonArrowLabelHV( GtkArrowType arrow_type, gint arrow_width, gint arrow_height, const gchar *label, GtkWidget **label_rtn, gboolean horizontal ) { const gint border = (label != NULL) ? 1 : 0; GtkWidget *w, *parent; gui_button_data_struct *btn_data; if(label_rtn != NULL) *label_rtn = NULL; /* Create callback data */ btn_data = GUI_BUTTON_DATA( g_malloc0(sizeof(gui_button_data_struct)) ); /* Create button */ btn_data->button = w = gtk_button_new(); gtk_object_set_data_full( GTK_OBJECT(w), GUI_BUTTON_DATA_KEY, btn_data, GUIButtonDataDestroyCB ); parent = w; /* Create main box */ if(horizontal) w = gtk_hbox_new(FALSE, 0); else w = gtk_vbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(w), 0); gtk_container_add(GTK_CONTAINER(parent), w); gtk_widget_show(w); btn_data->main_box = parent = w; /* Create arrow */ btn_data->arrow_type = arrow_type; btn_data->arrow = w = gtk_arrow_new( btn_data->arrow_type, GTK_SHADOW_OUT ); gtk_widget_set_usize( w, (arrow_width > 0) ? arrow_width : 20, (arrow_height > 0) ? arrow_height : 20 ); gtk_box_pack_start( GTK_BOX(parent), w, TRUE, FALSE, border ); gtk_widget_show(w); /* Create label? */ if(label != NULL) { btn_data->label_text = STRDUP(label); btn_data->label = w = gtk_label_new(btn_data->label_text); if(label_rtn != NULL) *label_rtn = w; gtk_label_set_justify( GTK_LABEL(w), horizontal ? GTK_JUSTIFY_LEFT : GTK_JUSTIFY_CENTER ); gtk_box_pack_start( GTK_BOX(parent), w, TRUE, FALSE, border ); gtk_widget_show(w); } return(btn_data->button); } /* * Creates a horizontal GtkButton with the specified arrow and * label. */ GtkWidget *GUIButtonArrowLabelH( GtkArrowType arrow_type, gint arrow_width, gint arrow_height, const gchar *label, GtkWidget **label_rtn ) { return(GUIButtonArrowLabelHV( arrow_type, arrow_width, arrow_height, label, label_rtn, TRUE )); } /* * Creates a vertical GtkButton with the specified arrow and * label. */ GtkWidget *GUIButtonArrowLabelV( GtkArrowType arrow_type, gint arrow_width, gint arrow_height, const gchar *label, GtkWidget **label_rtn ) { return(GUIButtonArrowLabelHV( arrow_type, arrow_width, arrow_height, label, label_rtn, FALSE )); } /* * Creates a GtkButton with the specified arrow. */ GtkWidget *GUIButtonArrow( GtkArrowType arrow_type, gint arrow_width, gint arrow_height ) { return(GUIButtonArrowLabelHV( arrow_type, arrow_width, arrow_height, NULL, NULL, FALSE )); } /* * GtkToggleButton creation nexus. */ GtkWidget *GUIToggleButtonPixmapLabelHV( guint8 **icon, const gchar *label, GtkWidget **label_rtn, gboolean horizontal ) { const gint border = (label != NULL) ? 1 : 0; GtkWidget *w, *parent; gui_button_data_struct *btn_data; if(label_rtn != NULL) *label_rtn = NULL; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); /* Create callback data */ btn_data = GUI_BUTTON_DATA( g_malloc0(sizeof(gui_button_data_struct)) ); /* Create button */ btn_data->button = w = gtk_toggle_button_new(); gtk_object_set_data_full( GTK_OBJECT(w), GUI_BUTTON_DATA_KEY, btn_data, GUIButtonDataDestroyCB ); parent = w; /* Create main box */ if(horizontal) w = gtk_hbox_new(FALSE, 0); else w = gtk_vbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(w), 0); gtk_container_add(GTK_CONTAINER(parent), w); gtk_widget_show(w); btn_data->main_box = parent = w; /* Create icon? */ if(icon != NULL) { GdkWindow *window = gui_window_root; GtkStyle *style = gtk_widget_get_style(btn_data->button); if(style != NULL) { GdkBitmap *mask; GdkPixmap *pixmap = gdk_pixmap_create_from_xpm_d( window, &mask, &style->bg[GTK_STATE_NORMAL], (gchar **)icon ); if(pixmap != NULL) { gint width, height; gdk_window_get_size(pixmap, &width, &height); btn_data->icon_data = (const guint8 **)icon; btn_data->pixmap = w = gtk_pixmap_new(pixmap, mask); gtk_widget_set_usize( w, width + (2 * 0), height + (2 * 0) ); gtk_box_pack_start( GTK_BOX(parent), w, TRUE, FALSE, border ); gtk_widget_show(w); GDK_PIXMAP_UNREF(pixmap); GDK_BITMAP_UNREF(mask); } } } /* Create label? */ if(label != NULL) { btn_data->label_text = STRDUP(label); btn_data->label = w = gtk_label_new(btn_data->label_text); if(label_rtn != NULL) *label_rtn = w; gtk_label_set_justify( GTK_LABEL(w), horizontal ? GTK_JUSTIFY_LEFT : GTK_JUSTIFY_CENTER ); gtk_box_pack_start( GTK_BOX(parent), w, TRUE, FALSE, border ); gtk_widget_show(w); } return(btn_data->button); } /* * Creates a horizonal GtkToggleButton with the specified icon and * label. */ GtkWidget *GUIToggleButtonPixmapLabelH( guint8 **icon, const gchar *label, GtkWidget **label_rtn ) { return(GUIToggleButtonPixmapLabelHV(icon, label, label_rtn, 1)); } /* * Creates a vertical GtkToggleButton with the specified icon and * label. */ GtkWidget *GUIToggleButtonPixmapLabelV( guint8 **icon, const gchar *label, GtkWidget **label_rtn ) { return(GUIToggleButtonPixmapLabelHV(icon, label, label_rtn, 0)); } /* * Creates a GtkToggleButton with the specified icon. */ GtkWidget *GUIToggleButtonPixmap(guint8 **icon) { return(GUIToggleButtonPixmapLabelHV(icon, NULL, NULL, 0)); } /* * Prompt creation nexus */ static GtkWidget *GUIPromptBarOrBrowse( guint8 **icon, const gchar *label, gpointer *label_rtn, gpointer *entry_rtn, gpointer *browse_rtn ) { const gint border_minor = 2; gint attach_x, attach_y; GtkWidget *parent, *w; /* Reset returns */ if(label_rtn != NULL) *label_rtn = NULL; if(entry_rtn != NULL) *entry_rtn = NULL; if(browse_rtn != NULL) *browse_rtn = NULL; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); /* Create prompt bar parent */ parent = w = gtk_table_new( 1, ((icon != NULL) ? 1 : 0) + ((label != NULL) ? 1 : 0) + 1 + ((browse_rtn != NULL) ? 1 : 0), FALSE ); gtk_table_set_col_spacings(GTK_TABLE(w), border_minor); attach_x = 0; attach_y = 0; /* Create icon */ if(icon != NULL) { GdkWindow *window = gui_window_root; GtkStyle *style = gtk_widget_get_style(parent); GdkBitmap *mask; GdkPixmap *pixmap = gdk_pixmap_create_from_xpm_d( window, &mask, (style != NULL) ? &style->bg[GTK_STATE_NORMAL] : NULL, (gchar **)icon ); if(pixmap != NULL) { gint width, height; gdk_window_get_size(pixmap, &width, &height); attach_x = 0; w = gtk_pixmap_new(pixmap, mask); gtk_widget_set_usize(w, width, height); gtk_table_attach( GTK_TABLE(parent), w, (guint)attach_x, (guint)(attach_x + 1), (guint)attach_y, (guint)(attach_y + 1), 0, 0, 0, 0 ); gtk_widget_show(w); GDK_PIXMAP_UNREF(pixmap); GDK_BITMAP_UNREF(mask); } } /* Create label? */ if(label != NULL) { attach_x = (icon != NULL) ? 1 : 0; w = gtk_label_new(label); if(label_rtn != NULL) *label_rtn = w; gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_RIGHT); gtk_table_attach( GTK_TABLE(parent), w, (guint)attach_x, (guint)(attach_x + 1), (guint)attach_y, (guint)(attach_y + 1), 0, 0, 0, 0 ); gtk_widget_show(w); } /* Create text entry? */ if(TRUE) { attach_x = ((icon != NULL) ? 1 : 0) + ((label != NULL) ? 1 : 0); w = gtk_entry_new(); if(entry_rtn != NULL) *entry_rtn = w; gtk_table_attach( GTK_TABLE(parent), w, (guint)attach_x, (guint)(attach_x + 1), (guint)attach_y, (guint)(attach_y + 1), GTK_SHRINK | GTK_EXPAND | GTK_FILL, 0, 0, 0 ); gtk_widget_show(w); } /* Create browse button? */ if(browse_rtn != NULL) { attach_x = ((icon != NULL) ? 1 : 0) + ((label != NULL) ? 1 : 0) + 1; w = GUIButtonPixmap( (guint8 **)icon_browse_20x20_xpm ); *browse_rtn = w; gtk_table_attach( GTK_TABLE(parent), w, (guint)attach_x, (guint)(attach_x + 1), (guint)attach_y, (guint)(attach_y + 1), 0, 0, 0, 0 ); gtk_widget_show(w); } return(parent); } /* * Creates a new prompt with an icon, label, entry, and browse * button. */ GtkWidget *GUIPromptBarWithBrowse( guint8 **icon, const gchar *label, gpointer *label_rtn, gpointer *entry_rtn, gpointer *browse_rtn, gpointer browse_data, void (*browse_cb)(GtkWidget *, gpointer) ) { GtkWidget *parent; parent = GUIPromptBarOrBrowse( icon, label, label_rtn, entry_rtn, browse_rtn ); /* Set signal callback for the browse button */ if((browse_rtn != NULL) && (browse_cb != NULL)) { GtkWidget *w = (GtkWidget *)*browse_rtn; if(w != NULL) gtk_signal_connect( GTK_OBJECT(w), "clicked", GTK_SIGNAL_FUNC(browse_cb), browse_data ); } return(parent); } /* * Creates a new prompt with an icon, label, and entry. */ GtkWidget *GUIPromptBar( guint8 **icon, const gchar *label, gpointer *label_rtn, gpointer *entry_rtn ) { return(GUIPromptBarOrBrowse( icon, label, label_rtn, entry_rtn, NULL )); } /* * Sets the DDE as binary data. */ void GUIDDESetBinary( GtkWidget *w, /* Owner widget */ GdkAtom selection_atom, /* Can be GDK_NONE */ gulong t, /* Time */ const guint8 *data, gint length ) { static GdkAtom target_atom = GDK_NONE; guint8 *datau8; gui_dde_owner_struct *owner; if(target_atom == GDK_NONE) target_atom = gdk_atom_intern("STRING", FALSE); if(selection_atom == GDK_NONE) selection_atom = GDK_SELECTION_PRIMARY; if((w == NULL) || (data == NULL) || (length <= 0)) return; if(GTK_WIDGET_NO_WINDOW(w)) { g_printerr( "GUIDDESetBinary(): Failed:\ GtkWidget 0x%.8x does not have a GdkWindow.\n", (guint32)w ); return; } /* Allocate callback data */ owner = GUI_DDE_OWNER(g_malloc0(sizeof(gui_dde_owner_struct))); owner->w = w; owner->target_atom = target_atom; owner->type_atom = target_atom; owner->selection_clear_event_id = gtk_signal_connect( GTK_OBJECT(w), "selection_clear_event", GTK_SIGNAL_FUNC(GUIDDESelectionClearEventCB), owner ); owner->selection_get_id = gtk_signal_connect( GTK_OBJECT(w), "selection_get", GTK_SIGNAL_FUNC(GUIDDESelectionGetCB), owner ); datau8 = (guint8 *)g_malloc((length + 1) * sizeof(guint8)); memcpy(datau8, data, length * sizeof(guint8)); datau8[length] = '\0'; owner->data = datau8; owner->length = length; /* Set owner callback data on the widget, destroying any * previously set owner callback data on the widget */ gtk_object_set_data_full( GTK_OBJECT(w), GUI_DDE_OWNER_DATA_KEY, owner, GUIDDEOwnerDestroyCB ); /* Set the widget as supporting the selection of the * specified type */ gtk_selection_add_target( w, /* Widget */ selection_atom, /* Selection */ target_atom, /* Target */ 0 /* Info */ ); /* Set selection owner */ if(!gtk_selection_owner_set( w, /* Owner GtkWidget */ selection_atom, /* Selection */ (guint32)t /* Time */ )) { /* Failed to set selection owner */ gtk_object_remove_data( GTK_OBJECT(w), GUI_DDE_OWNER_DATA_KEY ); return; } } /* * Gets the DDE as binary data. */ guint8 *GUIDDEGetBinary( GtkWidget *w, /* Widget making request */ GdkAtom selection_atom, /* Can be GDK_NONE */ gulong t, /* Time */ gint *length ) { guint8 *data; gint len; guint sig_id; GdkAtom type; GtkSelectionData *selection_data; static GdkAtom target_atom = GDK_NONE; if(target_atom == GDK_NONE) target_atom = gdk_atom_intern("STRING", FALSE); if(length != NULL) *length = 0; if(selection_atom == GDK_NONE) selection_atom = GDK_SELECTION_PRIMARY; if(w == NULL) return(NULL); if(GTK_WIDGET_NO_WINDOW(w)) { g_printerr( "GUIDDEGetBinary(): Failed:\ GtkWidget 0x%.8x does not have a GdkWindow.\n", (guint32)w ); return(NULL); } /* Set up callback data */ selection_data = (GtkSelectionData *)g_malloc0( sizeof(GtkSelectionData) ); selection_data->selection = selection_atom; selection_data->target = target_atom; selection_data->type = GDK_NONE; selection_data->format = -1; selection_data->data = NULL; selection_data->length = -1; /* -1 means data not received */ /* Set up widget to receive the "selection_received" signal */ sig_id = gtk_signal_connect( GTK_OBJECT(w), "selection_received", GTK_SIGNAL_FUNC(GUIDDESelectionReceivedCB), selection_data ); /* Request selection */ if(!gtk_selection_convert( w, /* Widget */ selection_atom, /* Selection */ target_atom, /* Target */ (guint32)t /* Time */ )) { /* Selection request failed */ GTK_SIGNAL_DISCONNECT(GTK_OBJECT(w), sig_id) g_free(selection_data->data); g_free(selection_data); return(NULL); } /* Wait for selection */ while(selection_data->length < 0) { while(gtk_events_pending() > 0) gtk_main_iteration(); } /* Got selection */ /* Disconnect signals */ GTK_SIGNAL_DISCONNECT(GTK_OBJECT(w), sig_id); /* Get data from selection from callback data */ type = selection_data->type; /* Integer */ if(type == GDK_SELECTION_TYPE_INTEGER) { data = (guint8 *)selection_data->data; selection_data->data = NULL; len = selection_data->length; } /* String (latin-1 characters) */ else if(type == GDK_SELECTION_TYPE_STRING) { data = (guint8 *)selection_data->data; selection_data->data = NULL; len = selection_data->length; } else { data = NULL; len = 0; } /* Delete callback data */ g_free(selection_data->data); g_free(selection_data); if(length != NULL) *length = len; return(data); } /* * Sets the DDE as a string. */ void GUIDDESetString( GtkWidget *w, /* Owner widget */ GdkAtom selection_atom, /* Selection */ gulong t, /* Time */ const gchar *data ) { static GdkAtom target_atom = GDK_NONE; gui_dde_owner_struct *owner; if(target_atom == GDK_NONE) target_atom = gdk_atom_intern("STRING", FALSE); if(selection_atom == GDK_NONE) selection_atom = GDK_SELECTION_PRIMARY; if((w == NULL) || (data == NULL)) return; if(GTK_WIDGET_NO_WINDOW(w)) { g_printerr( "GUIDDESetString(): Failed:\ GtkWidget 0x%.8x does not have a GdkWindow.\n", (guint32)w ); return; } /* Allocate callback data */ owner = GUI_DDE_OWNER(g_malloc0(sizeof(gui_dde_owner_struct))); owner->w = w; owner->target_atom = target_atom; owner->type_atom = target_atom; owner->selection_clear_event_id = gtk_signal_connect( GTK_OBJECT(w), "selection_clear_event", GTK_SIGNAL_FUNC(GUIDDESelectionClearEventCB), owner ); owner->selection_get_id = gtk_signal_connect( GTK_OBJECT(w), "selection_get", GTK_SIGNAL_FUNC(GUIDDESelectionGetCB), owner ); owner->data = STRDUP(data); owner->length = STRLEN(owner->data); /* Set owner callback data on the widget, destroying any * previously set owner callback data on the widget */ gtk_object_set_data_full( GTK_OBJECT(w), GUI_DDE_OWNER_DATA_KEY, owner, GUIDDEOwnerDestroyCB ); /* Set the widget as supporting the selection of the * specified type */ gtk_selection_add_target( w, /* Widget */ selection_atom, /* Selection */ target_atom, /* Target */ 0 /* Info */ ); /* Set selection owner */ if(!gtk_selection_owner_set( w, /* Owner GtkWidget */ selection_atom, /* Selection */ (guint32)t /* Time */ )) { /* Failed to set selection owner */ gtk_object_remove_data( GTK_OBJECT(w), GUI_DDE_OWNER_DATA_KEY ); return; } } /* * Gets the DDE as a string. * * The calling function must deallocate the returned pointer. */ gchar *GUIDDEGetString( GtkWidget *w, /* Widget making request */ GdkAtom selection_atom, /* Can be GDK_NONE */ gulong t /* Time */ ) { gchar *data; guint sig_id; GdkAtom type; GtkSelectionData *selection_data; static GdkAtom target_atom = GDK_NONE; if(target_atom == GDK_NONE) target_atom = gdk_atom_intern("STRING", FALSE); if(selection_atom == GDK_NONE) selection_atom = GDK_SELECTION_PRIMARY; if(w == NULL) return(NULL); if(GTK_WIDGET_NO_WINDOW(w)) { g_printerr( "GUIDDEGetString(): Failed:\ GtkWidget 0x%.8x does not have a GdkWindow.\n", (guint32)w ); return(NULL); } /* Set up callback data */ selection_data = (GtkSelectionData *)g_malloc0( sizeof(GtkSelectionData) ); selection_data->selection = selection_atom; selection_data->target = target_atom; selection_data->type = GDK_NONE; selection_data->format = -1; selection_data->data = NULL; selection_data->length = -1; /* -1 means data not received */ /* Set up widget to receive the "selection_received" signal */ sig_id = gtk_signal_connect( GTK_OBJECT(w), "selection_received", GTK_SIGNAL_FUNC(GUIDDESelectionReceivedCB), selection_data ); /* Request selection */ if(!gtk_selection_convert( w, /* Widget */ selection_atom, /* Selection */ target_atom, /* Target */ (guint32)t /* Time */ )) { /* Selection request failed */ GTK_SIGNAL_DISCONNECT(GTK_OBJECT(w), sig_id) g_free(selection_data->data); g_free(selection_data); return(NULL); } /* Wait for selection */ while(selection_data->length < 0) { while(gtk_events_pending() > 0) gtk_main_iteration(); } /* Got selection */ /* Disconnect signals */ GTK_SIGNAL_DISCONNECT(GTK_OBJECT(w), sig_id); /* Get data from selection from callback data */ type = selection_data->type; /* Integer */ if(type == GDK_SELECTION_TYPE_INTEGER) { switch(selection_data->length) { case 1: data = g_strdup_printf( "%i", *(gint8 *)selection_data->data ); break; case 2: data = g_strdup_printf( "%i", *(gint16 *)selection_data->data ); break; case 4: data = g_strdup_printf( "%i", *(gint32 *)selection_data->data ); break; case 8: data = g_strdup_printf( "%ld", (long)(*(gint64 *)selection_data->data) ); break; default: data = NULL; break; } } /* String (latin-1 characters) */ else if(type == GDK_SELECTION_TYPE_STRING) { data = (gchar *)selection_data->data; selection_data->data = NULL; } else { data = NULL; } /* Delete callback data */ g_free(selection_data->data); g_free(selection_data); return(data); } /* * Sets up widget as a DND drag source. */ void GUIDNDSetSrc( void *w, const void *drag_type, int ndrag_types, unsigned int actions, unsigned int buttons, void (*begin_cb)(GtkWidget *, GdkDragContext *, gpointer), void (*request_data_cb)(GtkWidget *, GdkDragContext *, GtkSelectionData *, guint, guint, gpointer), void (*delete_data_cb)(GtkWidget *, GdkDragContext *, gpointer), void (*end_cb)(GtkWidget *, GdkDragContext *, gpointer), gpointer client_data ) { GtkWidget *widget = (GtkWidget *)w; const GtkTargetEntry *target_entry = (const GtkTargetEntry *)drag_type; gint total_target_entries = (gint)ndrag_types; if((widget == NULL) || (target_entry == NULL) || (total_target_entries <= 0) ) return; /* Widget must have window */ if(GTK_WIDGET_NO_WINDOW(widget)) { g_printerr( "GUIDNDSetSrc(): Widget does not have window.\n" ); return; } /* Set the widget as a DND drag source */ gtk_drag_source_set( widget, buttons, target_entry, total_target_entries, actions ); /* Set the "drag_begin" signal callback, our local callback must * be connected before GTK internal drag begin callbacks */ gtk_signal_connect_after( GTK_OBJECT(widget), "drag_begin", GTK_SIGNAL_FUNC(GUIDNDDragBeginCB), NULL ); if(begin_cb != NULL) gtk_signal_connect_after( GTK_OBJECT(widget), "drag_begin", GTK_SIGNAL_FUNC(begin_cb), client_data ); /* Set the "drag_data_get" signal callback */ if(request_data_cb != NULL) gtk_signal_connect_after( GTK_OBJECT(widget), "drag_data_get", GTK_SIGNAL_FUNC(request_data_cb), client_data ); /* Set the "drag_data_delete" signal callback */ if(delete_data_cb != NULL) gtk_signal_connect_after( GTK_OBJECT(widget), "drag_data_delete", GTK_SIGNAL_FUNC(delete_data_cb), client_data ); /* Set the "drag_end" signal callback */ if(end_cb != NULL) gtk_signal_connect_after( GTK_OBJECT(widget), "drag_end", GTK_SIGNAL_FUNC(end_cb), client_data ); /* Set our own "drag_end" signal callback to be called after * the one for the client function */ gtk_signal_connect_after( GTK_OBJECT(widget), "drag_end", GTK_SIGNAL_FUNC(GUIDNDDragEndCB), NULL ); } /* * Sets up a widget as DND drop target. */ void GUIDNDSetTar( void *w, const void *drag_type, int ndrag_types, unsigned int actions, unsigned int default_action_same, unsigned int default_action, void (*recieved_data_cb)(GtkWidget *, GdkDragContext *, gint, gint, GtkSelectionData *, guint, guint, gpointer ), gpointer client_data ) { static gboolean init_cb_structs = TRUE; GtkWidget *widget = (GtkWidget *)w; const GtkTargetEntry *target_entry = (const GtkTargetEntry *)drag_type; gint total_target_entries = (gint)ndrag_types; static gui_dnd_cb_struct move_same_cb_data, move_cb_data, copy_cb_data; gui_dnd_cb_struct *cb_data_ptr = NULL; if((widget == NULL) || (target_entry == NULL) || (total_target_entries <= 0) ) return; /* Widget must have window */ if(GTK_WIDGET_NO_WINDOW(widget)) { g_printerr( "GUIDNDSetTar(): Widget does not have window.\n" ); return; } /* Set the widget as a DND drop target */ gtk_drag_dest_set( widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, target_entry, total_target_entries, actions ); /* Do we need to initialize DND callback data? */ if(init_cb_structs) { move_same_cb_data.default_action_same = GDK_ACTION_MOVE; move_same_cb_data.default_action = GDK_ACTION_COPY; move_cb_data.default_action_same = GDK_ACTION_MOVE; move_cb_data.default_action = GDK_ACTION_MOVE; copy_cb_data.default_action_same = GDK_ACTION_COPY; copy_cb_data.default_action = GDK_ACTION_COPY; init_cb_structs = FALSE; } /* Set local drag motion callback data */ /* Move only on same? */ if((default_action_same == GDK_ACTION_MOVE) && (default_action == GDK_ACTION_COPY) ) cb_data_ptr = &move_same_cb_data; /* Always move? */ else if((default_action_same == GDK_ACTION_MOVE) && (default_action == GDK_ACTION_MOVE) ) cb_data_ptr = &move_cb_data; /* Always copy? */ else if((default_action_same == GDK_ACTION_COPY) && (default_action == GDK_ACTION_COPY) ) cb_data_ptr = ©_cb_data; #if 0 /* Set this target widget to highlight when a drag goes over it */ gtk_drag_highlight(widget); #endif /* Set our local drag motion callback */ gtk_signal_connect_after( GTK_OBJECT(widget), "drag_motion", GTK_SIGNAL_FUNC(GUIDNDDragMotionCB), cb_data_ptr ); gtk_signal_connect_after( GTK_OBJECT(widget), "drag_drop", GTK_SIGNAL_FUNC(GUIDNDDragDropCB), cb_data_ptr ); /* Set data received callback for local and calling functions */ gtk_signal_connect_after( GTK_OBJECT(widget), "drag_data_received", GTK_SIGNAL_FUNC(GUIDNDDragReceivedCB), cb_data_ptr ); if(recieved_data_cb != NULL) gtk_signal_connect_after( GTK_OBJECT(widget), "drag_data_received", GTK_SIGNAL_FUNC(recieved_data_cb), client_data ); } /* * Sets the DND Icon for the next DND operation with the specified * pixmap and mask. * * If pixmap is NULL then the DND Icon is destroyed/shutdown. */ void GUIDNDSetDragIcon( GdkPixmap *pixmap, GdkBitmap *mask, gint hot_x, gint hot_y ) { gboolean is_pixmap_set = FALSE; GdkWindow *window; GtkWidget *w; gui_dnd_icon_struct *dnd_icon = &gui_dnd_icon; /* Destroy the DND Icon? */ if(pixmap == NULL) { w = dnd_icon->toplevel; if(w != NULL) { GTK_WIDGET_DESTROY(dnd_icon->icon_pm) GTK_WIDGET_DESTROY(dnd_icon->toplevel) memset(dnd_icon, 0x00, sizeof(gui_dnd_icon_struct)); } return; } /* Check if the DND Icon needs to be initialized for the very * first time */ w = dnd_icon->toplevel; if(w == NULL) { GtkWidget *parent; dnd_icon->toplevel = w = gtk_window_new(GTK_WINDOW_POPUP); gtk_widget_realize(w); parent = w; dnd_icon->icon_pm = w = gtk_pixmap_new(pixmap, mask); gtk_container_add(GTK_CONTAINER(parent), w); gtk_widget_show(w); is_pixmap_set = TRUE; } /* Get the GdkWindow of the DND Icon toplevel */ w = dnd_icon->toplevel; window = (w != NULL) ? w->window : NULL; if(window == NULL) return; /* Begin setting up the DND Icon with the new values */ dnd_icon->x = hot_x; dnd_icon->y = hot_y; gdk_window_get_size( pixmap, &dnd_icon->width, &dnd_icon->height ); /* Adjust size and shape of the DND Icon's toplevel window */ gtk_widget_set_usize(w, dnd_icon->width, dnd_icon->height); gdk_window_set_back_pixmap(window, pixmap, 0); gtk_widget_shape_combine_mask(w, mask, 0, 0); /* Set up the icon GtkPixmap */ w = dnd_icon->icon_pm; if((w != NULL) && !is_pixmap_set) { gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask); } } /* * Creates a new Banner. */ GtkWidget *GUIBannerCreate( const gchar *label, const gchar *font_name, GdkColor color_fg, GdkColor color_bg, GtkJustification justify, /* One of GTK_JUSTIFY_* */ gboolean expand ) { GdkFont *font = NULL; GtkRcStyle *rcstyle; GtkWidget *w = gtk_drawing_area_new(); gpointer *cb_data = (gpointer *)g_malloc0( 4 * sizeof(gpointer) ); cb_data[0] = STRDUP(label); cb_data[1] = (gpointer)justify; cb_data[2] = font = (font_name != NULL) ? gdk_font_load(font_name) : NULL; cb_data[3] = NULL; gtk_object_set_data_full( GTK_OBJECT(w), GUI_BANNER_DATA_KEY, cb_data, GUIBannerDataDestroyCB ); gtk_widget_add_events( w, GDK_STRUCTURE_MASK | GDK_EXPOSURE_MASK ); gtk_signal_connect( GTK_OBJECT(w), "configure_event", GTK_SIGNAL_FUNC(GUIBannerEventCB), cb_data ); gtk_signal_connect( GTK_OBJECT(w), "expose_event", GTK_SIGNAL_FUNC(GUIBannerEventCB), cb_data ); /* Set style */ rcstyle = gtk_rc_style_new(); if(!STRISEMPTY(font_name)) rcstyle->font_name = STRDUP(font_name); rcstyle->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG | GTK_RC_BG; rcstyle->color_flags[GTK_STATE_INSENSITIVE] = GTK_RC_FG | GTK_RC_BG; memcpy(&rcstyle->fg[GTK_STATE_NORMAL], &color_fg, sizeof(GdkColor)); memcpy(&rcstyle->bg[GTK_STATE_NORMAL], &color_bg, sizeof(GdkColor)); /* Modify foreground and background colors for insensitive */ #define LOWER_VALUE(c) (gushort)((((gint)(c) - (gint)((guint16)-1 / 2)) * 0.75) + \ (gint)((guint16)-1 / 2)) color_fg.red = LOWER_VALUE(color_fg.red); color_fg.green = LOWER_VALUE(color_fg.green); color_fg.blue = LOWER_VALUE(color_fg.blue); color_bg.red = LOWER_VALUE(color_bg.red); color_bg.green = LOWER_VALUE(color_bg.green); color_bg.blue = LOWER_VALUE(color_bg.blue); #undef LOWER_VALUE memcpy(&rcstyle->fg[GTK_STATE_INSENSITIVE], &color_fg, sizeof(GdkColor)); memcpy(&rcstyle->bg[GTK_STATE_INSENSITIVE], &color_bg, sizeof(GdkColor)); gtk_widget_modify_style(w, rcstyle); GTK_RC_STYLE_UNREF(rcstyle); /* Get new style values from widget */ if(font != NULL) { gint width, height; if(expand) width = -1; else if((font != NULL) && (label != NULL)) width = gdk_string_width(font, label); else width = -1; if(font != NULL) height = font->ascent + font->descent; else height = -1; gtk_widget_set_usize(w, width, height); } return(w); } /* * Draws the Banner. */ void GUIBannerDraw(GtkWidget *w) { GtkStateType state; GtkJustification justify; gint width, height; const gchar *label; GdkFont *font; GdkWindow *window; GdkDrawable *drawable; GtkStyle *style; gpointer *cb_data = (gpointer *)((w != NULL) ? gtk_object_get_data(GTK_OBJECT(w), GUI_BANNER_DATA_KEY) : NULL ); if(cb_data == NULL) return; label = (const gchar *)cb_data[0]; justify = (GtkJustification)cb_data[1]; font = (GdkFont *)cb_data[2]; state = GTK_WIDGET_STATE(w); window = w->window; style = gtk_widget_get_style(w); if((window == NULL) || (style == NULL)) return; drawable = (GdkDrawable *)window; gdk_window_get_size(drawable, &width, &height); if((width <= 0) || (height <= 0)) return; /* Begin drawing */ /* Background */ gdk_draw_rectangle( drawable, style->bg_gc[state], TRUE, 0, 0, width, height ); /* Got font and label? */ if((font != NULL) && !STRISEMPTY(label)) { const gint border = 3; gint lbearing, rbearing, swidth, ascent, descent; gdk_string_extents( font, label, &lbearing, &rbearing, &swidth, &ascent, &descent ); switch(justify) { case GTK_JUSTIFY_CENTER: gdk_draw_string( drawable, font, style->fg_gc[state], ((width - swidth) / 2) - lbearing, ((height - (font->ascent + font->descent)) / 2) + font->ascent, label ); break; case GTK_JUSTIFY_RIGHT: gdk_draw_string( drawable, font, style->fg_gc[state], (width - swidth - border) - lbearing, ((height - (font->ascent + font->descent)) / 2) + font->ascent, label ); break; case GTK_JUSTIFY_LEFT: gdk_draw_string( drawable, font, style->fg_gc[state], border - lbearing, ((height - (font->ascent + font->descent)) / 2) + font->ascent, label ); break; case GTK_JUSTIFY_FILL: break; } } /* Send drawable to window if drawable is not the window */ if(drawable != window) gdk_draw_pixmap( window, style->fg_gc[state], drawable, 0, 0, 0, 0, width, height ); } /* * Creates a new GtkCombo with label, combo, initial value, and * initial list of items. * * Returns the GtkTable (the parent) or NULL on failure. * * The given GList list will be duplicated, so the one passed to * this call will not be modified. */ GtkWidget *GUIComboCreate( const gchar *label, /* Label */ const gchar *text, /* Entry Value */ GList *list, /* Combo List */ gint max_items, /* Maximum Items In Combo List */ gpointer *combo_rtn, /* GtkCombo Return */ gpointer data, void (*func_cb)(GtkWidget *w, gpointer), void (*list_change_cb)(GtkWidget *, gpointer, GList *) ) { GtkWidget *parent, *wlabel = NULL, *w; GtkCombo *combo; const gchar *cstrptr; gpointer *cb_data; /* Reset return values */ if(combo_rtn != NULL) *combo_rtn = NULL; /* Create parent table widget */ parent = gtk_table_new( 1, ((label != NULL) ? 1 : 0) + 1, FALSE ); /* Do not show the table parent */ /* Create label? */ if(label != NULL) { gint x = 0; wlabel = gtk_label_new(label); gtk_table_attach( GTK_TABLE(parent), wlabel, (guint)x, (guint)(x + 1), 0, 1, 0, 0, 2, 2 ); gtk_label_set_justify(GTK_LABEL(wlabel), GTK_JUSTIFY_RIGHT); gtk_widget_show(wlabel); } /* Create combo */ if(TRUE) { gint i; gint x = (label != NULL) ? 1 : 0; GList *glist_in, *glist_out; GtkEntry *entry; w = gtk_combo_new(); combo = GTK_COMBO(w); entry = GTK_ENTRY(combo->entry); if(combo_rtn != NULL) *combo_rtn = w; gtk_table_attach( GTK_TABLE(parent), w, (guint)x, (guint)(x + 1), 0, 1, GTK_SHRINK | GTK_EXPAND | GTK_FILL, 0, 2, 2 ); gtk_combo_disable_activate(combo); gtk_entry_set_text(entry, (text != NULL) ? text : ""); gtk_entry_set_editable(entry, TRUE); gtk_combo_set_case_sensitive(combo, FALSE); /* Begin creating output glist, a duplicate input glist */ glist_out = NULL; glist_in = (GList *)list; /* Is input glist given? */ if(glist_in == NULL) { /* Input glist is NULL so create a bunch of empty strings * totalling that specified by max_items for the output * glist. */ for(i = 0; i < max_items; i++) glist_out = g_list_append(glist_out, STRDUP("")); } else { /* Input glist is given, make a duplicate of it as the * output glist. */ i = 0; while((i < max_items) && (glist_in != NULL)) { cstrptr = (const gchar *)glist_in->data; glist_out = g_list_append( glist_out, STRDUP(cstrptr) ); glist_in = g_list_next(glist_in); i++; } } glist_in = NULL; /* Input glist should no longer be used */ /* Set new output glist to combo box */ if(glist_out != NULL) gtk_combo_set_popdown_strings(combo, glist_out); /* Do not delete the output glist, it will be passed to the * callback data below. */ /* Allocate callback data, 9 pointers of format; * table Parent table that holds this combo and label. * label Label (may be NULL). * combo This combo widget. * GList Contains list of strings in combo list. * max_items Max items allowed in combo list. * data Calling function set callback data. * func_cb Calling function set callback function. * list_change_cb Calling function set list change function. * NULL */ cb_data = (gpointer *)g_malloc0(9 * sizeof(gpointer)); cb_data[0] = parent; cb_data[1] = wlabel; cb_data[2] = combo; cb_data[3] = glist_out; cb_data[4] = (gpointer)MAX(max_items, 0); cb_data[5] = data; cb_data[6] = (gpointer)func_cb; cb_data[7] = (gpointer)list_change_cb; cb_data[8] = NULL; gtk_object_set_data_full( GTK_OBJECT(combo), GUI_COMBO_DATA_KEY, cb_data, GUIComboDataDestroyCB ); gtk_signal_connect( GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(GUIComboActivateCB), cb_data ); gtk_signal_connect( GTK_OBJECT(entry), "changed", GTK_SIGNAL_FUNC(GUIComboChangedCB), cb_data ); gtk_widget_show(w); } return(parent); } /* * Adds the specified value to the combo widget w's list and current * value for the combo widget's entry widget. * * The item will only be added to the list if it is not NULL * and does not already exist in the list. * * Excess items may be truncated if adding this item would exceed * the combo list's maximum allowed items. */ void GUIComboActivateValue(GtkWidget *w, const gchar *value) { gpointer *cb_data; GtkCombo *combo = (GtkCombo *)w; if((combo == NULL) || (value == NULL)) return; cb_data = (gpointer *)GTK_OBJECT_GET_DATA( combo, GUI_COMBO_DATA_KEY ); if(cb_data == NULL) return; /* Set new value on combo's entry widget */ gtk_entry_set_text( GTK_ENTRY(combo->entry), value ); /* Call activate callback as if this was an actual activate * signal */ GUIComboActivateCB(GTK_WIDGET(combo), (gpointer)cb_data); } /* * Adds the given value to the beginning of the glist for the * combo box w. Older items in the list may be truncated if adding * a new value would exceed the set maximum items for the combo box. * * If value is already in the list then no operation will be * performed. * * The combo box's set list change callback will be called if it is * not NULL and the new value was different and added succesfully. */ void GUIComboAddItem(GtkWidget *w, const gchar *value) { gint i, max_items; gboolean status; const gchar *cstrptr; GtkWidget *parent, *wlabel; GtkCombo *combo = (GtkCombo *)w; GList *glist_in, *glist_next_in; gpointer client_data; void (*func_cb)(GtkWidget *, gpointer); void (*list_change_cb)(GtkWidget *, gpointer, GList *); gpointer *cb_data; if((combo == NULL) || (value == NULL)) return; /* Get object callback data */ cb_data = (gpointer *)GTK_OBJECT_GET_DATA( combo, GUI_COMBO_DATA_KEY ); if(cb_data == NULL) return; /* Parse callback data, format is as follows; * table Parent table that holds this combo and label. * label Label (may be NULL). * combo This combo widget. * GList Contains list of strings in combo list. * max_items Max items allowed in combo list. * client_data Calling function set callback data. * func_cb Calling function set callback function. * list_change_cb Calling function set list change function. * NULL */ parent = (GtkWidget *)(cb_data[0]); wlabel = (GtkWidget *)(cb_data[1]); combo = (GtkCombo *)(cb_data[2]); glist_in = (GList *)(cb_data[3]); max_items = (gint)(cb_data[4]); client_data = (gpointer)(cb_data[5]); func_cb = cb_data[6]; list_change_cb = cb_data[7]; /* Check if new value is already in the input glist */ status = TRUE; i = 0; glist_next_in = glist_in; /* Iterate from 0 to max_items or when the input glist is * NULL (whichever occures first). */ while((i < max_items) && (glist_next_in != NULL)) { cstrptr = (gchar *)glist_next_in->data; if(cstrptr != NULL) { /* Check if case sensitive? */ /* Compare list item value with given value */ if(!g_strcasecmp(cstrptr, value)) { /* Given value matches a value in the list, so set * status to FALSE indicating there is a value already * in the list. */ status = FALSE; break; } } i++; glist_next_in = g_list_next(glist_next_in); } /* Variable status will be set to FALSE if the value is already * in the list. */ /* Check if max_items allows us to add a new item to the list and * if status is TRUE (indicating value is not already in the * list). */ if((max_items > 0) && status) { /* Create new output glist */ GList *glist_out = NULL; /* Add first item in output glist to be the new value fetched * from the combo's entry. */ glist_out = g_list_append(glist_out, STRDUP(value)); /* Now copy old input glist items to output glist, starting * with i = 1 since we already have one item in the output * glist. */ i = 1; glist_next_in = glist_in; while((i < max_items) && (glist_next_in != NULL)) { cstrptr = (const gchar *)glist_next_in->data; glist_out = g_list_append(glist_out, STRDUP(cstrptr)); glist_next_in = g_list_next(glist_next_in); i++; } /* Set new output glist to the combo box's list */ if(glist_out != NULL) gtk_combo_set_popdown_strings(combo, glist_out); /* Free old input glist since its no longer being used */ if(glist_in != NULL) { g_list_foreach(glist_in, (GFunc)g_free, NULL); g_list_free(glist_in); glist_in = NULL; } /* Update input glist to be that of the output glist */ glist_in = glist_out; /* Record new glist on callback data */ cb_data[3] = (gpointer)glist_in; /* Call list change function and pass the new glist */ if(list_change_cb != NULL) { list_change_cb( (GtkWidget *)combo, /* Pass combo box as widget */ client_data, /* Client data */ glist_in /* New glist */ ); } } } /* * Returns the GList for the combo widget created by * GUIComboCreate(). */ GList *GUIComboGetList(GtkWidget *w) { gpointer *cb_data = (gpointer *)GTK_OBJECT_GET_DATA( w, GUI_COMBO_DATA_KEY ); if(cb_data == NULL) return(NULL); /* Parse callback data, format is as follows; * table Parent table that holds this combo and label. * label Label (may be NULL). * combo This combo widget. * GList Contains list of strings in combo list. * max_items Max items allowed in combo list. * client_data Calling function set callback data. * func_cb Calling function set callback function. * list_change_cb Calling function set list change function. * NULL */ return((GList *)cb_data[3]); } /* * Sets the new list for the combo. * * If the pointer of the given list is the same as the combo's * current list then the given list will simply be pdated to the * combo with a call to gtk_combo_set_popdown_strings(). * * If the given list is NULL then the combo's current list will * be deleted. * * In any case the given list should not be referenced again after * this call. */ void GUIComboSetList(GtkWidget *w, GList *list) { GList *glist; GtkCombo *combo = (GtkCombo *)w; gpointer *cb_data = (gpointer *)GTK_OBJECT_GET_DATA( w, GUI_COMBO_DATA_KEY ); if(cb_data == NULL) return; /* Parse callback data, format is as follows; * table Parent table that holds this combo and label. * label Label (may be NULL). * combo This combo widget. * GList Contains list of strings in combo list. * max_items Max items allowed in combo list. * client_data Calling function set callback data. * func_cb Calling function set callback function. * list_change_cb Calling function set list change function. * NULL */ glist = (GList *)cb_data[3]; /* Is given list NULL? */ if(list == NULL) { gint i, max_items = (gint)cb_data[4]; GList *glist_new, *glist_old = glist; /* Create a new glist containing just empty strings */ glist_new = NULL; for(i = 0; i < max_items; i++) glist_new = g_list_append(glist_new, STRDUP("")); /* Was new glist created successfully? */ if(glist_new != NULL) { /* Set new glist to combo */ gtk_combo_set_popdown_strings(combo, glist_new); /* If old glist exists, then delete it */ if(glist_old != NULL) { g_list_foreach(glist_old, (GFunc)g_free, NULL); g_list_free(glist_old); glist_old = NULL; } /* Update pointer to new glist */ cb_data[3] = (gpointer)glist_new; glist = glist_new; } } /* Given list matches current list's base pointer values? */ else if((gpointer)list == (gpointer)glist) { /* Just update list on combo then */ gtk_combo_set_popdown_strings(combo, glist); /* No need to change pointer on callback data */ /* No need to deallocate given list */ } else { /* New and current list base pointers do not match and * current glist may be NULL */ const gchar *s; gint i, max_items; GList *glist_new, *glist_in, *glist_old = glist; /* Make a copy the given list as glist_new and limit the * number of items to max_items */ i = 0; max_items = (gint)cb_data[4]; glist_new = NULL; /* New glist */ glist_in = (GList *)list; /* Input glist */ while((i < max_items) && (glist_in != NULL)) { s = (const gchar *)glist_in->data; glist_new = g_list_append(glist_new, STRDUP(s)); glist_in = g_list_next(glist_in); i++; } /* Destroy the given list */ glist_in = (GList *)list; /* Input glist */ list = NULL; /* Mark input list as NULL */ if(glist_in != NULL) { g_list_foreach(glist_in, (GFunc)g_free, NULL); g_list_free(glist_in); glist_in = NULL; } /* Is new coppied glist valid? */ if(glist_new != NULL) { /* Set new glist to combo */ gtk_combo_set_popdown_strings(combo, glist_new); /* If old glist exists, then delete it */ if(glist_old != NULL) { g_list_foreach(glist_old, (GFunc)g_free, NULL); g_list_free(glist_old); glist_old = NULL; } /* Update pointer to new glist on callback data */ cb_data[3] = (gpointer)glist_new; glist = glist_new; } } } /* * Resets all values in the combo widget. */ void GUIComboClearAll(GtkWidget *w) { GtkCombo *combo = (GtkCombo *)w; if(combo == NULL) return; /* Clear text entry */ gtk_entry_set_text(GTK_ENTRY(combo->entry), ""); gtk_entry_set_position(GTK_ENTRY(combo->entry), 0); /* Clear combo's glist by setting a new one as NULL */ GUIComboSetList(w, NULL); } /* * Creates a new Menu Bar & GtkAccelGroup. */ GtkWidget *GUIMenuBarCreate(GtkAccelGroup **accelgrp_rtn) { if(accelgrp_rtn != NULL) *accelgrp_rtn = gtk_accel_group_new(); return(gtk_menu_bar_new()); } /* * Creates a new Tear Off Menu. */ GtkWidget *GUIMenuCreateTearOff(void) { GtkWidget *menu = gtk_menu_new(), *w = gtk_tearoff_menu_item_new(); gtk_menu_append(GTK_MENU(menu), w); gtk_widget_show(w); return(menu); } /* * Creates a New Menu. */ GtkWidget *GUIMenuCreate(void) { return(gtk_menu_new()); } /* * Creates a new Menu Item. * * If accelgrp is NULL then only the accelerator key label will * state the accelerator key and the accelerator key will not be * added to the accelerator group. * * If functional_widget_rtn not NULL then it will refer to the * functional widget of the new Menu Item. For example, if the type * was GUI_MENU_ITEM_TYPE_LABEL then *functional_widget_rtn will * refer to the GtkLabel. */ GtkWidget *GUIMenuItemCreate( GtkWidget *menu, gui_menu_item_type type, /* One of GUI_MENU_ITEM_TYPE_* */ GtkAccelGroup *accelgrp, guint8 **icon, const gchar *label, guint accel_key, guint accel_mods, gpointer *functional_widget_rtn, gpointer data, void (*func_cb)(GtkWidget *w, gpointer) ) { const gint border_minor = 2, border_accel_label = 15; GtkWidget *w, *menu_item = NULL, *parent, *parent2; gui_menu_item_data_struct *mi; if(menu == NULL) return(NULL); /* Reset functional widget ID */ if(functional_widget_rtn != NULL) *functional_widget_rtn = NULL; /* Create menu item data */ mi = GUI_MENU_ITEM_DATA( g_malloc0(sizeof(gui_menu_item_data_struct)) ); /* Create menu item by type */ switch(type) { case GUI_MENU_ITEM_TYPE_LABEL: case GUI_MENU_ITEM_TYPE_SUBMENU: /* Create a GtkMenuItem */ mi->menu_item = menu_item = parent = w = gtk_menu_item_new(); if(!GTK_WIDGET_NO_WINDOW(w)) gtk_widget_add_events( w, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK ); gtk_menu_append(GTK_MENU(menu), w); gtk_object_set_data_full( GTK_OBJECT(w), GUI_MENU_ITEM_DATA_KEY, mi, GUIMenuDataDestroyCB ); gtk_widget_show(w); /* Create a GtkTable to hold the icon and labels */ w = gtk_table_new(1, 3, FALSE); gtk_container_add(GTK_CONTAINER(parent), w); #ifndef HAVE_WIN32 gtk_table_set_col_spacing( GTK_TABLE(w), 0, (guint)border_minor ); gtk_table_set_col_spacing( GTK_TABLE(w), 1, (guint)border_accel_label ); #endif gtk_widget_show(w); parent = w; /* Create icon, if icon is NULL then an empty fixed * widget would have been returned */ mi->icon_data = (const guint8 **)icon; mi->pixmap = w = GUICreateMenuItemIcon(icon); if(w != NULL) { gtk_table_attach( GTK_TABLE(parent), w, 0, 1, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 ); gtk_widget_show(w); } /* Create a GtkAlignment to align the label */ w = gtk_alignment_new(0.0f, 0.5f, 0.0f, 0.0f); gtk_table_attach( GTK_TABLE(parent), w, 1, 2, 0, 1, GTK_SHRINK | GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0 ); gtk_widget_show(w); parent2 = w; /* Create a GtkLabel as the label */ mi->label_text = STRDUP((label != NULL) ? label : ""); mi->label = w = gtk_label_new(mi->label_text); gtk_container_add(GTK_CONTAINER(parent2), w); gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT); gtk_widget_show(w); /* Record the GtkLabel as the functional widget */ if(functional_widget_rtn != NULL) *functional_widget_rtn = w; /* Set callback for menu item? */ if(func_cb != NULL) { /* Create menu item client data */ gpointer *mi_client_data = (gpointer *)g_malloc0( 4 * sizeof(gpointer) ); mi_client_data[0] = w; /* Functional widget (GtkLabel) */ mi_client_data[1] = data; mi_client_data[2] = (gpointer)func_cb; mi_client_data[3] = NULL; gtk_object_set_data_full( GTK_OBJECT(menu_item), GUI_MENU_ITEM_CLIENT_DATA_KEY, mi_client_data, GUIMenuClientDataDestroyCB ); gtk_signal_connect_object( GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC(GUIMenuActivateCB), (gpointer)mi_client_data ); } /* Create a GtkAlignment for the accelerator key label */ w = gtk_alignment_new(1.0f, 0.5f, 0.0f, 0.0f); gtk_table_attach( GTK_TABLE(parent), w, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 ); gtk_widget_show(w); parent2 = w; /* Create a GtkLabel as the accelerator key label */ mi->accel_label = w = gtk_label_new(""); gtk_container_add(GTK_CONTAINER(parent2), w); gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_RIGHT); /* Set accelerator key and accelerator key GtkLabel */ GUIMenuItemSetAccelKey( menu_item, accelgrp, accel_key, accel_mods ); break; case GUI_MENU_ITEM_TYPE_CHECK: /* Create a GtkCheckMenuItem */ mi->label_text = STRDUP((label != NULL) ? label : ""); mi->menu_item = menu_item = parent = w = gtk_check_menu_item_new_with_label(mi->label_text); /* Need to set default height */ gtk_widget_set_usize(w, -1, GUI_MENU_ITEM_DEF_HEIGHT + 2); gtk_menu_append(GTK_MENU(menu), w); gtk_object_set_data_full( GTK_OBJECT(w), GUI_MENU_ITEM_DATA_KEY, mi, GUIMenuDataDestroyCB ); gtk_widget_show(w); /* Record check menu item as the functional widget */ if(functional_widget_rtn != NULL) *functional_widget_rtn = w; /* Set callback for the check menu item? */ if(func_cb != NULL) { /* Create menu item client data */ gpointer *mi_client_data = (gpointer *)g_malloc0( 4 * sizeof(gpointer) ); mi_client_data[0] = w; /* Functional widget */ mi_client_data[1] = data; mi_client_data[2] = (gpointer)func_cb; mi_client_data[3] = NULL; gtk_object_set_data_full( GTK_OBJECT(menu_item), GUI_MENU_ITEM_CLIENT_DATA_KEY, mi_client_data, GUIMenuClientDataDestroyCB ); gtk_signal_connect_object( GTK_OBJECT(menu_item), "toggled", GTK_SIGNAL_FUNC(GUIMenuActivateCB), (gpointer)mi_client_data ); } /* Set accelerator key */ GUIMenuItemSetAccelKey( menu_item, accelgrp, accel_key, accel_mods ); break; case GUI_MENU_ITEM_TYPE_SEPARATOR: /* Create a GtkMenuItem */ mi->menu_item = menu_item = parent = w = gtk_menu_item_new(); gtk_menu_append(GTK_MENU(menu), w); gtk_object_set_data_full( GTK_OBJECT(w), GUI_MENU_ITEM_DATA_KEY, mi, GUIMenuDataDestroyCB ); gtk_widget_show(w); /* Create horizontal separator */ w = gtk_hseparator_new(); gtk_container_add(GTK_CONTAINER(parent), w); GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(menu_item), GTK_SENSITIVE); gtk_widget_show(w); /* Record horizontal separator as the functional widget */ if(functional_widget_rtn != NULL) *functional_widget_rtn = w; break; default: GUIMenuDataDestroyCB(mi); mi = NULL; break; } return(menu_item); } /* * Sets the Menu Item as the default item. */ void GUISetMenuItemDefault(GtkWidget *w) { #if 0 GtkRcStyle *rcstyle; #endif gui_menu_item_data_struct *cb_data = GUI_MENU_ITEM_DATA( GTK_OBJECT_GET_DATA(w, GUI_MENU_ITEM_DATA_KEY) ); if(cb_data == NULL) return; #if 0 rcstyle = gtk_rc_style_new(); rcstyle->font_name = STRDUP( "-*-*-bold-*-*-*-*-*-*-*-*-*-*-*" /* "-adobe-helvetica-bold-r-normal-*-12-*-*-*-*-*-iso8859-1" */ ); w = cb_data->label; if(w != NULL) gtk_widget_modify_style(w, rcstyle); w = cb_data->accel_label; if(w != NULL) gtk_widget_modify_style(w, rcstyle); GTK_RC_STYLE_UNREF(rcstyle) #endif } /* * Sets the Menu Item's "enter_notify_event" and * "leave_notify_event" signal callbacks. */ void GUISetMenuItemCrossingCB( GtkWidget *w, gint (*enter_cb)(GtkWidget *, GdkEvent *, gpointer), gpointer enter_data, gint (*leave_cb)(GtkWidget *, GdkEvent *, gpointer), gpointer leave_data ) { if(w == NULL) return; if(enter_cb != NULL) gtk_signal_connect( GTK_OBJECT((GtkWidget *)w), "enter_notify_event", GTK_SIGNAL_FUNC(enter_cb), enter_data ); if(leave_cb != NULL) gtk_signal_connect( GTK_OBJECT((GtkWidget *)w), "leave_notify_event", GTK_SIGNAL_FUNC(leave_cb), leave_data ); } /* * Adds the Menu to the Menu Bar with the specified label. * * Returns the Menu Bar Label or NULL on error. */ GtkWidget *GUIMenuAddToMenuBar( GtkWidget *menu_bar, GtkWidget *menu, const gchar *label, gui_menu_bar_item_alignment align /* One of GUI_MENU_BAR_ALIGN_* */ ) { GtkWidget *menu_label; GtkMenuShell *menu_shell; if((menu_bar == NULL) || (menu == NULL)) return(NULL); menu_shell = GTK_MENU_SHELL(menu_bar); /* Create Menu Label */ if(label != NULL) { menu_label = gtk_menu_item_new_with_label(label); } else { GList *glist = menu_shell->children; gchar *s = g_strdup_printf( "Menu %i", g_list_length(glist) + 1 ); menu_label = gtk_menu_item_new_with_label(s); g_free(s); } /* Set Menu Label to reffer to the given Menu */ gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu_label), menu ); /* Append Menu Label to the given Menu Bar */ gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), menu_label); gtk_widget_show(menu_label); /* Set Menu Label alignment */ if(align == GUI_MENU_BAR_ALIGN_RIGHT) gtk_menu_item_right_justify(GTK_MENU_ITEM(menu_label)); return(menu_label); } /* * Sets the Menu Item's label. */ void GUIMenuItemSetLabel(GtkWidget *menu_item, const gchar *label) { GtkWidget *w; gui_menu_item_data_struct *mi = GUI_MENU_ITEM_DATA( GTK_OBJECT_GET_DATA(menu_item, GUI_MENU_ITEM_DATA_KEY) ); if(mi == NULL) return; w = mi->label; if(label != NULL) { /* No change in label text? */ const gchar *old_label = mi->label_text; if((old_label != NULL) ? !strcmp(old_label, label) : FALSE) return; /* Record new label text */ g_free(mi->label_text); mi->label_text = STRDUP(label); /* Set new label text */ if((w != NULL) ? GTK_IS_LABEL(w) : FALSE) gtk_label_set_text(GTK_LABEL(w), mi->label_text); } else { /* Label text was already empty? */ if(mi->label_text == NULL) return; /* Record new label text */ g_free(mi->label_text); mi->label_text = STRDUP("(null)"); /* Set new label text */ if((w != NULL) ? GTK_IS_LABEL(w) : FALSE) gtk_label_set_text(GTK_LABEL(w), mi->label_text); } } /* * Sets the Menu Item's pixmap. */ void GUIMenuItemSetPixmap(GtkWidget *menu_item, guint8 **icon_data) { GdkWindow *window; GtkStyle *style; GtkWidget *w; gui_menu_item_data_struct *mi = GUI_MENU_ITEM_DATA( GTK_OBJECT_GET_DATA(menu_item, GUI_MENU_ITEM_DATA_KEY) ); if((mi == NULL) || (icon_data == NULL)) return; if(gui_window_root == NULL) gui_window_root = (GdkWindow *)GDK_ROOT_PARENT(); window = gui_window_root; /* No change in icon data? */ if(mi->icon_data == (const guint8 **)icon_data) return; style = gtk_widget_get_style(menu_item); w = mi->pixmap; if((w != NULL) ? GTK_IS_PIXMAP(w) : FALSE) { GdkBitmap *mask = NULL; GdkPixmap *pixmap = gdk_pixmap_create_from_xpm_d( window, &mask, (style != NULL) ? &style->bg[GTK_STATE_NORMAL] : NULL, (gchar **)icon_data ); if(pixmap != NULL) { gint width, height; /* Record new icon data */ mi->icon_data = (const guint8 **)icon_data; /* Update pixmap */ gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask); /* Get size of newly loaded pixmap */ gdk_window_get_size(pixmap, &width, &height); } GDK_PIXMAP_UNREF(pixmap); GDK_BITMAP_UNREF(mask); } } /* * Sets the Menu Item's accelerator key. * * If accelgrp is NULL then only the accelerator key label will be * updated. */ void GUIMenuItemSetAccelKey( GtkWidget *menu_item, GtkAccelGroup *accelgrp, guint accel_key, guint accel_mods ) { GtkWidget *w; gui_menu_item_data_struct *mi = GUI_MENU_ITEM_DATA( GTK_OBJECT_GET_DATA(menu_item, GUI_MENU_ITEM_DATA_KEY) ); if(mi == NULL) return; /* No change? */ if((mi->accel_key == accel_key) && (mi->accel_mods == accel_mods) ) return; /* Update the GtkAccelGroup? */ if(accelgrp != NULL) { /* Remove existing accelerator key? */ if(mi->accel_key != 0) gtk_widget_remove_accelerator( menu_item, accelgrp, mi->accel_key, mi->accel_mods ); /* Add new accelerator key */ gtk_widget_add_accelerator( menu_item, "activate", accelgrp, accel_key, accel_mods, GTK_ACCEL_VISIBLE ); } /* Update the accelerator key GtkLabel */ w = mi->accel_label; if(w != NULL) { GtkLabel *label = GTK_LABEL(w); /* Accelerator key specified? */ if(accel_key != 0) { const gchar *key_name; gchar *accel_text = STRDUP(""); /* Append modifier name to accelerator text */ if(accel_mods & GDK_LOCK_MASK) { gchar *s = g_strconcat(accel_text, "CapsLock+", NULL); g_free(accel_text); accel_text = s; } if(accel_mods & GDK_CONTROL_MASK) { gchar *s = g_strconcat(accel_text, "Ctrl+", NULL); g_free(accel_text); accel_text = s; } if(accel_mods & GDK_SHIFT_MASK) { gchar *s = g_strconcat(accel_text, "Shift+", NULL); g_free(accel_text); accel_text = s; } if(accel_mods & GDK_MOD1_MASK) { gchar *s = g_strconcat(accel_text, "Alt+", NULL); g_free(accel_text); accel_text = s; } if(accel_mods & GDK_MOD2_MASK) { gchar *s = g_strconcat(accel_text, "NumLock+", NULL); g_free(accel_text); accel_text = s; } if(accel_mods & GDK_MOD3_MASK) { gchar *s = g_strconcat(accel_text, "Mod3+", NULL); g_free(accel_text); accel_text = s; } if(accel_mods & GDK_MOD4_MASK) { gchar *s = g_strconcat(accel_text, "Mod4+", NULL); g_free(accel_text); accel_text = s; } if(accel_mods & GDK_MOD5_MASK) { gchar *s = g_strconcat(accel_text, "ScrollLock+", NULL); g_free(accel_text); accel_text = s; } /* Append key name to accelerator key text */ key_name = GUIGetKeyName(accel_key); /* key_name = gdk_keyval_name(accel_key); */ if(*key_name != '\0') { gchar *s = g_strconcat(accel_text, key_name, NULL); g_free(accel_text); accel_text = s; } else { gchar *char_name = g_strdup_printf( "%c", toupper(accel_key) ); gchar *s = g_strconcat(accel_text, char_name, NULL); g_free(char_name); g_free(accel_text); accel_text = s; } /* Set and map accelerator key GtkLabel */ g_free(mi->accel_text); mi->accel_text = STRDUP(accel_text); gtk_label_set_text(label, accel_text); gtk_widget_show(w); g_free(accel_text); } else { /* Clear and unmap accelerator key GtkLabel */ g_free(mi->accel_text); mi->accel_text = NULL; gtk_label_set_text(label, ""); gtk_widget_hide(w); } } /* Record new accelerator key value */ mi->accel_key = accel_key; mi->accel_mods = accel_mods; } /* * Sets the Check Menu Item's active state. */ void GUIMenuItemSetCheck( GtkWidget *menu_item, gboolean active, gboolean emit ) { #if 1 if((menu_item != NULL) ? !GTK_IS_CHECK_MENU_ITEM(menu_item) : TRUE) return; if(emit) gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(menu_item), active ); else GTK_CHECK_MENU_ITEM(menu_item)->active = active; #else GtkWidget *w; gui_menu_item_data_struct *mi = GUI_MENU_ITEM_DATA( GTK_OBJECT_GET_DATA(menu_item, GUI_MENU_ITEM_DATA_KEY) ); if(mi == NULL) return; w = mi->check; #endif } /* * Gets the Check Menu Item's active state. */ gboolean GUIMenuItemGetCheck(GtkWidget *menu_item) { #if 1 if(menu_item == NULL) return(FALSE); if(GTK_IS_CHECK_MENU_ITEM(menu_item)) return(GTK_CHECK_MENU_ITEM(menu_item)->active); else return(FALSE); #else #endif } /* * Same as GUIMenuAddToMenuBar() except a pixmap is placed to the * left of the label on the menu bar. */ GtkWidget *GUIMenuAddToMenuBarPixmapH( GtkWidget *menu_bar, GtkWidget *menu, const gchar *label, guint8 **icon_data, gui_menu_bar_item_alignment align ) { return(GUIMenuAddToMenuBar( menu_bar, menu, label, align )); } /* * Links the Menu Item to the Sub Menu. */ void GUIMenuItemSetSubMenu( GtkWidget *menu_item, GtkWidget *sub_menu ) { if(menu_item == NULL) return; if(sub_menu == NULL) gtk_menu_item_remove_submenu(GTK_MENU_ITEM(menu_item)); else gtk_menu_item_set_submenu( GTK_MENU_ITEM(menu_item), sub_menu ); } /* * Creates a pull out widget horizontally, returning the hbox which * the calling function can pack child widgets into. * * The given parent must be a hbox or a vbox. * * The toplevel_width and toplevel_height specify the size of the * toplevel window that will be used when this widget is `pulled * out'. * * gtk_widget_show() will be called for you, the client function need * not call it. */ void *GUIPullOutCreateH( void *parent_box, int homogeneous, int spacing, /* Of client vbox */ int expand, int fill, int padding, /* Of holder hbox */ int toplevel_width, int toplevel_height, void *pull_out_client_data, void (*pull_out_cb)(void *, void *), void *push_in_client_data, void (*push_in_cb)(void *, void *) ) { gpointer *cb_data; GtkWidget *pull_out_btn, *holder_hbox, *client_hbox; if(parent_box == NULL) return(NULL); /* Create a hbox to place into the given parent box. This hbox * will hold the parenting hbox plus some other widgets. */ holder_hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start( (GtkBox *)parent_box, holder_hbox, expand, fill, padding ); gtk_widget_show(holder_hbox); /* Create pull out button and parent it to the holder hbox. * Note that this is not really a button but an event box. */ pull_out_btn = gtk_event_box_new(); gtk_box_pack_start( GTK_BOX(holder_hbox), pull_out_btn, FALSE, FALSE, 0 ); gtk_widget_set_usize(pull_out_btn, 10, -1); gtk_widget_show(pull_out_btn); /* Create the client hbox, which will be parented to the above * holder hbox when `placed in' and reparented to a toplevel * GtkWindow when `pulled out'. */ client_hbox = gtk_hbox_new(homogeneous, spacing); gtk_box_pack_start( GTK_BOX(holder_hbox), client_hbox, TRUE, TRUE, 0 ); gtk_widget_show(client_hbox); /* Set callbacks and callback data */ /* Allocate and set up callback data */ cb_data = (gpointer *)g_malloc0(13 * sizeof(gpointer)); if(cb_data != NULL) { /* Format is as follows (13 arguments): * * client_hbox * holder_hbox * holder_window * holder_window_x * holder_window_y * holder_window_width * holder_window_height * in_place (1 if true). * pull_out_client_data * pull_out_cb * push_in_client_data * push_in_cb */ cb_data[0] = (gpointer)client_hbox; cb_data[1] = (gpointer)holder_hbox; cb_data[2] = NULL; cb_data[3] = 0; cb_data[4] = 0; cb_data[5] = (gpointer)MAX(toplevel_width, 0); cb_data[6] = (gpointer)MAX(toplevel_height, 0); cb_data[7] = (gpointer)1; /* Initially `pushed in' */ cb_data[8] = (gpointer)pull_out_client_data; cb_data[9] = (gpointer)pull_out_cb; cb_data[10] = (gpointer)push_in_client_data; cb_data[11] = (gpointer)push_in_cb; cb_data[12] = NULL; gtk_object_set_data_full( GTK_OBJECT(client_hbox), GUI_PULLOUT_DATA_KEY, cb_data, GUIPullOutDataDestroyCB ); } gtk_signal_connect( GTK_OBJECT(pull_out_btn), "button_press_event", GTK_SIGNAL_FUNC(GUIPullOutPullOutBtnCB), cb_data ); gtk_signal_connect_after( GTK_OBJECT(pull_out_btn), "expose_event", GTK_SIGNAL_FUNC(GUIPullOutDrawHandleCB), NULL ); gtk_signal_connect( GTK_OBJECT(pull_out_btn), "draw", GTK_SIGNAL_FUNC(GUIPullOutDrawHandleDrawCB), NULL ); return(client_hbox); } /* * Returns the pointer to the toplevel window (if any) of the * client_hbox and the geometry of that window. * * The client box should be one created by GUIPullOutCreate*(). */ void *GUIPullOutGetToplevelWindow( void *client_box, int *x, int *y, int *width, int *height ) { gpointer *cb_data; GtkWidget *w = NULL; if(x != NULL) *x = 0; if(y != NULL) *y = 0; if(width != NULL) *width = 0; if(height != NULL) *height = 0; if(client_box == NULL) return(w); cb_data = (gpointer *)GTK_OBJECT_GET_DATA( client_box, GUI_PULLOUT_DATA_KEY ); if(cb_data != NULL) { /* Format is as follows (13 arguments): * * client_hbox * holder_hbox * holder_window * holder_window_x * holder_window_y * holder_window_width * holder_window_height * in_place (1 if true). * pull_out_client_data * pull_out_cb * push_in_client_data * push_in_cb */ w = (GtkWidget *)cb_data[2]; if((w != NULL) ? !GTK_WIDGET_NO_WINDOW(w) : FALSE) { GdkWindow *window = w->window; gint rx, ry, rwidth, rheight, rdepth; gdk_window_get_geometry( window, &rx, &ry, &rwidth, &rheight, &rdepth ); if(x != NULL) *x = rx; if(y != NULL) *y = ry; if(width != NULL) *width = rwidth; if(height != NULL) *height = rheight; } } return(w); } /* * Pulls out the pull out box. */ void GUIPullOutPullOut(void *client_box) { gpointer *cb_data; if(client_box == NULL) return; cb_data = (gpointer *)GTK_OBJECT_GET_DATA( client_box, GUI_PULLOUT_DATA_KEY ); if(cb_data != NULL) { /* Format is as follows (13 arguments): * * client_hbox * holder_hbox * holder_window * holder_window_x * holder_window_y * holder_window_width * holder_window_height * in_place (1 if true). * pull_out_client_data * pull_out_cb * push_in_client_data * push_in_cb */ /* In place (pushed in)? */ if((gint)cb_data[7]) { GUIPullOutPullOutBtnCB( NULL, NULL, (gpointer)cb_data ); } } } /* * Pushes in the pull out box. */ void GUIPullOutPushIn(void *client_box) { GtkWidget *w; gpointer *cb_data; if(client_box == NULL) return; cb_data = (gpointer *)GTK_OBJECT_GET_DATA( client_box, GUI_PULLOUT_DATA_KEY ); if(cb_data != NULL) { /* Format is as follows (13 arguments): * * client_hbox * holder_hbox * holder_window * holder_window_x * holder_window_y * holder_window_width * holder_window_height * in_place (1 if true). * pull_out_client_data * pull_out_cb * push_in_client_data * push_in_cb */ w = (GtkWidget *)cb_data[2]; /* Not in place (pulled out)? */ if(!((gint)cb_data[7])) { GUIPullOutCloseCB( (GtkWidget *)cb_data[2], NULL, (gpointer)cb_data ); } } }