netscape-revival
cmd/xfe/quickfile.c
/* -*- Mode: C; tab-width: 8 -*-
quickfile.c --- facilities for the quick file bookmark button/menu
Copyright © 1995 Netscape Communications Corporation, all rights reserved.
Created: Chris Toshok <toshok@netscape.com>, 10-Jun-96.
*/
#include "mozilla.h"
#include "xfe.h"
#include "quickfile.h"
#include "bkmks.h"
#include "felocale.h"
#include "xp_trace.h"
#include <X11/IntrinsicP.h> /* for w->core.height */
#include <Xm/Xm.h>
#include <Xm/Label.h>
#include <Xm/MenuShell.h>
#include <Xm/MenuUtilP.h>
#include <Xm/RowColumn.h>
#include <XmL/Grid.h>
#ifndef _STDC_
#define _STDC_ 1
#define HACKED_STDC 1
#endif
#ifdef HACKED_STDC
#undef HACKED_STDC
#undef _STDC_
#endif
/* the event mask for the pointer grabs we do */
#define Events ((unsigned int) (ButtonPressMask | ButtonMotionMask | \
ButtonReleaseMask | \
EnterWindowMask | LeaveWindowMask))
#include "icons.h"
#include "icondata.h"
#include <xpgetstr.h>
extern int XFE_BM_ALIAS;
extern int XFE_ESTIMATED_TIME_REMAINING;
extern int XFE_ESTIMATED_TIME_REMAINING_CHECKED;
extern int XFE_ESTIMATED_TIME_REMAINING_CHECKING;
extern int XFE_DONE_CHECKING_ETC;
extern int XFE_GG_EMPTY_LL;
extern int XFE_LOOK_FOR_DOCUMENTS_THAT_HAVE_CHANGED_ON;
extern MWContext* main_bm_context;
typedef struct qf_bookmark_struct qf_bookmark;
typedef struct qf_popup_struct qf_popup;
static void fe_qf_cell_draw_callback(Widget w, XtPointer client_data, XtPointer call_data);
static void fe_qf_select_cell_callback(Widget w, XtPointer client_data, XtPointer call_data);
static void fe_qf_activate_cell_callback(Widget w, XtPointer client_data, XtPointer call_data);
static void fe_qf_initial_post_handler(Widget w, XtPointer client_data, XEvent *event, Boolean *cont);
static void fe_qf_button_release_handler(Widget w, XtPointer client_data, XEvent *event, Boolean *cont);
static qf_popup *fe_qf_popup_create(MWContext *context, Widget parent_shell, Arg *av, int ac);
static void fe_qf_unpost_submenus(qf_popup *popup);
static void fe_qf_unpost_all(qf_popup *popup);
static void fe_qf_unpost_submenu(qf_bookmark *bookmark);
static void fe_qf_post_submenu(qf_bookmark *bookmark);
static void fe_qf_generate_menu_hook(fe_QuickFile quickfile);
static void fe_qf_add_menu_items (qf_popup *popup, MWContext *bm_context,
BM_Entry *entry);
static void fe_qf_add_child(qf_bookmark *bookmark, int position);
/* hooks used in traversing through the menus */
static void fe_qf_disarm_hook(qf_bookmark *bookmark);
static void fe_qf_arm_hook(qf_bookmark *bookmark);
static void fe_qf_activate_hook(qf_bookmark *bookmark);
static void fe_qf_fill_in_menu_hook(qf_bookmark *cascade);
/* The equivalent of the MenuShell/RowColumn combination in motif. */
struct qf_popup_struct {
MWContext *context; /* the context we're in */
Boolean popped_up; /* whether we're popped up or not */
Widget shell; /* our containing shell */
Widget rc;
Widget grid; /* the actual list of bookmarks */
qf_bookmark *bookmark; /* our parent in the cascade. Useful
for unposting the entire cascade. */
qf_bookmark *active; /* the currently active child. */
int active_index;
qf_bookmark **children;
int num_children;
int num_children_alloc;
};
/* The equivalent of the cascade button for the quickfile menu. */
struct qf_bookmark_struct {
Position x;
Position y;
Position width;
Position height;
char *name; /* the string we display */
qf_popup *parent_pane; /* the pane we appear in. */
qf_popup *submenu; /* the pane we pop up. */
BM_Entry *entry; /* the entry associated with a submenu */
void (*activate_hook)(qf_bookmark *); /* callback of sorts. */
void (*arm_hook)(qf_bookmark *); /* callback of sorts. */
void (*disarm_hook)(qf_bookmark *); /* callback of sorts. */
void (*cascade_hook)(qf_bookmark *); /* callback of sorts. */
};
/* This is the fe_QuickFile structure, typedef'ed in quickfile.h */
struct fe_qf_struct {
MWContext *context; /* the context we're in */
Widget button; /* the button that starts it all. */
qf_popup *initial_popup; /* our toplevel menu. */
Boolean menu_up_to_date_p; /* whether or not we should recreate the toplevel
menu */
XtIntervalId popdown_timer; /* used when dragging */
void (*popup_hook)(fe_QuickFile); /* callback of sorts. */
};
static fe_icon pixmapFolderClosed = { 0 };
static fe_icon pixmapFolderOpen = { 0 };
static fe_icon pixmapBookmark = { 0 };
static void
PixmapDraw(Widget w, Pixmap pixmap, Pixmap mask,
int pixmapWidth, int pixmapHeight, unsigned char alignment, GC gc,
XRectangle *rect, XRectangle *clipRect)
{
Display *dpy;
Window win;
int needsClip;
int x, y, width, height;
if (pixmap == XmUNSPECIFIED_PIXMAP) return;
if (rect->width <= 4 || rect->height <= 4) return;
if (clipRect->width < 3 || clipRect->height < 3) return;
if (!XtIsRealized(w)) return;
dpy = XtDisplay(w);
win = XtWindow(w);
width = pixmapWidth;
height = pixmapHeight;
if (!width || !height) {
alignment = XmALIGNMENT_TOP_LEFT;
width = clipRect->width - 4;
height = clipRect->height - 4;
}
if (alignment == XmALIGNMENT_TOP_LEFT ||
alignment == XmALIGNMENT_LEFT ||
alignment == XmALIGNMENT_BOTTOM_LEFT) {
x = rect->x + 2;
} else if (alignment == XmALIGNMENT_TOP ||
alignment == XmALIGNMENT_CENTER ||
alignment == XmALIGNMENT_BOTTOM) {
x = rect->x + ((int)rect->width - width) / 2;
} else {
x = rect->x + rect->width - width - 2;
}
if (alignment == XmALIGNMENT_TOP ||
alignment == XmALIGNMENT_TOP_LEFT ||
alignment == XmALIGNMENT_TOP_RIGHT) {
y = rect->y + 2;
} else if (alignment == XmALIGNMENT_LEFT ||
alignment == XmALIGNMENT_CENTER ||
alignment == XmALIGNMENT_RIGHT) {
y = rect->y + ((int)rect->height - height) / 2;
} else {
y = rect->y + rect->height - height - 2;
}
needsClip = 1;
if (clipRect->x <= x &&
clipRect->y <= y &&
clipRect->x + clipRect->width >= x + width &&
clipRect->y + clipRect->height >= y + height) {
needsClip = 0;
}
if (needsClip) {
XSetClipRectangles(dpy, gc, 0, 0, clipRect, 1, Unsorted);
} else if (mask) {
XSetClipMask(dpy, gc, mask);
XSetClipOrigin(dpy, gc, x, y);
}
XSetGraphicsExposures(dpy, gc, False);
XCopyArea(dpy, pixmap, win, gc, 0, 0, width, height, x, y);
XSetGraphicsExposures(dpy, gc, True);
if (needsClip || mask) {
XSetClipMask(dpy, gc, None);
}
}
Widget
fe_QuickFile_Button(fe_QuickFile quickfile)
{
return quickfile->button;
}
fe_QuickFile
fe_QuickFile_Create(MWContext *context,
Widget parent)
{
fe_QuickFile quickfile = (fe_QuickFile)XtMalloc(sizeof(struct fe_qf_struct));
quickfile->context = context;
quickfile->button = XtVaCreateManagedWidget("QFile",
xmLabelWidgetClass,
parent,
NULL);
XtAddEventHandler(quickfile->button,
ButtonPressMask,
False,
fe_qf_initial_post_handler,
quickfile);
quickfile->initial_popup = fe_qf_popup_create(context, CONTEXT_WIDGET(context), NULL, 0);
quickfile->menu_up_to_date_p = False; /* so the hook will generate the
menu the first time through */
quickfile->popup_hook = fe_qf_generate_menu_hook;
/* now we generate the pixmaps */
if (!pixmapFolderOpen.pixmap)
{
Pixel bg_pixel;
XtVaGetValues(quickfile->initial_popup->grid, XmNbackground, &bg_pixel, NULL);
fe_MakeIcon(context, bg_pixel, &pixmapFolderClosed, NULL,
HHdr.width, HHdr.height,
HHdr.mono_bits, HHdr.color_bits, HHdr.mask_bits,
FALSE);
fe_MakeIcon(context, bg_pixel, &pixmapFolderOpen, NULL,
HHdrO.width, HHdrO.height,
HHdrO.mono_bits, HHdrO.color_bits, HHdrO.mask_bits,
FALSE);
fe_MakeIcon(context, bg_pixel, &pixmapBookmark, NULL,
HBkm.width, HBkm.height,
HBkm.mono_bits, HBkm.color_bits, HBkm.mask_bits,
FALSE);
}
return quickfile;
}
void
fe_QuickFile_Destroy(fe_QuickFile quickfile)
{
/* do nothing for now.. -- major memory leak. FIX ME */
}
void
fe_QuickFile_Invalidate(fe_QuickFile quickfile)
{
if (quickfile)
quickfile->menu_up_to_date_p = 0;
}
/* This functions pops down _all_ popups on the screen. */
static void
fe_qf_unpost_all(qf_popup *popup)
{
/* first we find the root */
while (popup->bookmark)
{
popup = popup->bookmark->parent_pane;
}
/* then we popdown all our children. */
fe_qf_unpost_submenus(popup);
/* then we unpost the root pane. */
XtPopdown(popup->shell);
/* and marked it as being down. */
popup->popped_up = False;
/* disable selection in the grid widget */
XtCallActionProc(popup->grid,
"MenuDisarm",
NULL, NULL, 0);
}
/* This function pops down all the menu panes in the
cascade below -- but not including -- the one
passed as the parameter. */
static void
fe_qf_unpost_submenus(qf_popup *popup)
{
qf_bookmark *active_bookmark = popup->active;
XP_ASSERT(popup != NULL);
if (active_bookmark)
{
fe_qf_unpost_submenu(active_bookmark);
popup->active = NULL;
}
}
static void
fe_qf_unpost_submenu(qf_bookmark *bookmark)
{
/* if we don't have a submenu. */
if (!bookmark->submenu)
return;
/* if it's not popped up. */
if (!bookmark->submenu->popped_up)
return;
/* pop down the submenus of this one. */
fe_qf_unpost_submenus(bookmark->submenu);
/* disable selection in the grid widget */
#ifdef DEBUG_toshok
XP_Trace(" disabling selection in the popped up grid\n");
#endif
XtCallActionProc(bookmark->submenu->grid,
"MenuDisarm",
NULL, NULL, 0);
/* then pop down this menu */
XtPopdown(bookmark->submenu->shell);
bookmark->submenu->popped_up = False;
}
void
fe_qf_post_submenu(qf_bookmark *bookmark)
{
XRectangle rect;
Dimension st = 0;
/* if we don't have a submenu. */
if (!bookmark->submenu)
return;
/* if it's not popped up already */
if (bookmark->submenu->popped_up)
return;
/* save off the cascade that popped us off, used in the popup_hook. */
bookmark->submenu->bookmark = bookmark;
/* call the popup's hook */
if (bookmark->cascade_hook)
(*bookmark->cascade_hook)(bookmark);
/* move the shell to the right place - we subtract the shadow
thickness so the highlighted rectangles for the folder and the
first item in the submenu line up... you know, it's the little
things that make the world go 'round */
XmLGridRowColumnToXY(bookmark->parent_pane->grid,
XmCONTENT, bookmark->parent_pane->active_index,
XmCONTENT, 0,
False, &rect);
XtVaGetValues(bookmark->submenu->grid,
XmNshadowThickness, &st,
NULL);
XtMoveWidget(bookmark->submenu->shell,
bookmark->parent_pane->shell->core.x + bookmark->parent_pane->shell->core.width,
bookmark->parent_pane->shell->core.y + rect.y - st);
/* pop up the shell */
XtPopup(bookmark->submenu->shell, XtGrabNonexclusive);
bookmark->submenu->popped_up = True;
#ifdef DEBUG_toshok
XP_Trace(" Enabling traversal in the popped up grid\n");
#endif
XtCallActionProc(bookmark->submenu->grid,
"MenuArm",
NULL, NULL, 0);
}
/* This method gets called just before the initial pane is posted,
giving us time to generate the information that will go in it. */
static void
fe_qf_generate_menu_hook(fe_QuickFile quickfile)
{
qf_popup *popup;
MWContext *bm_context;
BM_Entry *entry;
XP_ASSERT(quickfile->initial_popup != NULL);
#ifdef DEBUG_toshok
XP_Trace("Inside fe_qf_generate_menu_hook()\n");
#endif
if (quickfile->menu_up_to_date_p)
return;
popup = quickfile->initial_popup;
bm_context = main_bm_context; /* ### */
if (popup == NULL || quickfile->menu_up_to_date_p)
return;
/* first we need to destroy all the children off the popup */
#ifdef DEBUG_toshok
XP_Trace(" Destroying current children of popup\n");
#endif
if (popup->num_children)
{
/* fe_qf_PopupDestroyChildren(popup);*/
}
entry = BM_GetMenuHeader(bm_context);
if (entry)
{
/* this is a bit of a hack, but we don't want to create
* a submenu for the top header, "Joe's Bookmarks". instead
* we jump to the children.
*/
if (BM_IsHeader(entry)) entry = BM_GetChildren(entry);
#ifdef DEBUG_toshok
XP_Trace(" Adding new menu entries\n");
#endif
if (entry)
fe_qf_add_menu_items (popup, bm_context, entry);
}
/* XtRealizeWidget (popup);*/
#ifdef DEBUG_toshok
XP_Trace(" Setting up to date flag to true\n");
#endif
quickfile->menu_up_to_date_p = True;
}
static void
fe_qf_fill_in_menu_hook(qf_bookmark *cascade)
{
MWContext* bm_context = main_bm_context; /* ### */
BM_Entry* entry = cascade->entry;
#ifdef DEBUG_toshok
XP_Trace("Inside fe_qf_fill_in_menu_hook()\n");
#endif
if (entry)
{
XP_ASSERT(BM_IsHeader(entry));
if (cascade->submenu)
{
#ifdef DEBUG_toshok
XP_Trace(" adding menu items to submenu\n");
#endif
fe_qf_add_menu_items(cascade->submenu, bm_context,
BM_GetChildren(entry));
}
#ifdef DEBUG_toshok
XP_Trace(" setting entry to NULL\n");
#endif
cascade->entry = NULL;
}
}
static qf_popup *
fe_qf_popup_create(MWContext *context,
Widget parent_shell,
Arg *av, int ac)
{
qf_popup *new_popup = (qf_popup*)XtMalloc(sizeof(qf_popup));
Arg *new_arglist;
Arg av2[10];
int ac2;
Visual *v;
Colormap cmap;
Cardinal depth;
new_popup->context = context;
new_popup->popped_up = False;
XtVaGetValues(CONTEXT_WIDGET(context),
XmNdepth, &depth,
XmNcolormap, &cmap,
XmNvisual, &v,
NULL);
ac2 = 0;
XtSetArg(av2[ac2], XmNdepth, depth); ac2++;
XtSetArg(av2[ac2], XmNcolormap, cmap); ac2++;
XtSetArg(av2[ac2], XmNvisual, v); ac2++;
XtSetArg(av2[ac2], XmNwidth, 120); ac2++;
XtSetArg(av2[ac2], XmNheight, 100); ac2++;
XtSetArg(av2[ac2], XtNallowShellResize, True); ac2++;
new_arglist = XtMergeArgLists(av, ac, av2, ac2);
new_popup->shell = XtCreatePopupShell("quickfilePopup",
xmMenuShellWidgetClass,
parent_shell,
new_arglist, ac + ac2);
XtUninstallTranslations(new_popup->shell);
new_popup->rc = XtVaCreateWidget("rc",
xmRowColumnWidgetClass,
new_popup->shell,
XmNmarginHeight, 0,
XmNmarginWidth, 0,
NULL);
XtUnmanageChild(new_popup->rc);
new_popup->grid = XtVaCreateManagedWidget("grid",
xmlGridWidgetClass,
new_popup->rc,
XmNuseTextWidget, False,
XmNrows, 0,
XmNcolumns, 2,
XmNsimpleWidths, "3c 30c",
XmNhorizontalSizePolicy, XmVARIABLE,
XmNverticalSizePolicy, XmVARIABLE,
XmNselectionPolicy, XmSELECT_BROWSE_ROW,
XmNautoSelect, False,
XmNshadowType, XmSHADOW_OUT,
NULL);
/* now we set the cell defaults. */
XtVaSetValues(new_popup->grid,
XmNcellDefaults, True,
XmNcellLeftBorderType, XmBORDER_NONE,
XmNcellRightBorderType, XmBORDER_NONE,
XmNcellTopBorderType, XmBORDER_NONE,
XmNcellBottomBorderType, XmBORDER_NONE,
XmNcellAlignment, XmALIGNMENT_LEFT,
NULL);
XtAddCallback(new_popup->grid, XmNcellDrawCallback, fe_qf_cell_draw_callback, new_popup);
XtAddCallback(new_popup->grid, XmNselectCallback, fe_qf_select_cell_callback, new_popup);
XtAddCallback(new_popup->grid, XmNactivateCallback, fe_qf_activate_cell_callback, new_popup);
XtManageChild(new_popup->rc);
new_popup->num_children = 0;
new_popup->num_children_alloc = 4;
new_popup->children = (qf_bookmark**)XtMalloc(sizeof(qf_bookmark*)
* new_popup->num_children_alloc);
new_popup->bookmark =
new_popup->active = NULL;
return new_popup;
}
static qf_bookmark *
fe_qf_BookmarkCreate(qf_popup *parent,
char *name,
qf_popup *submenu,
BM_Entry *entry)
{
qf_bookmark *new_bookmark = (qf_bookmark*)XtMalloc(sizeof(qf_bookmark));
new_bookmark->x =
new_bookmark->y =
new_bookmark->width =
new_bookmark->height = -1;
new_bookmark->activate_hook =
new_bookmark->cascade_hook =
new_bookmark->arm_hook =
new_bookmark->disarm_hook = NULL;
new_bookmark->name = strdup(name);
new_bookmark->parent_pane = parent;
new_bookmark->entry = entry;
new_bookmark->submenu = submenu;
return new_bookmark;
}
static void
fe_qf_add_child(qf_bookmark *bookmark, int position)
{
qf_popup *popup = bookmark->parent_pane;
int rows;
#ifdef DEBUG_toshok
XP_Trace("Inside fe_qf_add_child()\n");
#endif
popup->children[popup->num_children++] = bookmark;
if (popup->num_children == popup->num_children_alloc)
{
popup->num_children_alloc *= 2;
popup->children = (qf_bookmark**)XtRealloc((char*)popup->children,
popup->num_children_alloc
* sizeof(qf_bookmark*));
}
#ifdef DEBUG_toshok
XP_Trace(" Adding a new row\n");
#endif
XmLGridAddRows(bookmark->parent_pane->grid,
XmCONTENT, position, 1);
if (position == -1)
position = popup->num_children - 1;
#ifdef DEBUG_toshok
XP_Trace(" Setting the string '%s' at the position %d\n",
bookmark->name,
position);
#endif
XmLGridSetStringsPos(bookmark->parent_pane->grid,
XmCONTENT, position, XmCONTENT,
1, bookmark->name);
}
static void
fe_qf_button_release_handler(Widget w,
XtPointer client_data,
XEvent *event,
Boolean *cont)
{
fe_QuickFile quickfile = (fe_QuickFile)client_data;
#ifdef DEBUG_toshok
XP_Trace("Inside fe_qf_button_release_handler\n");
XP_Trace(" popping down entire quickfile menu\n");
#endif
fe_qf_unpost_all(quickfile->initial_popup);
/* ungrab the pointer. */
XtUngrabPointer(w, CurrentTime);
}
static void
fe_qf_initial_post_handler(Widget w,
XtPointer client_data,
XEvent *event,
Boolean *cont)
{
fe_QuickFile quickfile = (fe_QuickFile)client_data;
Position x_root, y_root;
String param[1];
#ifdef DEBUG_toshok
XP_Trace("Inside fe_qf_initial_post_handler()\n");
#endif
/* we only do stuff on button 1 press. */
if (event->xbutton.button != 1)
return;
/* There should always be a popup. */
XP_ASSERT(quickfile->initial_popup != NULL);
/* It should never be popped up if we're here. */
XP_ASSERT(quickfile->initial_popup->popped_up == False);
/* call the quickfile button's initial hook */
#ifdef DEBUG_toshok
XP_Trace(" Calling popup_hook\n");
#endif
if (quickfile->popup_hook)
(*quickfile->popup_hook)(quickfile);
#ifdef DEBUG_toshok
XP_Trace(" Calling XtTranslateCoords()\n");
#endif
XtTranslateCoords(quickfile->button, 0, 0, &x_root, &y_root);
#ifdef DEBUG_toshok
XP_Trace(" Calling XtMoveWidget()\n");
#endif
XtMoveWidget(quickfile->initial_popup->shell,
x_root + quickfile->button->core.width,
y_root);
#ifdef DEBUG_toshok
XP_Trace(" adding button release event handler\n");
#endif
XtAddEventHandler(quickfile->initial_popup->shell,
ButtonReleaseMask, False, fe_qf_button_release_handler,
(XtPointer) quickfile);
#ifdef DEBUG_toshok
XP_Trace(" Calling XtPopupSpringLoaded()\n");
#endif
/* XtPopup(quickfile->initial_popup->shell, XtGrabExclusive);*/
XtPopupSpringLoaded(quickfile->initial_popup->shell);
_XmGrabPointer(quickfile->initial_popup->grid, True, Events,
GrabModeSync, GrabModeAsync, None,
XmGetMenuCursor(XtDisplay(quickfile->initial_popup->grid)),
CurrentTime);
XAllowEvents(XtDisplay(quickfile->initial_popup->grid), SyncPointer, CurrentTime);
#ifdef DEBUG_toshok
XP_Trace(" Setting popped_up to true\n");
#endif
quickfile->initial_popup->popped_up = True;
#ifdef DEBUG_toshok
XP_Trace(" Enabling traversal in the popped up grid\n");
#endif
XtCallActionProc(quickfile->initial_popup->grid,
"MenuArm",
NULL, NULL, 0);
}
static void
fe_qf_add_menu_items (qf_popup *popup,
MWContext *bm_context,
BM_Entry *entry)
{
Widget button;
Arg av [20];
int ac;
Visual *v = 0;
Colormap cmap = 0;
Cardinal depth = 0;
#ifdef DEBUG_toshok
XP_Trace("Inside fe_qf_add_menu_items()\n");
#endif
XtVaGetValues (popup->shell, XtNvisual, &v,
XtNcolormap, &cmap, XtNdepth, &depth, 0);
while (entry)
{
qf_bookmark *bookmark;
char *bm_name = BM_GetName(entry);
if (BM_IsHeader(entry))
{
qf_popup *submenu;
#ifdef DEBUG_toshok
XP_Trace(" Adding new folder\n");
#endif
ac = 0;
if (BM_GetChildren(entry))
{
ac = 0;
XtSetArg (av[ac], XmNvisual, v); ac++;
XtSetArg (av[ac], XmNcolormap, cmap); ac++;
XtSetArg (av[ac], XmNdepth, depth); ac++;
submenu = fe_qf_popup_create(popup->context, popup->shell, av, ac);
}
else
{
submenu = 0;
}
bookmark = fe_qf_BookmarkCreate(popup,
bm_name,
submenu,
entry);
bookmark->arm_hook = fe_qf_arm_hook;
bookmark->disarm_hook = fe_qf_disarm_hook;
bookmark->activate_hook = fe_qf_activate_hook;
bookmark->cascade_hook = fe_qf_fill_in_menu_hook;
fe_qf_add_child(bookmark, -1);
}
else if (BM_IsSeparator(entry))
{
#ifdef DEBUG_toshok
XP_Trace(" Adding new separator\n");
#endif
bookmark = fe_qf_BookmarkCreate(popup,
"-------------------------",
NULL,
NULL);
fe_qf_add_child(bookmark, -1);
}
else
{
#ifdef DEBUG_toshok
XP_Trace(" Adding new bookmark\n");
#endif
bookmark = fe_qf_BookmarkCreate(popup,
bm_name,
NULL,
entry);
bookmark->arm_hook = fe_qf_arm_hook;
bookmark->disarm_hook = fe_qf_disarm_hook;
bookmark->activate_hook = fe_qf_activate_hook;
fe_qf_add_child(bookmark, -1);
}
entry = BM_GetNext(entry);
}
}
static void
fe_qf_activate_hook (qf_bookmark *bookmark)
{
MWContext *context = bookmark->parent_pane->context;
BM_Entry *entry = bookmark->entry;
URL_Struct *url;
/* pop everything down */
fe_qf_unpost_all(bookmark->parent_pane);
if (bookmark->submenu == NULL)
{
fe_UserActivity(context);
if (!entry || !(BM_IsAlias(entry) || BM_IsUrl(entry)))
return;
url = NET_CreateURLStruct (BM_GetAddress(entry), FALSE);
/* item->last_visit = time ((time_t *) 0); ### */
/* fe_BookmarkAccessTimeChanged (context, item); ### */
fe_GetURL (context, url, FALSE);
}
else
{
/* do special stuff if we're in a cascade button -- tear off thingy */
}
}
static void
fe_qf_arm_hook(qf_bookmark *bookmark)
{
MWContext *context = bookmark->parent_pane->context;
BM_Entry *entry = bookmark->entry;
fe_UserActivity(context);
/* if we're a folder, we post our submenu when we're armed. */
fe_qf_post_submenu(bookmark);
if (!entry || !(BM_IsAlias(entry) || BM_IsUrl(entry)))
return;
XFE_Progress(context, BM_GetAddress(entry));
}
static void
fe_qf_disarm_hook(qf_bookmark *bookmark)
{
MWContext *context = bookmark->parent_pane->context;
/* if we're a folder, we unpost our submenu when we're disarmed. */
fe_qf_unpost_submenu(bookmark);
XFE_Progress(context, "");
}
static void
fe_qf_cell_draw_callback(Widget w, XtPointer client_data, XtPointer call_data)
{
qf_popup *popup = (qf_popup*)client_data;
XmLGridCallbackStruct* call = (XmLGridCallbackStruct*) call_data;
XmLGridDrawStruct *draw = call->drawInfo;
Boolean drawSelected = draw->drawSelected;
qf_bookmark *bookmark = popup->children[call->row];
fe_icon* data = NULL;
XRectangle r;
if (call->column == 0) /* here we're drawing the icon. */
{
if (bookmark->submenu)
{
if (drawSelected)
data = &pixmapFolderOpen;
else
data = &pixmapFolderClosed;
}
else
{
data = &pixmapBookmark;
}
r = *draw->cellRect;
r.width = data->width;
PixmapDraw(w, data->pixmap, data->mask, data->width, data->height,
XmALIGNMENT_LEFT, draw->gc, &r, call->clipRect);
}
}
static void
fe_qf_activate_cell_callback(Widget w, XtPointer client_data, XtPointer call_data)
{
qf_popup *popup = (qf_popup*)client_data;
XmLGridCallbackStruct *cbs = (XmLGridCallbackStruct*)call_data;
#ifdef DEBUG_toshok
XP_Trace("Inside fe_qf_activate_cell_callback()\n");
#endif
popup->active = popup->children[cbs->row];
popup->active_index = cbs->row;
/* and call it's arm hook if it has one. */
#ifdef DEBUG_toshok
XP_Trace(" calling activate_hook.\n");
#endif
if (popup->active
&& popup->active->activate_hook)
popup->active->activate_hook(popup->active);
}
static void
fe_qf_select_cell_callback(Widget w, XtPointer client_data, XtPointer call_data)
{
qf_popup *popup = (qf_popup*)client_data;
XmLGridCallbackStruct *cbs = (XmLGridCallbackStruct*)call_data;
#ifdef DEBUG_toshok
XP_Trace("Inside fe_qf_select_cell_callback()\n");
#endif
/* first we disarm the currently active bookmark, if there is one. */
#ifdef DEBUG_toshok
XP_Trace(" calling disarm_hook.\n");
#endif
if (popup->active
&& popup->active->disarm_hook)
popup->active->disarm_hook(popup->active);
/* then switch to the new item. */
popup->active = popup->children[cbs->row];
popup->active_index = cbs->row;
/* and call it's arm hook if it has one. */
#ifdef DEBUG_toshok
XP_Trace(" calling arm_hook\n");
#endif
if (popup->active
&& popup->active->arm_hook)
popup->active->arm_hook(popup->active);
}