folder.c revision d859ff80
1c9e2be55Smrg/* 2c9e2be55Smrg * $XConsortium: folder.c,v 2.44 94/08/29 20:25:49 swick Exp $ 3c9e2be55Smrg * 4c9e2be55Smrg * 5c9e2be55Smrg * COPYRIGHT 1987, 1989 6c9e2be55Smrg * DIGITAL EQUIPMENT CORPORATION 7c9e2be55Smrg * MAYNARD, MASSACHUSETTS 8c9e2be55Smrg * ALL RIGHTS RESERVED. 9c9e2be55Smrg * 10c9e2be55Smrg * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND 11c9e2be55Smrg * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. 12c9e2be55Smrg * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR 13c9e2be55Smrg * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. 14c9e2be55Smrg * 15c9e2be55Smrg * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT 16c9e2be55Smrg * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN 17c9e2be55Smrg * ADDITION TO THAT SET FORTH ABOVE. 18c9e2be55Smrg * 19c9e2be55Smrg * Permission to use, copy, modify, and distribute this software and its 20c9e2be55Smrg * documentation for any purpose and without fee is hereby granted, provided 21c9e2be55Smrg * that the above copyright notice appear in all copies and that both that 22c9e2be55Smrg * copyright notice and this permission notice appear in supporting 23c9e2be55Smrg * documentation, and that the name of Digital Equipment Corporation not be 24c9e2be55Smrg * used in advertising or publicity pertaining to distribution of the software 25c9e2be55Smrg * without specific, written prior permission. 26c9e2be55Smrg */ 27c9e2be55Smrg/* $XFree86: xc/programs/xmh/folder.c,v 1.3 2001/10/28 03:34:38 tsi Exp $ */ 28c9e2be55Smrg 29c9e2be55Smrg/* folder.c -- implement buttons relating to folders and other globals. */ 30c9e2be55Smrg 31c9e2be55Smrg#include "xmh.h" 32c9e2be55Smrg#include <X11/Xmu/CharSet.h> 33c9e2be55Smrg#include <X11/Xaw/Cardinals.h> 34c9e2be55Smrg#include <X11/Xatom.h> 35c9e2be55Smrg#include <sys/stat.h> 36c9e2be55Smrg#include <ctype.h> 37c9e2be55Smrg#include "bboxint.h" 38c9e2be55Smrg#include "tocintrnl.h" 39c9e2be55Smrg#include "actions.h" 40c9e2be55Smrg 41c9e2be55Smrgtypedef struct { /* client data structure for callbacks */ 42c9e2be55Smrg Scrn scrn; /* the xmh scrn of action */ 43c9e2be55Smrg Toc toc; /* the toc of the selected folder */ 44c9e2be55Smrg Toc original_toc; /* the toc of the current folder */ 45c9e2be55Smrg} DeleteDataRec, *DeleteData; 46c9e2be55Smrg 47c9e2be55Smrg 48c9e2be55Smrgstatic void CheckAndDeleteFolder(XMH_CB_ARGS); 49c9e2be55Smrgstatic void CancelDeleteFolder(XMH_CB_ARGS); 50c9e2be55Smrgstatic void CheckAndConfirmDeleteFolder(XMH_CB_ARGS); 51c9e2be55Smrgstatic void FreeMenuData(XMH_CB_ARGS); 52c9e2be55Smrgstatic void CreateFolderMenu(Button); 53c9e2be55Smrgstatic void AddFolderMenuEntry(Button, char *); 54c9e2be55Smrgstatic void DeleteFolderMenuEntry(Button, char *); 55c9e2be55Smrg 56c9e2be55Smrg#ifdef DEBUG_CLEANUP 57c9e2be55Smrgextern Boolean ExitLoop; 58c9e2be55Smrg#endif 59c9e2be55Smrg 60c9e2be55Smrg/* Close this toc&view scrn. If this is the last toc&view, quit xmh. */ 61c9e2be55Smrg 62c9e2be55Smrg/*ARGSUSED*/ 63c9e2be55Smrgvoid DoClose( 64c9e2be55Smrg Widget widget, 65c9e2be55Smrg XtPointer client_data, 66c9e2be55Smrg XtPointer call_data) 67c9e2be55Smrg{ 68c9e2be55Smrg Scrn scrn = (Scrn) client_data; 69c9e2be55Smrg register int i, count; 70c9e2be55Smrg Toc toc; 71c9e2be55Smrg XtCallbackRec confirm_callbacks[2]; 72c9e2be55Smrg 73c9e2be55Smrg count = 0; 74c9e2be55Smrg for (i=0 ; i<numScrns ; i++) 75c9e2be55Smrg if (scrnList[i]->kind == STtocAndView && scrnList[i]->mapped) 76c9e2be55Smrg count++; 77c9e2be55Smrg 78c9e2be55Smrg confirm_callbacks[0].callback = (XtCallbackProc) DoClose; 79c9e2be55Smrg confirm_callbacks[0].closure = (XtPointer) scrn; 80c9e2be55Smrg confirm_callbacks[1].callback = (XtCallbackProc) NULL; 81c9e2be55Smrg confirm_callbacks[1].closure = (XtPointer) NULL; 82c9e2be55Smrg 83c9e2be55Smrg if (count <= 1) { 84c9e2be55Smrg 85c9e2be55Smrg for (i = numScrns - 1; i >= 0; i--) 86c9e2be55Smrg if (scrnList[i] != scrn) { 87c9e2be55Smrg if (MsgSetScrn((Msg) NULL, scrnList[i], confirm_callbacks, 88c9e2be55Smrg (XtCallbackList) NULL) == NEEDS_CONFIRMATION) 89c9e2be55Smrg return; 90c9e2be55Smrg } 91c9e2be55Smrg for (i = 0; i < numFolders; i++) { 92c9e2be55Smrg toc = folderList[i]; 93c9e2be55Smrg 94c9e2be55Smrg if (TocConfirmCataclysm(toc, confirm_callbacks, 95c9e2be55Smrg (XtCallbackList) NULL)) 96c9e2be55Smrg return; 97c9e2be55Smrg } 98c9e2be55Smrg/* if (MsgSetScrn((Msg) NULL, scrn)) 99c9e2be55Smrg * return; 100c9e2be55Smrg * %%% 101c9e2be55Smrg * for (i = 0; i < numFolders; i++) { 102c9e2be55Smrg * toc = folderList[i]; 103c9e2be55Smrg * if (toc->scanfile && toc->curmsg) 104c9e2be55Smrg * CmdSetSequence(toc, "cur", MakeSingleMsgList(toc->curmsg)); 105c9e2be55Smrg * } 106c9e2be55Smrg */ 107c9e2be55Smrg 108c9e2be55Smrg#ifdef DEBUG_CLEANUP 109c9e2be55Smrg XtDestroyWidget(scrn->parent); 110c9e2be55Smrg ExitLoop = TRUE; 111c9e2be55Smrg return; 112c9e2be55Smrg#else 113c9e2be55Smrg XtVaSetValues(scrn->parent, XtNjoinSession, (XtArgVal)False, NULL); 114c9e2be55Smrg XtUnmapWidget(scrn->parent); 115c9e2be55Smrg XtDestroyApplicationContext 116c9e2be55Smrg (XtWidgetToApplicationContext(scrn->parent)); 117c9e2be55Smrg exit(0); 118c9e2be55Smrg#endif 119c9e2be55Smrg } 120c9e2be55Smrg else { 121d859ff80Smrg if (MsgSetScrn((Msg) NULL, scrn, confirm_callbacks, 122c9e2be55Smrg (XtCallbackList) NULL) == NEEDS_CONFIRMATION) 123c9e2be55Smrg return; 124c9e2be55Smrg DestroyScrn(scrn); /* doesn't destroy first toc&view scrn */ 125c9e2be55Smrg } 126c9e2be55Smrg} 127c9e2be55Smrg 128c9e2be55Smrg/*ARGSUSED*/ 129c9e2be55Smrgvoid XmhClose( 130c9e2be55Smrg Widget w, 131c9e2be55Smrg XEvent *event, /* unused */ 132c9e2be55Smrg String *params, /* unused */ 133c9e2be55Smrg Cardinal *num_params) /* unused */ 134c9e2be55Smrg{ 135c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 136c9e2be55Smrg DoClose(w, (XtPointer) scrn, (XtPointer) NULL); 137c9e2be55Smrg} 138c9e2be55Smrg 139c9e2be55Smrg/* Open the selected folder in this screen. */ 140c9e2be55Smrg 141c9e2be55Smrg/* ARGSUSED*/ 142c9e2be55Smrgvoid DoOpenFolder( 143c9e2be55Smrg Widget widget, 144c9e2be55Smrg XtPointer client_data, 145c9e2be55Smrg XtPointer call_data) 146c9e2be55Smrg{ 147c9e2be55Smrg /* Invoked by the Folder menu entry "Open Folder"'s notify action. */ 148c9e2be55Smrg 149c9e2be55Smrg Scrn scrn = (Scrn) client_data; 150c9e2be55Smrg Toc toc = SelectedToc(scrn); 151c9e2be55Smrg if (TocFolderExists(toc)) 152c9e2be55Smrg TocSetScrn(toc, scrn); 153c9e2be55Smrg else 154c9e2be55Smrg PopupError(scrn->parent, "Cannot open selected folder."); 155c9e2be55Smrg} 156c9e2be55Smrg 157c9e2be55Smrg 158c9e2be55Smrg/*ARGSUSED*/ 159c9e2be55Smrgvoid XmhOpenFolder( 160c9e2be55Smrg Widget w, 161c9e2be55Smrg XEvent *event, /* unused */ 162c9e2be55Smrg String *params, 163c9e2be55Smrg Cardinal *num_params) 164c9e2be55Smrg{ 165c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 166c9e2be55Smrg 167c9e2be55Smrg /* This action may be invoked from folder menu buttons or from folder 168c9e2be55Smrg * menus, as an action procedure on an event specified in translations. 169c9e2be55Smrg * In this case, the action will open a folder only if that folder 170c9e2be55Smrg * was actually selected from a folder button or menu. If the folder 171c9e2be55Smrg * was selected from a folder menu, the menu entry callback procedure, 172d859ff80Smrg * which changes the selected folder, and is invoked by the "notify" 173c9e2be55Smrg * action, must have already executed; and the menu entry "unhightlight" 174c9e2be55Smrg * action must execute after this action. 175c9e2be55Smrg * 176c9e2be55Smrg * This action does not execute if invoked as an accelerator whose 177d859ff80Smrg * source widget is a menu button or a folder menu. However, it 178c9e2be55Smrg * may be invoked as a keyboard accelerator of any widget other than 179c9e2be55Smrg * the folder menu buttons or the folder menus. In that case, it will 180c9e2be55Smrg * open the currently selected folder. 181c9e2be55Smrg * 182c9e2be55Smrg * If given a parameter, it will take it as the name of a folder to 183c9e2be55Smrg * select and open. 184c9e2be55Smrg */ 185c9e2be55Smrg 186c9e2be55Smrg if (! UserWantsAction(w, scrn)) return; 187c9e2be55Smrg if (*num_params) SetCurrentFolderName(scrn, params[0]); 188c9e2be55Smrg DoOpenFolder(w, (XtPointer) scrn, (XtPointer) NULL); 189c9e2be55Smrg} 190c9e2be55Smrg 191c9e2be55Smrg 192c9e2be55Smrg/* Compose a new message. */ 193c9e2be55Smrg 194c9e2be55Smrg/*ARGSUSED*/ 195c9e2be55Smrgvoid DoComposeMessage( 196c9e2be55Smrg Widget widget, 197c9e2be55Smrg XtPointer client_data, 198c9e2be55Smrg XtPointer call_data) 199c9e2be55Smrg{ 200c9e2be55Smrg Scrn scrn = NewCompScrn(); 201c9e2be55Smrg Msg msg = TocMakeNewMsg(DraftsFolder); 202c9e2be55Smrg MsgLoadComposition(msg); 203c9e2be55Smrg MsgSetTemporary(msg); 204c9e2be55Smrg MsgSetReapable(msg); 205c9e2be55Smrg MsgSetScrnForComp(msg, scrn); 206c9e2be55Smrg MapScrn(scrn); 207c9e2be55Smrg} 208c9e2be55Smrg 209d859ff80Smrg 210c9e2be55Smrg/*ARGSUSED*/ 211c9e2be55Smrgvoid XmhComposeMessage( 212c9e2be55Smrg Widget w, 213c9e2be55Smrg XEvent *event, /* unused */ 214c9e2be55Smrg String *params, /* unused */ 215c9e2be55Smrg Cardinal *num_params) /* unused */ 216c9e2be55Smrg{ 217c9e2be55Smrg DoComposeMessage(w, (XtPointer) NULL, (XtPointer) NULL); 218c9e2be55Smrg} 219c9e2be55Smrg 220c9e2be55Smrg 221c9e2be55Smrg/* Make a new scrn displaying the given folder. */ 222c9e2be55Smrg 223c9e2be55Smrg/*ARGSUSED*/ 224c9e2be55Smrgvoid DoOpenFolderInNewWindow( 225c9e2be55Smrg Widget widget, 226c9e2be55Smrg XtPointer client_data, 227c9e2be55Smrg XtPointer call_data) 228c9e2be55Smrg{ 229c9e2be55Smrg Scrn scrn = (Scrn) client_data; 230c9e2be55Smrg Toc toc = SelectedToc(scrn); 231c9e2be55Smrg if (TocFolderExists(toc)) { 232c9e2be55Smrg scrn = CreateNewScrn(STtocAndView); 233c9e2be55Smrg TocSetScrn(toc, scrn); 234c9e2be55Smrg MapScrn(scrn); 235d859ff80Smrg } else 236c9e2be55Smrg PopupError(scrn->parent, "Cannot open selected folder."); 237c9e2be55Smrg} 238c9e2be55Smrg 239c9e2be55Smrg 240c9e2be55Smrg/*ARGSUSED*/ 241c9e2be55Smrgvoid XmhOpenFolderInNewWindow( 242c9e2be55Smrg Widget w, 243c9e2be55Smrg XEvent *event, /* unused */ 244c9e2be55Smrg String *params, /* unused */ 245c9e2be55Smrg Cardinal *num_params) /* unused */ 246c9e2be55Smrg{ 247c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 248c9e2be55Smrg DoOpenFolderInNewWindow(w, (XtPointer) scrn, (XtPointer) NULL); 249c9e2be55Smrg} 250c9e2be55Smrg 251c9e2be55Smrg 252c9e2be55Smrg/* Create a new folder with the given name. */ 253c9e2be55Smrg 254c9e2be55Smrgstatic char *previous_label = NULL; 255c9e2be55Smrg/*ARGSUSED*/ 256c9e2be55Smrgstatic void CreateFolder( 257c9e2be55Smrg Widget widget, /* the okay button of the dialog widget */ 258c9e2be55Smrg XtPointer client_data, /* the dialog widget */ 259c9e2be55Smrg XtPointer call_data) 260c9e2be55Smrg{ 261c9e2be55Smrg Toc toc; 262c9e2be55Smrg register int i; 263c9e2be55Smrg char *name; 264c9e2be55Smrg Widget dialog = (Widget) client_data; 265c9e2be55Smrg Arg args[3]; 266c9e2be55Smrg char str[300], *label; 267c9e2be55Smrg 268c9e2be55Smrg name = XawDialogGetValueString(dialog); 269c9e2be55Smrg for (i=0 ; name[i] > ' ' ; i++) ; 270c9e2be55Smrg name[i] = '\0'; 271c9e2be55Smrg toc = TocGetNamed(name); 272c9e2be55Smrg if ((toc) || (i==0) || (name[0]=='/') || ((toc = TocCreateFolder(name)) 273c9e2be55Smrg == NULL)) { 274d859ff80Smrg if (toc) 275c9e2be55Smrg (void) sprintf(str, "Folder \"%s\" already exists. Try again.", 276c9e2be55Smrg name); 277c9e2be55Smrg else if (name[0]=='/') 278c9e2be55Smrg (void) sprintf(str, "Please specify folders relative to \"%s\".", 279c9e2be55Smrg app_resources.mail_path); 280d859ff80Smrg else 281c9e2be55Smrg (void) sprintf(str, "Cannot create folder \"%s\". Try again.", 282c9e2be55Smrg name); 283c9e2be55Smrg label = XtNewString(str); 284c9e2be55Smrg XtSetArg(args[0], XtNlabel, label); 285c9e2be55Smrg XtSetArg(args[1], XtNvalue, ""); 286c9e2be55Smrg XtSetValues(dialog, args, TWO); 287c9e2be55Smrg if (previous_label) 288c9e2be55Smrg XtFree(previous_label); 289c9e2be55Smrg previous_label = label; 290c9e2be55Smrg return; 291c9e2be55Smrg } 292c9e2be55Smrg for (i = 0; i < numScrns; i++) 293c9e2be55Smrg if (scrnList[i]->folderbuttons) { 294c9e2be55Smrg char *c; 295c9e2be55Smrg Button button; 296c9e2be55Smrg if ((c = strchr(name, '/'))) { /* if is subfolder */ 297c9e2be55Smrg c[0] = '\0'; 298c9e2be55Smrg button = BBoxFindButtonNamed(scrnList[i]->folderbuttons, 299c9e2be55Smrg name); 300c9e2be55Smrg c[0] = '/'; 301c9e2be55Smrg if (button) AddFolderMenuEntry(button, name); 302c9e2be55Smrg } 303c9e2be55Smrg else 304c9e2be55Smrg BBoxAddButton(scrnList[i]->folderbuttons, name, 305c9e2be55Smrg menuButtonWidgetClass, True); 306c9e2be55Smrg } 307c9e2be55Smrg DestroyPopup(widget, (XtPointer) XtParent(dialog), (XtPointer) NULL); 308c9e2be55Smrg} 309c9e2be55Smrg 310c9e2be55Smrg 311c9e2be55Smrg/* Create a new folder. Requires the user to name the new folder. */ 312c9e2be55Smrg 313c9e2be55Smrg/*ARGSUSED*/ 314c9e2be55Smrgvoid DoCreateFolder( 315c9e2be55Smrg Widget widget, /* unused */ 316c9e2be55Smrg XtPointer client_data, 317c9e2be55Smrg XtPointer call_data) /* unused */ 318c9e2be55Smrg{ 319c9e2be55Smrg Scrn scrn = (Scrn) client_data; 320c9e2be55Smrg PopupPrompt(scrn->parent, "Create folder named:", CreateFolder); 321c9e2be55Smrg} 322c9e2be55Smrg 323c9e2be55Smrg 324c9e2be55Smrg/*ARGSUSED*/ 325c9e2be55Smrgvoid XmhCreateFolder( 326c9e2be55Smrg Widget w, 327c9e2be55Smrg XEvent *event, /* unused */ 328c9e2be55Smrg String *params, /* unused */ 329c9e2be55Smrg Cardinal *num_params) /* unused */ 330c9e2be55Smrg{ 331c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 332c9e2be55Smrg DoCreateFolder(w, (XtPointer)scrn, (XtPointer)NULL); 333c9e2be55Smrg} 334c9e2be55Smrg 335c9e2be55Smrg 336c9e2be55Smrg/*ARGSUSED*/ 337c9e2be55Smrgstatic void CancelDeleteFolder( 338c9e2be55Smrg Widget widget, /* unused */ 339c9e2be55Smrg XtPointer client_data, 340c9e2be55Smrg XtPointer call_data) /* unused */ 341c9e2be55Smrg{ 342c9e2be55Smrg DeleteData deleteData = (DeleteData) client_data; 343c9e2be55Smrg 344c9e2be55Smrg TocClearDeletePending(deleteData->toc); 345c9e2be55Smrg 346c9e2be55Smrg /* When the delete request is made, the toc currently being viewed is 347c9e2be55Smrg * changed if necessary to be the toc under consideration for deletion. 348c9e2be55Smrg * Once deletion has been confirmed or cancelled, we revert to display 349c9e2be55Smrg * the toc originally under view, unless the toc originally under 350c9e2be55Smrg * view has been deleted. 351c9e2be55Smrg */ 352c9e2be55Smrg 353c9e2be55Smrg if (deleteData->original_toc != NULL) 354c9e2be55Smrg TocSetScrn(deleteData->original_toc, deleteData->scrn); 355c9e2be55Smrg XtFree((char *) deleteData); 356c9e2be55Smrg} 357c9e2be55Smrg 358c9e2be55Smrg 359c9e2be55Smrg/*ARGSUSED*/ 360c9e2be55Smrgstatic void CheckAndConfirmDeleteFolder( 361c9e2be55Smrg Widget widget, /* unreliable; sometimes NULL */ 362c9e2be55Smrg XtPointer client_data, /* data structure */ 363c9e2be55Smrg XtPointer call_data) /* unused */ 364c9e2be55Smrg{ 365c9e2be55Smrg DeleteData deleteData = (DeleteData) client_data; 366c9e2be55Smrg Scrn scrn = deleteData->scrn; 367c9e2be55Smrg Toc toc = deleteData->toc; 368c9e2be55Smrg char str[300]; 369c9e2be55Smrg XtCallbackRec confirms[2]; 370c9e2be55Smrg XtCallbackRec cancels[2]; 371c9e2be55Smrg 372c9e2be55Smrg static XtCallbackRec yes_callbacks[] = { 373c9e2be55Smrg {CheckAndDeleteFolder, (XtPointer) NULL}, 374c9e2be55Smrg {(XtCallbackProc) NULL, (XtPointer) NULL} 375c9e2be55Smrg }; 376c9e2be55Smrg 377c9e2be55Smrg static XtCallbackRec no_callbacks[] = { 378c9e2be55Smrg {CancelDeleteFolder, (XtPointer) NULL}, 379c9e2be55Smrg {(XtCallbackProc) NULL, (XtPointer) NULL} 380c9e2be55Smrg }; 381c9e2be55Smrg 382c9e2be55Smrg /* Display the toc of the folder to be deleted. */ 383c9e2be55Smrg 384c9e2be55Smrg TocSetScrn(toc, scrn); 385c9e2be55Smrg 386c9e2be55Smrg /* Check for pending delete, copy, move, or edits on messages in the 387c9e2be55Smrg * folder to be deleted, and ask for confirmation if they are found. 388c9e2be55Smrg */ 389c9e2be55Smrg 390c9e2be55Smrg confirms[0].callback = (XtCallbackProc) CheckAndConfirmDeleteFolder; 391c9e2be55Smrg confirms[0].closure = client_data; 392c9e2be55Smrg confirms[1].callback = (XtCallbackProc) NULL; 393c9e2be55Smrg confirms[1].closure = (XtPointer) NULL; 394d859ff80Smrg 395c9e2be55Smrg cancels[0].callback = (XtCallbackProc) CancelDeleteFolder; 396c9e2be55Smrg cancels[0].closure = client_data; 397c9e2be55Smrg cancels[1].callback = (XtCallbackProc) NULL; 398c9e2be55Smrg cancels[1].closure = (XtPointer) NULL; 399c9e2be55Smrg 400c9e2be55Smrg if (TocConfirmCataclysm(toc, confirms, cancels) == NEEDS_CONFIRMATION) 401c9e2be55Smrg return; 402c9e2be55Smrg 403c9e2be55Smrg /* Ask the user for confirmation on destroying the folder. */ 404c9e2be55Smrg 405c9e2be55Smrg yes_callbacks[0].closure = client_data; 406c9e2be55Smrg no_callbacks[0].closure = client_data; 407c9e2be55Smrg (void) sprintf(str, "Are you sure you want to destroy %s?", TocName(toc)); 408c9e2be55Smrg PopupConfirm(scrn->tocwidget, str, yes_callbacks, no_callbacks); 409c9e2be55Smrg} 410c9e2be55Smrg 411c9e2be55Smrg 412c9e2be55Smrg/*ARGSUSED*/ 413c9e2be55Smrgstatic void CheckAndDeleteFolder( 414c9e2be55Smrg Widget widget, /* unused */ 415c9e2be55Smrg XtPointer client_data, /* data structure */ 416c9e2be55Smrg XtPointer call_data) /* unused */ 417c9e2be55Smrg{ 418c9e2be55Smrg DeleteData deleteData = (DeleteData) client_data; 419c9e2be55Smrg Scrn scrn = deleteData->scrn; 420c9e2be55Smrg Toc toc = deleteData->toc; 421c9e2be55Smrg XtCallbackRec confirms[2]; 422c9e2be55Smrg XtCallbackRec cancels[2]; 423c9e2be55Smrg int i; 424c9e2be55Smrg char *foldername; 425d859ff80Smrg 426c9e2be55Smrg /* Check for changes occurring after the popup was first presented. */ 427c9e2be55Smrg 428c9e2be55Smrg confirms[0].callback = (XtCallbackProc) CheckAndConfirmDeleteFolder; 429c9e2be55Smrg confirms[0].closure = client_data; 430c9e2be55Smrg confirms[1].callback = (XtCallbackProc) NULL; 431c9e2be55Smrg confirms[1].closure = (XtPointer) NULL; 432d859ff80Smrg 433c9e2be55Smrg cancels[0].callback = (XtCallbackProc) CancelDeleteFolder; 434c9e2be55Smrg cancels[0].closure = client_data; 435c9e2be55Smrg cancels[1].callback = (XtCallbackProc) NULL; 436c9e2be55Smrg cancels[1].closure = (XtPointer) NULL; 437d859ff80Smrg 438c9e2be55Smrg if (TocConfirmCataclysm(toc, confirms, cancels) == NEEDS_CONFIRMATION) 439c9e2be55Smrg return; 440c9e2be55Smrg 441c9e2be55Smrg /* Delete. Restore the previously viewed toc, if it wasn't deleted. */ 442c9e2be55Smrg 443c9e2be55Smrg foldername = TocName(toc); 444c9e2be55Smrg TocSetScrn(toc, (Scrn) NULL); 445c9e2be55Smrg TocDeleteFolder(toc); 446c9e2be55Smrg for (i=0 ; i<numScrns ; i++) 447c9e2be55Smrg if (scrnList[i]->folderbuttons) { 448c9e2be55Smrg 449c9e2be55Smrg if (IsSubfolder(foldername)) { 450c9e2be55Smrg char parent_folder[300]; 451c9e2be55Smrg char *c = strchr( strcpy(parent_folder, foldername), '/'); 452c9e2be55Smrg *c = '\0'; 453c9e2be55Smrg 454d859ff80Smrg/* Since menus are built upon demand, and are a per-xmh-screen resource, 455c9e2be55Smrg * not all xmh toc & view screens will have the same menus built. 456c9e2be55Smrg * So the menu entry deletion routines must be able to handle a button 457c9e2be55Smrg * whose menu field is null. It would be better to share folder menus 458c9e2be55Smrg * between xmh screens, but accelerators call action procedures which depend 459c9e2be55Smrg * upon being able to get the xmh screen (Scrn) from the widget argument. 460c9e2be55Smrg */ 461c9e2be55Smrg 462c9e2be55Smrg DeleteFolderMenuEntry 463c9e2be55Smrg ( BBoxFindButtonNamed( scrnList[i]->folderbuttons, 464d859ff80Smrg parent_folder), 465c9e2be55Smrg foldername); 466c9e2be55Smrg } 467c9e2be55Smrg else { 468c9e2be55Smrg BBoxDeleteButton 469c9e2be55Smrg (BBoxFindButtonNamed( scrnList[i]->folderbuttons, 470c9e2be55Smrg foldername)); 471c9e2be55Smrg } 472c9e2be55Smrg 473c9e2be55Smrg /* If we've deleted the current folder, show the Initial Folder */ 474c9e2be55Smrg 475d859ff80Smrg if ((! strcmp(scrnList[i]->curfolder, foldername)) 476c9e2be55Smrg && (BBoxNumButtons(scrnList[i]->folderbuttons)) 477c9e2be55Smrg && (strcmp(foldername, app_resources.initial_folder_name))) 478c9e2be55Smrg TocSetScrn(InitialFolder, scrnList[i]); 479c9e2be55Smrg } 480c9e2be55Smrg XtFree(foldername); 481d859ff80Smrg if (deleteData->original_toc != NULL) 482c9e2be55Smrg TocSetScrn(deleteData->original_toc, scrn); 483c9e2be55Smrg XtFree((char *) deleteData); 484c9e2be55Smrg} 485c9e2be55Smrg 486c9e2be55Smrg 487c9e2be55Smrg/* Delete the selected folder. Requires confirmation! */ 488c9e2be55Smrg 489c9e2be55Smrg/*ARGSUSED*/ 490c9e2be55Smrgvoid DoDeleteFolder( 491c9e2be55Smrg Widget w, 492c9e2be55Smrg XtPointer client_data, 493c9e2be55Smrg XtPointer call_data) 494c9e2be55Smrg{ 495c9e2be55Smrg Scrn scrn = (Scrn) client_data; 496c9e2be55Smrg Toc toc = SelectedToc(scrn); 497c9e2be55Smrg DeleteData deleteData; 498c9e2be55Smrg 499c9e2be55Smrg if (! TocFolderExists(toc)) { 500c9e2be55Smrg /* Too hard to clean up xmh when the folder doesn't exist anymore. */ 501c9e2be55Smrg PopupError(scrn->parent, 502c9e2be55Smrg "Cannot open selected folder for confirmation to delete."); 503c9e2be55Smrg return; 504c9e2be55Smrg } 505c9e2be55Smrg 506d859ff80Smrg /* Prevent more than one confirmation popup on the same folder. 507c9e2be55Smrg * TestAndSet returns true if there is a delete pending on this folder. 508c9e2be55Smrg */ 509c9e2be55Smrg if (TocTestAndSetDeletePending(toc)) { 510c9e2be55Smrg PopupError(scrn->parent, "There is a delete pending on this folder."); 511c9e2be55Smrg return; 512c9e2be55Smrg } 513c9e2be55Smrg 514c9e2be55Smrg deleteData = XtNew(DeleteDataRec); 515c9e2be55Smrg deleteData->scrn = scrn; 516c9e2be55Smrg deleteData->toc = toc; 517c9e2be55Smrg deleteData->original_toc = CurrentToc(scrn); 518c9e2be55Smrg if (deleteData->original_toc == toc) 519c9e2be55Smrg deleteData->original_toc = (Toc) NULL; 520c9e2be55Smrg 521c9e2be55Smrg CheckAndConfirmDeleteFolder(w, (XtPointer) deleteData, (XtPointer) NULL); 522c9e2be55Smrg} 523c9e2be55Smrg 524c9e2be55Smrg 525c9e2be55Smrg/*ARGSUSED*/ 526c9e2be55Smrgvoid XmhDeleteFolder( 527c9e2be55Smrg Widget w, 528c9e2be55Smrg XEvent *event, /* unused */ 529c9e2be55Smrg String *params, /* unused */ 530c9e2be55Smrg Cardinal *num_params) /* unused */ 531c9e2be55Smrg{ 532c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 533c9e2be55Smrg DoDeleteFolder(w, (XtPointer) scrn, (XtPointer) NULL); 534c9e2be55Smrg} 535c9e2be55Smrg 536c9e2be55Smrg 537c9e2be55Smrg/*----- Notes on MenuButtons as folder buttons --------------------------- 538c9e2be55Smrg * 539c9e2be55Smrg * I assume that the name of the button is identical to the name of the folder. 540c9e2be55Smrg * Only top-level folders have buttons. 541c9e2be55Smrg * Only top-level folders may have subfolders. 542c9e2be55Smrg * Top-level folders and their subfolders may have messages. 543c9e2be55Smrg * 544c9e2be55Smrg */ 545c9e2be55Smrg 546c9e2be55Smrgstatic char filename[500]; /* for IsFolder() and for callback */ 547c9e2be55Smrgstatic int flen = 0; /* length of a substring of filename */ 548c9e2be55Smrg 549c9e2be55Smrg 550c9e2be55Smrg/* Function name: IsFolder 551c9e2be55Smrg * Description: determines if a file is an mh subfolder. 552c9e2be55Smrg */ 553c9e2be55Smrgstatic int IsFolder(char *name) 554c9e2be55Smrg{ 555c9e2be55Smrg register int i, len; 556c9e2be55Smrg struct stat buf; 557c9e2be55Smrg 558c9e2be55Smrg /* mh does not like subfolder names to be strings of digits */ 559c9e2be55Smrg 560c9e2be55Smrg if (isdigit(name[0]) || name[0] == '#') { 561c9e2be55Smrg len = strlen(name); 562c9e2be55Smrg for(i=1; i < len && isdigit(name[i]); i++) 563c9e2be55Smrg ; 564c9e2be55Smrg if (i == len) return FALSE; 565c9e2be55Smrg } 566c9e2be55Smrg else if (name[0] == '.') 567c9e2be55Smrg return FALSE; 568c9e2be55Smrg 569c9e2be55Smrg (void) sprintf(filename + flen, "/%s", name); 570c9e2be55Smrg if (stat(filename, &buf) /* failed */) return False; 571c9e2be55Smrg#ifdef S_ISDIR 572c9e2be55Smrg return S_ISDIR(buf.st_mode); 573c9e2be55Smrg#else 574c9e2be55Smrg return (buf.st_mode & S_IFMT) == S_IFDIR; 575c9e2be55Smrg#endif 576c9e2be55Smrg} 577c9e2be55Smrg 578c9e2be55Smrg 579c9e2be55Smrg/* menu entry selection callback for folder menus. */ 580c9e2be55Smrg 581c9e2be55Smrg/*ARGSUSED*/ 582c9e2be55Smrgstatic void DoSelectFolder( 583c9e2be55Smrg Widget w, /* the menu entry object */ 584c9e2be55Smrg XtPointer closure, /* foldername */ 585d859ff80Smrg XtPointer data) 586c9e2be55Smrg{ 587c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 588c9e2be55Smrg SetCurrentFolderName(scrn, (char *) closure); 589c9e2be55Smrg} 590c9e2be55Smrg 591c9e2be55Smrg/*ARGSUSED*/ 592c9e2be55Smrgstatic void FreeMenuData( 593c9e2be55Smrg Widget w, 594c9e2be55Smrg XtPointer client_data, 595c9e2be55Smrg XtPointer call_data) 596c9e2be55Smrg{ 597c9e2be55Smrg XtFree((char*) client_data); 598c9e2be55Smrg} 599c9e2be55Smrg 600c9e2be55Smrg/* Function name: AddFolderMenuEntry 601d859ff80Smrg * Description: 602c9e2be55Smrg * Add an entry to a menu. If the menu is not already created, 603c9e2be55Smrg * create it, including the (already existing) new subfolder directory. 604c9e2be55Smrg * If the menu is already created, add the new entry. 605c9e2be55Smrg */ 606c9e2be55Smrg 607c9e2be55Smrgstatic void AddFolderMenuEntry( 608c9e2be55Smrg Button button, /* the corresponding menu button */ 609c9e2be55Smrg char *entryname) /* the new entry, relative to MailDir */ 610c9e2be55Smrg{ 611c9e2be55Smrg Arg args[4]; 612c9e2be55Smrg char * name; 613c9e2be55Smrg char * c; 614c9e2be55Smrg char tmpname[300]; 615c9e2be55Smrg char * label; 616c9e2be55Smrg static XtCallbackRec callbacks[] = { 617c9e2be55Smrg { DoSelectFolder, (XtPointer) NULL }, 618c9e2be55Smrg { (XtCallbackProc) NULL, (XtPointer) NULL} 619c9e2be55Smrg }; 620c9e2be55Smrg static XtCallbackRec destroyCallbacks[] = { 621c9e2be55Smrg { FreeMenuData, (XtPointer) NULL }, 622c9e2be55Smrg { (XtCallbackProc) NULL, (XtPointer) NULL} 623c9e2be55Smrg }; 624c9e2be55Smrg 625c9e2be55Smrg /* The menu must be created before we can add an entry to it. */ 626c9e2be55Smrg 627c9e2be55Smrg if (button->menu == NULL || button->menu == NoMenuForButton) { 628c9e2be55Smrg CreateFolderMenu(button); 629c9e2be55Smrg return; 630c9e2be55Smrg } 631c9e2be55Smrg name = XtNewString(entryname); 632c9e2be55Smrg callbacks[0].closure = (XtPointer) name; 633c9e2be55Smrg destroyCallbacks[0].closure = (XtPointer) name; 634c9e2be55Smrg XtSetArg(args[0], XtNcallback, callbacks); /* ONE */ 635c9e2be55Smrg XtSetArg(args[1], XtNdestroyCallback, destroyCallbacks); /* TWO */ 636c9e2be55Smrg 637c9e2be55Smrg /* When a subfolder and its parent folder have identical names, 638c9e2be55Smrg * the widget name of the subfolder's menu entry must be unique. 639c9e2be55Smrg */ 640c9e2be55Smrg label = entryname; 641c9e2be55Smrg c = strchr( strcpy(tmpname, entryname), '/'); 642c9e2be55Smrg if (c) { 643c9e2be55Smrg *c = '\0'; 644c9e2be55Smrg label = ++c; 645c9e2be55Smrg if (strcmp(tmpname, c) == 0) { 646c9e2be55Smrg c--; 647c9e2be55Smrg *c = '_'; 648c9e2be55Smrg } 649c9e2be55Smrg name = c; 650c9e2be55Smrg } 651c9e2be55Smrg XtSetArg(args[2], XtNlabel, label); /* THREE */ 652d859ff80Smrg XtCreateManagedWidget(name, smeBSBObjectClass, button->menu, 653c9e2be55Smrg args, THREE); 654c9e2be55Smrg} 655c9e2be55Smrg 656c9e2be55Smrg 657c9e2be55Smrg 658c9e2be55Smrg/* Function name: CreateFolderMenu 659d859ff80Smrg * Description: 660c9e2be55Smrg * Menus are created for folder buttons if the folder has at least one 661d859ff80Smrg * subfolder. For the directory given by the concatenation of 662d859ff80Smrg * app_resources.mail_path, '/', and the name of the button, 663c9e2be55Smrg * CreateFolderMenu creates the menu whose entries are 664c9e2be55Smrg * the subdirectories which do not begin with '.' and do not have 665c9e2be55Smrg * names which are all digits, and do not have names which are a '#' 666c9e2be55Smrg * followed by all digits. The first entry is always the name of the 667c9e2be55Smrg * parent folder. Remaining entries are alphabetized. 668c9e2be55Smrg */ 669c9e2be55Smrg 670c9e2be55Smrgstatic void CreateFolderMenu( 671c9e2be55Smrg Button button) 672c9e2be55Smrg{ 673c9e2be55Smrg char **namelist; 674c9e2be55Smrg register int i, n, length; 675c9e2be55Smrg char directory[500]; 676c9e2be55Smrg 677c9e2be55Smrg n = strlen(app_resources.mail_path); 678c9e2be55Smrg (void) strncpy(directory, app_resources.mail_path, n); 679c9e2be55Smrg directory[n++] = '/'; 680c9e2be55Smrg (void) strcpy(directory + n, button->name); 681c9e2be55Smrg flen = strlen(directory); /* for IsFolder */ 682c9e2be55Smrg (void) strcpy(filename, directory); /* for IsFolder */ 683c9e2be55Smrg n = ScanDir(directory, &namelist, IsFolder); 684c9e2be55Smrg if (n <= 0) { 685c9e2be55Smrg /* no subfolders, therefore no menu */ 686c9e2be55Smrg button->menu = NoMenuForButton; 687c9e2be55Smrg return; 688c9e2be55Smrg } 689c9e2be55Smrg 690c9e2be55Smrg button->menu = XtCreatePopupShell("menu", simpleMenuWidgetClass, 691c9e2be55Smrg button->widget, (ArgList) NULL, ZERO); 692d859ff80Smrg 693c9e2be55Smrg /* The first entry is always the parent folder */ 694c9e2be55Smrg 695c9e2be55Smrg AddFolderMenuEntry(button, button->name); 696c9e2be55Smrg 697c9e2be55Smrg /* Build the menu by adding all the current entries to the new menu. */ 698c9e2be55Smrg 699c9e2be55Smrg length = strlen(button->name); 700c9e2be55Smrg (void) strncpy(directory, button->name, length); 701c9e2be55Smrg directory[length++] = '/'; 702c9e2be55Smrg for (i=0; i < n; i++) { 703c9e2be55Smrg (void) strcpy(directory + length, namelist[i]); 704c9e2be55Smrg free((char *) namelist[i]); 705c9e2be55Smrg AddFolderMenuEntry(button, directory); 706c9e2be55Smrg } 707c9e2be55Smrg free((char *) namelist); 708c9e2be55Smrg} 709c9e2be55Smrg 710c9e2be55Smrg 711c9e2be55Smrg/* Function: DeleteFolderMenuEntry 712c9e2be55Smrg * Description: Remove a subfolder from a menu. 713c9e2be55Smrg */ 714c9e2be55Smrg 715c9e2be55Smrgstatic void DeleteFolderMenuEntry( 716c9e2be55Smrg Button button, 717c9e2be55Smrg char *foldername) 718c9e2be55Smrg{ 719c9e2be55Smrg char * c; 720c9e2be55Smrg Arg args[2]; 721c9e2be55Smrg char * subfolder; 722c9e2be55Smrg int n; 723c9e2be55Smrg char tmpname[300]; 724c9e2be55Smrg Widget entry; 725d859ff80Smrg 726c9e2be55Smrg if (button == NULL || button->menu == NULL) return; 727c9e2be55Smrg XtSetArg(args[0], XtNnumChildren, &n); 728c9e2be55Smrg XtSetArg(args[1], XtNlabel, &c); 729c9e2be55Smrg XtGetValues(button->menu, args, TWO); 730c9e2be55Smrg if ((n <= 3 && c) || n <= 2) { 731d859ff80Smrg XtDestroyWidget(button->menu); 732c9e2be55Smrg button->menu = NoMenuForButton; 733c9e2be55Smrg return; 734c9e2be55Smrg } 735c9e2be55Smrg 736c9e2be55Smrg c = strchr( strcpy(tmpname, foldername), '/'); 737c9e2be55Smrg if (c) { 738c9e2be55Smrg *c = '\0'; 739c9e2be55Smrg subfolder = ++c; 740c9e2be55Smrg if (strcmp(button->name, subfolder) == 0) { 741c9e2be55Smrg c--; 742c9e2be55Smrg *c = '_'; 743c9e2be55Smrg subfolder = c; 744c9e2be55Smrg } 745c9e2be55Smrg if ((entry = XtNameToWidget(button->menu, subfolder)) != NULL) 746c9e2be55Smrg XtDestroyWidget(entry); 747c9e2be55Smrg } 748c9e2be55Smrg} 749c9e2be55Smrg 750c9e2be55Smrg/* Function Name: PopupFolderMenu 751d859ff80Smrg * Description: This action should always be taken when the user 752d859ff80Smrg * selects a folder button. A folder button represents a folder 753c9e2be55Smrg * and zero or more subfolders. The menu of subfolders is built upon 754d859ff80Smrg * the first reference to it, by this routine. If there are no 755d859ff80Smrg * subfolders, this routine will mark the folder as having no 756c9e2be55Smrg * subfolders, and no menu will be built. In that case, the menu 757c9e2be55Smrg * button emulates a command button. When subfolders exist, 758c9e2be55Smrg * the menu will popup, using the menu button action PopupMenu. 759c9e2be55Smrg */ 760c9e2be55Smrg 761c9e2be55Smrg/*ARGSUSED*/ 762c9e2be55Smrgvoid XmhPopupFolderMenu( 763c9e2be55Smrg Widget w, 764c9e2be55Smrg XEvent *event, /* unused */ 765c9e2be55Smrg String *vector, /* unused */ 766c9e2be55Smrg Cardinal *count) /* unused */ 767c9e2be55Smrg{ 768c9e2be55Smrg Button button; 769c9e2be55Smrg Scrn scrn; 770c9e2be55Smrg 771c9e2be55Smrg scrn = ScrnFromWidget(w); 772c9e2be55Smrg if ((button = BBoxFindButton(scrn->folderbuttons, w)) == NULL) 773c9e2be55Smrg return; 774c9e2be55Smrg if (button->menu == NULL) 775c9e2be55Smrg CreateFolderMenu(button); 776c9e2be55Smrg 777c9e2be55Smrg if (button->menu == NoMenuForButton) 778c9e2be55Smrg LastMenuButtonPressed = w; 779c9e2be55Smrg else { 780c9e2be55Smrg XtCallActionProc(button->widget, "PopupMenu", (XEvent *) NULL, 781c9e2be55Smrg (String *) NULL, (Cardinal) 0); 782c9e2be55Smrg XtCallActionProc(button->widget, "reset", (XEvent *) NULL, 783c9e2be55Smrg (String *) NULL, (Cardinal) 0); 784c9e2be55Smrg } 785c9e2be55Smrg} 786c9e2be55Smrg 787c9e2be55Smrg 788c9e2be55Smrg/* Function Name: XmhSetCurrentFolder 789d859ff80Smrg * Description: This action procedure allows menu buttons to 790c9e2be55Smrg * emulate toggle widgets in their function of folder selection. 791c9e2be55Smrg * Therefore, mh folders with no subfolders can be represented 792c9e2be55Smrg * by a button instead of a menu with one entry. Sets the currently 793c9e2be55Smrg * selected folder. 794c9e2be55Smrg */ 795c9e2be55Smrg 796c9e2be55Smrg/*ARGSUSED*/ 797c9e2be55Smrgvoid XmhSetCurrentFolder( 798c9e2be55Smrg Widget w, 799c9e2be55Smrg XEvent *event, /* unused */ 800c9e2be55Smrg String *vector, /* unused */ 801c9e2be55Smrg Cardinal *count) /* unused */ 802c9e2be55Smrg{ 803c9e2be55Smrg Button button; 804c9e2be55Smrg Scrn scrn; 805c9e2be55Smrg 806c9e2be55Smrg /* The MenuButton widget has a button grab currently active; the 807c9e2be55Smrg * currently selected folder will be updated if the user has released 808c9e2be55Smrg * the mouse button while the mouse pointer was on the same menu button 809d859ff80Smrg * widget that originally activated the button grab. This mechanism is 810c9e2be55Smrg * insured by the XmhPopupFolderMenu action setting LastMenuButtonPressed. 811c9e2be55Smrg * The action XmhLeaveFolderButton, and it's translation in the application 812c9e2be55Smrg * defaults file, bound to LeaveWindow events, insures that the menu 813d859ff80Smrg * button behaves properly when the user moves the pointer out of the 814c9e2be55Smrg * menu button window. 815c9e2be55Smrg * 816c9e2be55Smrg * This action is for menu button widgets only. 817c9e2be55Smrg */ 818c9e2be55Smrg 819c9e2be55Smrg if (w != LastMenuButtonPressed) 820c9e2be55Smrg return; 821c9e2be55Smrg scrn = ScrnFromWidget(w); 822c9e2be55Smrg if ((button = BBoxFindButton(scrn->folderbuttons, w)) == NULL) 823c9e2be55Smrg return; 824c9e2be55Smrg SetCurrentFolderName(scrn, button->name); 825c9e2be55Smrg} 826c9e2be55Smrg 827c9e2be55Smrg 828c9e2be55Smrg/*ARGSUSED*/ 829c9e2be55Smrgvoid XmhLeaveFolderButton( 830c9e2be55Smrg Widget w, 831c9e2be55Smrg XEvent *event, 832c9e2be55Smrg String *vector, 833c9e2be55Smrg Cardinal *count) 834c9e2be55Smrg{ 835c9e2be55Smrg LastMenuButtonPressed = NULL; 836c9e2be55Smrg} 837c9e2be55Smrg 838c9e2be55Smrg 839c9e2be55Smrgvoid Push( 840c9e2be55Smrg Stack *stack_ptr, 841c9e2be55Smrg char *data) 842c9e2be55Smrg{ 843c9e2be55Smrg Stack new = XtNew(StackRec); 844c9e2be55Smrg new->data = data; 845c9e2be55Smrg new->next = *stack_ptr; 846c9e2be55Smrg *stack_ptr = new; 847c9e2be55Smrg} 848c9e2be55Smrg 849c9e2be55Smrgchar * Pop( 850c9e2be55Smrg Stack *stack_ptr) 851c9e2be55Smrg{ 852c9e2be55Smrg Stack top; 853c9e2be55Smrg char *data = NULL; 854c9e2be55Smrg 855c9e2be55Smrg if ((top = *stack_ptr) != NULL) { 856c9e2be55Smrg data = top->data; 857c9e2be55Smrg *stack_ptr = top->next; 858c9e2be55Smrg XtFree((char *) top); 859c9e2be55Smrg } 860c9e2be55Smrg return data; 861c9e2be55Smrg} 862c9e2be55Smrg 863c9e2be55Smrg/* Parameters are taken as names of folders to be pushed on the stack. 864c9e2be55Smrg * With no parameters, the currently selected folder is pushed. 865c9e2be55Smrg */ 866c9e2be55Smrg 867c9e2be55Smrg/*ARGSUSED*/ 868c9e2be55Smrgvoid XmhPushFolder( 869c9e2be55Smrg Widget w, 870c9e2be55Smrg XEvent *event, 871c9e2be55Smrg String *params, 872c9e2be55Smrg Cardinal *count) 873c9e2be55Smrg{ 874c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 875c9e2be55Smrg Cardinal i; 876c9e2be55Smrg 877d859ff80Smrg for (i=0; i < *count; i++) 878c9e2be55Smrg Push(&scrn->folder_stack, params[i]); 879c9e2be55Smrg 880c9e2be55Smrg if (*count == 0 && scrn->curfolder) 881c9e2be55Smrg Push(&scrn->folder_stack, scrn->curfolder); 882c9e2be55Smrg} 883c9e2be55Smrg 884c9e2be55Smrg/* Pop the stack & take that folder to be the currently selected folder. */ 885c9e2be55Smrg 886c9e2be55Smrg/*ARGSUSED*/ 887c9e2be55Smrgvoid XmhPopFolder( 888c9e2be55Smrg Widget w, 889c9e2be55Smrg XEvent *event, 890c9e2be55Smrg String *params, 891c9e2be55Smrg Cardinal *count) 892c9e2be55Smrg{ 893c9e2be55Smrg Scrn scrn = ScrnFromWidget(w); 894c9e2be55Smrg char *folder; 895c9e2be55Smrg 896c9e2be55Smrg if ((folder = Pop(&scrn->folder_stack)) != NULL) 897c9e2be55Smrg SetCurrentFolderName(scrn, folder); 898c9e2be55Smrg} 899c9e2be55Smrg 900c9e2be55Smrgstatic Boolean InParams( 901c9e2be55Smrg String str, 902c9e2be55Smrg String *p, 903c9e2be55Smrg Cardinal n) 904c9e2be55Smrg{ 905c9e2be55Smrg Cardinal i; 906c9e2be55Smrg for (i=0; i < n; p++, i++) 907c9e2be55Smrg if (! XmuCompareISOLatin1(*p, str)) return True; 908c9e2be55Smrg return False; 909c9e2be55Smrg} 910c9e2be55Smrg 911c9e2be55Smrg/* generalized routine for xmh participation in WM protocols */ 912c9e2be55Smrg 913c9e2be55Smrg/*ARGSUSED*/ 914c9e2be55Smrgvoid XmhWMProtocols( 915c9e2be55Smrg Widget w, /* NULL if from checkpoint timer */ 916c9e2be55Smrg XEvent * event, /* NULL if from checkpoint timer */ 917c9e2be55Smrg String * params, 918c9e2be55Smrg Cardinal * num_params) 919c9e2be55Smrg{ 920c9e2be55Smrg Boolean dw = False; /* will we do delete window? */ 921c9e2be55Smrg Boolean sy = False; /* will we do save yourself? */ 922c9e2be55Smrg static char*WM_DELETE_WINDOW = "WM_DELETE_WINDOW"; 923c9e2be55Smrg static char*WM_SAVE_YOURSELF = "WM_SAVE_YOURSELF"; 924c9e2be55Smrg 925c9e2be55Smrg#define DO_DELETE_WINDOW InParams(WM_DELETE_WINDOW, params, *num_params) 926c9e2be55Smrg#define DO_SAVE_YOURSELF InParams(WM_SAVE_YOURSELF, params, *num_params) 927c9e2be55Smrg 928d859ff80Smrg /* Respond to a recognized WM protocol request iff 929c9e2be55Smrg * event type is ClientMessage and no parameters are passed, or 930c9e2be55Smrg * event type is ClientMessage and event data is matched to parameters, or 931c9e2be55Smrg * event type isn't ClientMessage and parameters make a request. 932c9e2be55Smrg */ 933c9e2be55Smrg 934c9e2be55Smrg if (event && event->type == ClientMessage) { 935c9e2be55Smrg if (event->xclient.message_type == wm_protocols) { 936c9e2be55Smrg if (event->xclient.data.l[0] == wm_delete_window && 937c9e2be55Smrg (*num_params == 0 || DO_DELETE_WINDOW)) 938c9e2be55Smrg dw = True; 939c9e2be55Smrg else if (event->xclient.data.l[0] == wm_save_yourself && 940c9e2be55Smrg (*num_params == 0 || DO_SAVE_YOURSELF)) 941c9e2be55Smrg sy = True; 942c9e2be55Smrg } 943c9e2be55Smrg } else { 944c9e2be55Smrg if (DO_DELETE_WINDOW) 945c9e2be55Smrg dw = True; 946c9e2be55Smrg if (DO_SAVE_YOURSELF) 947c9e2be55Smrg sy = True; 948c9e2be55Smrg } 949c9e2be55Smrg 950c9e2be55Smrg#undef DO_DELETE_WINDOW 951c9e2be55Smrg#undef DO_SAVE_YOURSELF 952c9e2be55Smrg 953c9e2be55Smrg if (sy) { 954c9e2be55Smrg register int i; 955c9e2be55Smrg for (i=0; i<numScrns; i++) 956d859ff80Smrg if (scrnList[i]->msg) 957c9e2be55Smrg MsgCheckPoint(scrnList[i]->msg); 958c9e2be55Smrg if (w) /* don't generate a property notify via the checkpoint timer */ 959c9e2be55Smrg XChangeProperty(XtDisplay(toplevel), XtWindow(toplevel), 960c9e2be55Smrg XA_WM_COMMAND, XA_STRING, 8, PropModeAppend, 961c9e2be55Smrg (unsigned char *)"", 0); 962c9e2be55Smrg } 963c9e2be55Smrg if (dw && w) { 964c9e2be55Smrg Scrn scrn; 965c9e2be55Smrg 966c9e2be55Smrg while (w && !XtIsShell(w)) 967c9e2be55Smrg w = XtParent(w); 968c9e2be55Smrg if (XtIsTransientShell(w)) { 969c9e2be55Smrg WMDeletePopup(w, event); 970c9e2be55Smrg return; 971c9e2be55Smrg } 972c9e2be55Smrg scrn = ScrnFromWidget(w); 973c9e2be55Smrg switch (scrn->kind) { 974c9e2be55Smrg case STtocAndView: 975c9e2be55Smrg DoClose(w, (XtPointer)scrn, (XtPointer)NULL); 976c9e2be55Smrg break; 977c9e2be55Smrg case STview: 978c9e2be55Smrg case STcomp: 979c9e2be55Smrg DoCloseView(w, (XtPointer)scrn, (XtPointer)NULL); 980c9e2be55Smrg break; 981c9e2be55Smrg case STpick: 982c9e2be55Smrg DestroyScrn(scrn); 983c9e2be55Smrg break; 984c9e2be55Smrg } 985c9e2be55Smrg } 986c9e2be55Smrg} 987c9e2be55Smrg 988c9e2be55Smrg 989c9e2be55Smrgtypedef struct _InteractMsgTokenRec { 990c9e2be55Smrg Scrn scrn; 991c9e2be55Smrg XtCheckpointToken cp_token; 992c9e2be55Smrg} InteractMsgTokenRec, *InteractMsgToken; 993c9e2be55Smrg 994c9e2be55Smrgstatic void CommitMsgChanges( 995c9e2be55Smrg Widget w, /* unused */ 996c9e2be55Smrg XtPointer client_data, /* InteractMsgToken */ 997c9e2be55Smrg XtPointer call_data) 998c9e2be55Smrg{ 999c9e2be55Smrg Cardinal zero = 0; 1000c9e2be55Smrg InteractMsgToken iToken = (InteractMsgToken) client_data; 1001c9e2be55Smrg 1002c9e2be55Smrg XmhSave(iToken->scrn->parent, (XEvent*)NULL, (String*)NULL, &zero); 1003c9e2be55Smrg 1004c9e2be55Smrg if (MsgChanged(iToken->scrn->msg)) 1005c9e2be55Smrg iToken->cp_token->save_success = False; 1006c9e2be55Smrg 1007c9e2be55Smrg XtSessionReturnToken(iToken->cp_token); 1008c9e2be55Smrg XtFree((XtPointer)iToken); 1009c9e2be55Smrg} 1010c9e2be55Smrg 1011c9e2be55Smrgstatic void CancelMsgChanges( 1012c9e2be55Smrg Widget w, /* unused */ 1013c9e2be55Smrg XtPointer client_data, /* InteractMsgToken */ 1014c9e2be55Smrg XtPointer call_data) 1015c9e2be55Smrg{ 1016c9e2be55Smrg InteractMsgToken iToken = (InteractMsgToken) client_data; 1017c9e2be55Smrg 1018c9e2be55Smrg /* don't change any msg state now; this is only a checkpoint 1019c9e2be55Smrg * and the session might be continuing. */ 1020c9e2be55Smrg 1021c9e2be55Smrg MsgCheckPoint(iToken->scrn->msg); 1022c9e2be55Smrg 1023c9e2be55Smrg XtSessionReturnToken(iToken->cp_token); 1024c9e2be55Smrg XtFree((XtPointer)iToken); 1025c9e2be55Smrg} 1026c9e2be55Smrg 1027c9e2be55Smrgstatic void CommitMsgInteract( 1028c9e2be55Smrg Widget w, /* unused */ 1029c9e2be55Smrg XtPointer client_data, /* Scrn */ 1030c9e2be55Smrg XtPointer call_data) /* XtCheckpointToken */ 1031c9e2be55Smrg{ 1032c9e2be55Smrg Scrn scrn = (Scrn) client_data; 1033c9e2be55Smrg XtCheckpointToken cpToken = (XtCheckpointToken) call_data; 1034c9e2be55Smrg char str[300]; 1035c9e2be55Smrg InteractMsgToken iToken; 1036c9e2be55Smrg static XtCallbackRec yes_callbacks[] = { 1037c9e2be55Smrg {CommitMsgChanges, (XtPointer) NULL}, 1038c9e2be55Smrg {(XtCallbackProc) NULL, (XtPointer) NULL} 1039c9e2be55Smrg }; 1040c9e2be55Smrg 1041c9e2be55Smrg static XtCallbackRec no_callbacks[] = { 1042c9e2be55Smrg {CancelMsgChanges, (XtPointer) NULL}, 1043c9e2be55Smrg {(XtCallbackProc) NULL, (XtPointer) NULL} 1044c9e2be55Smrg }; 1045c9e2be55Smrg 1046c9e2be55Smrg if (cpToken->interact_style != SmInteractStyleAny 1047c9e2be55Smrg || cpToken->cancel_shutdown) { 1048c9e2be55Smrg XtSessionReturnToken(cpToken); 1049c9e2be55Smrg return; 1050c9e2be55Smrg } 1051c9e2be55Smrg 1052c9e2be55Smrg iToken = XtNew(InteractMsgTokenRec); 1053c9e2be55Smrg 1054c9e2be55Smrg iToken->scrn = scrn; 1055c9e2be55Smrg iToken->cp_token = cpToken; 1056c9e2be55Smrg 1057c9e2be55Smrg yes_callbacks[0].closure = no_callbacks[0].closure = (XtPointer) iToken; 1058c9e2be55Smrg 1059c9e2be55Smrg (void)sprintf(str,"Save changes to message %s?", MsgName(scrn->msg)); 1060c9e2be55Smrg 1061c9e2be55Smrg /* %%% should add cancel button */ 1062c9e2be55Smrg PopupConfirm(scrn->parent, str, yes_callbacks, no_callbacks); 1063c9e2be55Smrg} 1064c9e2be55Smrg 1065c9e2be55Smrg 1066c9e2be55Smrgtypedef struct _InteractTocTokenRec { 1067c9e2be55Smrg Toc toc; 1068c9e2be55Smrg XtCheckpointToken cp_token; 1069c9e2be55Smrg} InteractTocTokenRec, *InteractTocToken; 1070c9e2be55Smrg 1071c9e2be55Smrgstatic void CommitTocChanges( 1072c9e2be55Smrg Widget w, /* unused */ 1073c9e2be55Smrg XtPointer client_data, /* InteractTocToken */ 1074c9e2be55Smrg XtPointer call_data) 1075c9e2be55Smrg{ 1076c9e2be55Smrg InteractTocToken iToken = (InteractTocToken) client_data; 1077c9e2be55Smrg 1078c9e2be55Smrg TocCommitChanges(w, (XtPointer) iToken->toc, (XtPointer) NULL); 1079c9e2be55Smrg 1080c9e2be55Smrg XtSessionReturnToken(iToken->cp_token); 1081c9e2be55Smrg XtFree((XtPointer)iToken); 1082c9e2be55Smrg} 1083c9e2be55Smrg 1084c9e2be55Smrgstatic void CancelTocChanges( 1085c9e2be55Smrg Widget w, /* unused */ 1086c9e2be55Smrg XtPointer client_data, /* InteractTocToken */ 1087c9e2be55Smrg XtPointer call_data) 1088c9e2be55Smrg{ 1089c9e2be55Smrg InteractTocToken iToken = (InteractTocToken) client_data; 1090c9e2be55Smrg 1091c9e2be55Smrg /* don't change any folder or msg state now; this is only 1092c9e2be55Smrg * a checkpoint and the session might be continuing. */ 1093c9e2be55Smrg 1094c9e2be55Smrg XtSessionReturnToken(iToken->cp_token); 1095c9e2be55Smrg XtFree((XtPointer)iToken); 1096c9e2be55Smrg} 1097c9e2be55Smrg 1098c9e2be55Smrgstatic void CommitTocInteract( 1099c9e2be55Smrg Widget w, /* unused */ 1100c9e2be55Smrg XtPointer client_data, /* Toc */ 1101c9e2be55Smrg XtPointer call_data) /* XtCheckpointToken */ 1102c9e2be55Smrg{ 1103c9e2be55Smrg Toc toc = (Toc) client_data; 1104c9e2be55Smrg XtCheckpointToken cpToken = (XtCheckpointToken) call_data; 1105c9e2be55Smrg char str[300]; 1106c9e2be55Smrg Widget tocwidget; 1107c9e2be55Smrg Cardinal i; 1108c9e2be55Smrg InteractTocToken iToken; 1109c9e2be55Smrg static XtCallbackRec yes_callbacks[] = { 1110c9e2be55Smrg {CommitTocChanges, (XtPointer) NULL}, 1111c9e2be55Smrg {(XtCallbackProc) NULL, (XtPointer) NULL} 1112c9e2be55Smrg }; 1113c9e2be55Smrg 1114c9e2be55Smrg static XtCallbackRec no_callbacks[] = { 1115c9e2be55Smrg {CancelTocChanges, (XtPointer) NULL}, 1116c9e2be55Smrg {(XtCallbackProc) NULL, (XtPointer) NULL} 1117c9e2be55Smrg }; 1118c9e2be55Smrg 1119c9e2be55Smrg if (cpToken->interact_style != SmInteractStyleAny 1120c9e2be55Smrg || cpToken->cancel_shutdown) { 1121c9e2be55Smrg XtSessionReturnToken(cpToken); 1122c9e2be55Smrg return; 1123c9e2be55Smrg } 1124c9e2be55Smrg 1125c9e2be55Smrg iToken = XtNew(InteractTocTokenRec); 1126c9e2be55Smrg 1127c9e2be55Smrg iToken->toc = toc; 1128c9e2be55Smrg iToken->cp_token = cpToken; 1129c9e2be55Smrg 1130c9e2be55Smrg yes_callbacks[0].closure = no_callbacks[0].closure = (XtPointer) iToken; 1131c9e2be55Smrg 1132c9e2be55Smrg (void)sprintf(str,"Commit all changes to %s folder?", toc->foldername); 1133c9e2be55Smrg 1134c9e2be55Smrg tocwidget = NULL; 1135c9e2be55Smrg for (i=0; i < toc->num_scrns; i++) 1136c9e2be55Smrg if (toc->scrn[i]->mapped) { 1137c9e2be55Smrg tocwidget = toc->scrn[i]->tocwidget; 1138c9e2be55Smrg break; 1139c9e2be55Smrg } 1140c9e2be55Smrg 1141c9e2be55Smrg /* %%% should add cancel button */ 1142c9e2be55Smrg PopupConfirm(tocwidget, str, yes_callbacks, no_callbacks); 1143c9e2be55Smrg} 1144c9e2be55Smrg 1145c9e2be55Smrg/* Callback for Session Manager SaveYourself */ 1146c9e2be55Smrg 1147c9e2be55Smrg/*ARGSUSED*/ 1148c9e2be55Smrgvoid DoSaveYourself( 1149c9e2be55Smrg Widget w, /* unused; s/b toplevel */ 1150c9e2be55Smrg XtPointer client_data, /* unused */ 1151c9e2be55Smrg XtPointer call_data) /* XtCheckpointToken */ 1152c9e2be55Smrg{ 1153c9e2be55Smrg XtCheckpointToken cpToken = (XtCheckpointToken)call_data; 1154c9e2be55Smrg 1155c9e2be55Smrg { /* confirm any uncommitted msg changes */ 1156c9e2be55Smrg int i; 1157c9e2be55Smrg for (i=0 ; i<numScrns ; i++) { 1158c9e2be55Smrg if (MsgChanged(scrnList[i]->msg)) { 1159c9e2be55Smrg if (cpToken->interact_style == SmInteractStyleAny) 1160c9e2be55Smrg XtAddCallback(toplevel, XtNinteractCallback, 1161c9e2be55Smrg CommitMsgInteract, (XtPointer)scrnList[i]); 1162c9e2be55Smrg else { 1163c9e2be55Smrg Cardinal zero = 0; 1164c9e2be55Smrg XmhSave(scrnList[i]->parent, (XEvent*)NULL, 1165c9e2be55Smrg (String*)NULL, &zero); 1166c9e2be55Smrg if (MsgChanged(scrnList[i]->msg)) { 1167c9e2be55Smrg MsgCheckPoint(scrnList[i]->msg); 1168c9e2be55Smrg cpToken->save_success = False; 1169c9e2be55Smrg } 1170c9e2be55Smrg } 1171c9e2be55Smrg } 1172c9e2be55Smrg } 1173c9e2be55Smrg } 1174c9e2be55Smrg 1175c9e2be55Smrg { /* confirm any uncommitted folder changes */ 1176c9e2be55Smrg int i; 1177c9e2be55Smrg for (i = 0; i < numFolders; i++) { 1178c9e2be55Smrg if (TocHasChanges(folderList[i])) { 1179c9e2be55Smrg if (cpToken->interact_style == SmInteractStyleAny) 1180c9e2be55Smrg XtAddCallback(toplevel, XtNinteractCallback, 1181c9e2be55Smrg CommitTocInteract, (XtPointer)folderList[i]); 1182c9e2be55Smrg else 1183c9e2be55Smrg TocCommitChanges(w, (XtPointer)folderList[i], 1184c9e2be55Smrg (XtPointer) NULL); 1185c9e2be55Smrg } 1186c9e2be55Smrg } 1187c9e2be55Smrg } 1188c9e2be55Smrg} 1189