X11workbench Toolkit  1.0
edit_window.c
1 // _ _ _ _ _ //
3 // ___ __| |(_)| |_ __ __(_) _ __ __| | ___ __ __ ___ //
4 // / _ \ / _` || || __| \ \ /\ / /| || '_ \ / _` | / _ \\ \ /\ / / / __| //
5 // | __/| (_| || || |_ \ V V / | || | | || (_| || (_) |\ V V /_| (__ //
6 // \___| \__,_||_| \__|_____\_/\_/ |_||_| |_| \__,_| \___/ \_/\_/(_)\___| //
7 // |_____| //
8 // //
9 // a window into which you can type (and edit) text //
10 // //
12 
13 /*****************************************************************************
14 
15  X11workbench - X11 programmer's 'work bench' application and toolkit
16  Copyright (c) 2010-2018 by Bob Frazier (aka 'Big Bad Bombastic Bob')
17  all rights reserved
18 
19  DISCLAIMER: The X11workbench application and toolkit software are supplied
20  'as-is', with no warranties, either implied or explicit.
21  Any claims to alleged functionality or features should be
22  considered 'preliminary', and might not function as advertised.
23 
24  BSD-like license:
25 
26  There is no restriction as to what you can do with this software, so long
27  as you include the above copyright notice and DISCLAIMER for any distributed
28  work that is equal to or derived from this one, along with this paragraph
29  that explains the terms of the license if the source is also being made
30  available. A "derived work" describes a work that uses a significant portion
31  of the source files or algorithms that are included with this one.
32  Specifically excluded from this are files that were generated by the software,
33  or anything that is included with the software that is part of another package
34  (such as files that were created or added during the 'configure' process).
35  Specifically included is the use of part or all of any of the X11 workbench
36  toolkit source or header files in your distributed application. If you do not
37  ship the source, the above copyright statement is still required to be placed
38  in a reasonably prominent place, such as documentation, splash screens, and/or
39  'about the application' dialog boxes.
40 
41  Use and distribution are in accordance with GPL, LGPL, and/or the above
42  BSD-like license. See COPYING and README files for more information.
43 
44 
45  Additional information at http://sourceforge.net/projects/X11workbench
46 
47 ******************************************************************************/
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <memory.h>
53 #include <string.h>
54 #include <strings.h>
55 
56 #define _EDIT_WINDOW_C_IMPLEMENTED_
57 
58 #include "window_helper.h"
59 #include "edit_window.h"
60 #include "conf_help.h"
61 #include "file_help.h"
62 #include "draw_text.h"
63 
64 #include "dialog_window.h" // for message boxen
65 #include "dialog_controls.h" // for 'aDIALOG_INIT'
66 
67 
68 #if 0 // assign to 0 to disable this trace-style debugging ALL of the time
69 #define CALLBACK_TRACKER WBDebugPrint("TEMPORARY - edit_window.c: %s - callback tracker\n", __FUNCTION__);
70 #else //
71 #define CALLBACK_TRACKER WB_DEBUG_PRINT((DebugLevel_Heavy | DebugSubSystem_EditWindow), "edit_window.c: %s - callback tracker\n", __FUNCTION__);
72 #endif // 0,1
73 
74 #define EDIT_WINDOW_LINE_SPACING 4 /* 4 spaces between each line */
75 
76 #define CALLBACK_CHECK_NULL(X) if(X) (X)
77 #define CALLBACK_CHECK_NULL2(X) (X) ? (X)
78 
79 
80 struct _PROPERTY_DLG_
81 {
82  WBEditWindow *pEditWindow;
83 };
84 
85 
86 
87 
88 int FWEditWindowEvent(Window wID, XEvent *pEvent);
89 static void InternalEditWindowDestructor(WBChildFrame *pC);
90 static void InternalEditWindowDestroy(WBEditWindow *pEditWindow);
91 
92 // UI callbacks for WBChildFrameUI
93 
94 static void internal_do_char(WBChildFrame *, XClientMessageEvent *); // handler for regular WB_CHAR Client Messages (WBChildFrame *, typed-in characters)
95 static void internal_scancode(WBChildFrame *, XClientMessageEvent *); // handler for 'other scan code' WB_CHAR Client Messages (WBChildFrame *, typed-in characters)
96 static void internal_bkspace(WBChildFrame *, int iACS); // 'backspace' delete character (WBChildFrame *, backspace equivalent). 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
97 static void internal_del(WBChildFrame *, int iACS); // 'delete' char under cursor (WBChildFrame *, delete equivalent). 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
98 static void internal_tab(WBChildFrame *, int iACS); // 'tab' char, or tab navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
99 static void internal_enter(WBChildFrame *, int iACS); // 'enter' char, or 'enter' for navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
100 static void internal_properties(WBChildFrame *); // display the property sheet for the displayed document (optional)
101 static void internal_uparrow(WBChildFrame *, int iACS); // 'up' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
102 static void internal_downarrow(WBChildFrame *, int iACS); // 'down' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
103 static void internal_leftarrow(WBChildFrame *, int iACS); // 'left' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
104 static void internal_rightarrow(WBChildFrame *, int iACS); // 'right' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
105 static void internal_home(WBChildFrame *, int iACS); // 'home' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
106 static void internal_end(WBChildFrame *, int iACS); // 'end' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
107 static void internal_pgup(WBChildFrame *, int iACS); // 'page up' navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
108 static void internal_pgdown(WBChildFrame *, int iACS); // 'page down' navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
109 static void internal_pgleft(WBChildFrame *, int iACS); // 'page left' navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
110 static void internal_pgright(WBChildFrame *, int iACS); // 'page right' navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
111 static void internal_help(WBChildFrame *, int iACS); // 'help' context (WBChildFrame *, F1). 'iACS' is the Alt/Ctrl/Shift flags. \sa aWB_CHAR
112 static void internal_hover_notify(WBChildFrame *, int x, int y); // 'mouse hover' notification (WBChildFrame *, x and y are pixel coords with respect to upper left corner)
113 static void internal_hover_cancel(WBChildFrame *); // 'mouse hover' cancel notification (WBChildFrame *, cancel any 'hover' action)
114 static int internal_is_ins_mode(WBChildFrame *); // returns non-zero if in 'insert' mode, 0 for 'overwrite'
115 static void internal_toggle_ins_mode(WBChildFrame *); // toggles insert mode on/off (WBChildFrame *, press 'INS' key)
116 static void internal_copy_to_cb(WBChildFrame *); // copy selection to clipboard
117 static void internal_paste_from_cb(WBChildFrame *); // paste from clipboard
118 static void internal_cut_to_cb(WBChildFrame *); // delete selection, copying to clipboard first
119 static void internal_delete_sel(WBChildFrame *); // delete selection only
120 static void internal_select_all(WBChildFrame *); // select all
121 static void internal_select_none(WBChildFrame *); // select none
122 static void internal_save(WBChildFrame *, const char *szFileName); // save to specified file name (WBChildFrame *, NULL to keep same file name)
123 static WB_PCSTR internal_get_file_name(WBChildFrame *); // get (const) pointer to file name string
124 static void internal_mouse_click(WBChildFrame *, int iX, int iY,
125  int iButtonMask, int iACS); // 'mouse click' notification. \sa aWB_POINTER
126 static void internal_mouse_dblclick(WBChildFrame *, int iX, int iY,
127  int iButtonMask, int iACS); // 'mouse double click' notification. \sa aWB_POINTER
128 static void internal_mouse_drag(WBChildFrame *, int iX, int iY,
129  int iButtonMask, int iACS); // 'mouse drag' (begin) notification. \sa aWB_POINTER
130 static void internal_mouse_drop(WBChildFrame *, int iX, int iY,
131  int iButtonMask, int iACS); // 'mouse drop' (drag end) notification. \sa aWB_POINTER
132 static void internal_mouse_move(WBChildFrame *, int iX, int iY); // 'mouse motion' notification. \sa aWB_POINTER
133 static void internal_scroll_vert(WBChildFrame *, int iMode, int iValue); // 'scroll vertical' notification. \details A higher-level scrolling notification. 'iMode' is 0 for absolute, 1 for relative. 'iValue' is the absolute (or relative) new vertical scroll position to assign \sa aSCROLL_NOTIFY
134 static void internal_scroll_horiz(WBChildFrame *, int iMode, int iValue); // 'scroll vertical' notification. \details A higher-level scrolling notification. 'iMode' is 0 for absolute, 1 for relative. 'iValue' is the absolute (or relative) new horizontal scroll position to assign \sa aSCROLL_NOTIFY
135 
136 static void internal_mouse_cancel(WBChildFrame *); // 'mouse cancel' notification (cancel 'drag', etc.). \sa aWB_POINTER
137 static void internal_get_row_col(WBChildFrame *pC, int *piR, int *piC);// get row/col (etc.)
138 static int internal_has_selection(WBChildFrame *pC); // returns non-zero value if there is a selection
139 static void internal_undo(WBChildFrame *); // perform an undo
140 static void internal_redo(WBChildFrame *); // perform a re-do
141 static int internal_can_undo(WBChildFrame *); // returns non-zero value if 'can undo'
142 static int internal_can_redo(WBChildFrame *); // returns non-zero value if 'can redo'
143 static int internal_is_empty(WBChildFrame *); // returns non-zero value if 'empty'
144 
145 
146 static void internal_update_status_text(WBEditWindow *); // called whenever status text should change
147 static void internal_new_cursor_pos(WBEditWindow *); // called whenever cursor position changes.
148 
149 static int PropertyDialogCallback(Window wID, XEvent *pEvent);
150 
151 
152 
153 static XColor clrFG, clrBG, clrAFG, clrABG;
154 static int iInitColorFlag = 0;
155 
156 
157 static WBChildFrameUI internal_CFUI =
158 {
160  internal_do_char, internal_scancode, internal_bkspace, internal_del,
161  internal_tab, internal_enter, internal_properties,
162  internal_uparrow, internal_downarrow,
163  internal_leftarrow, internal_rightarrow, internal_home, internal_end,
164  internal_pgup, internal_pgdown, internal_pgleft, internal_pgright,
165  internal_help, internal_hover_notify, internal_hover_cancel, internal_is_ins_mode,
166  internal_toggle_ins_mode, internal_copy_to_cb, internal_paste_from_cb, internal_cut_to_cb,
167  internal_delete_sel, internal_select_all, internal_select_none, internal_save,
168  internal_get_file_name, internal_mouse_click, internal_mouse_dblclick, internal_mouse_drag,
169  internal_mouse_drop, internal_mouse_move, internal_scroll_vert, internal_scroll_horiz,
170  internal_mouse_cancel, internal_get_row_col, internal_has_selection, internal_undo,
171  internal_redo, internal_can_undo, internal_can_redo, internal_is_empty
172 };
173 
174 
175 
193 
210 Atom aEW_EDIT_CHANGE=None;
211 
212 
213 
214 
215 #define LOAD_COLOR0(X,Y) if(CHGetResourceString(WBGetDefaultDisplay(), X, Y, sizeof(Y)) > 0) { }
216 #define LOAD_COLOR(X,Y,Z) if(CHGetResourceString(WBGetDefaultDisplay(), X, Y, sizeof(Y)) <= 0){ WB_WARN_PRINT("%s - WARNING: can't find color %s, using default value %s\n", __FUNCTION__, X, Z); strcpy(Y,Z); }
217 
218 static void InternalCheckEWColorsAndAtoms(void)
219 {
220  Colormap colormap;
221 
222  // *Frame.background, *Frame.foreground, *WmFrame.background, *WmFrame.foreground,
223  // *Form.background, *Form.foreground, *background, *foreground
224 
225  if(aEW_EDIT_CHANGE == None)
226  {
227  aEW_EDIT_CHANGE = WBGetAtom(WBGetDefaultDisplay(), "EW_EDIT_CHANGE");
228  }
229 
230  if(aEW_HOVER_NOTIFY == None)
231  {
232  aEW_HOVER_NOTIFY = WBGetAtom(WBGetDefaultDisplay(), "EW_HOVER_NOTIFY");
233  }
234 
235  if(!iInitColorFlag)
236  {
237  char szFG[16], szBG[16], szAFG[16], szABG[16]; // note colors can typically be up to 13 characters + 0 byte
238 
239  colormap = DefaultColormap(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
240 
241  // (these color names and standards have changed *WAY* too many times...)
242 
243  LOAD_COLOR0("*Text.foreground",szFG) else LOAD_COLOR0("*Edit.foreground", szFG)
244  else LOAD_COLOR("*foreground", szFG, "#000000");
245  LOAD_COLOR0("*Text.background",szBG) else LOAD_COLOR0("*Edit.background", szBG)
246  else LOAD_COLOR("*background", szBG, "white"); // pure white background by default
247 
248  LOAD_COLOR("selected_bg_color", szABG, "#0040FF"); // a slightly greenish blue for the 'selected' BG color
249  LOAD_COLOR("selected_fg_color", szAFG, "white"); // white FG when selected
250 
251  WB_ERROR_PRINT("TEMPORARY: %s - edit window colors: FG=%s BG=%s AFG=%s ABG=%s\n", __FUNCTION__,
252  szFG, szBG, szAFG, szABG);
253 
254  XParseColor(WBGetDefaultDisplay(), colormap, szFG, &clrFG);
255  XAllocColor(WBGetDefaultDisplay(), colormap, &clrFG);
256  XParseColor(WBGetDefaultDisplay(), colormap, szBG, &clrBG);
257  XAllocColor(WBGetDefaultDisplay(), colormap, &clrBG);
258  XParseColor(WBGetDefaultDisplay(), colormap, szAFG, &clrAFG);
259  XAllocColor(WBGetDefaultDisplay(), colormap, &clrAFG);
260  XParseColor(WBGetDefaultDisplay(), colormap, szABG, &clrABG);
261  XAllocColor(WBGetDefaultDisplay(), colormap, &clrABG);
262 
263  iInitColorFlag = 1;
264  }
265 }
266 
267 
268 WBEditWindow *WBCreateEditWindow(WBFrameWindow *pOwner, XFontStruct *pFont,
269  const char *szFocusMenu, const WBFWMenuHandler *pHandlerArray,
270  int fFlags)
271 {
272 WBEditWindow *pRval;
273 XFontSet rFontSet;
274 Display *pDisplay;
275 int iRet;
276 
277 
278  CALLBACK_TRACKER;
279 
280  InternalCheckEWColorsAndAtoms();
281 
282  if(!pOwner)
283  {
284  return NULL;
285  }
286 
287  pDisplay = WBGetWindowDisplay(pOwner->wID);
288 
289  pRval = (WBEditWindow *)WBAlloc(sizeof(*pRval));
290 
291  if(!pRval)
292  {
293  WB_ERROR_PRINT("ERROR: %s - not enough memory\n", __FUNCTION__);
294  return NULL;
295  }
296 
297  bzero(pRval, sizeof(*pRval));
298 
299  pRval->ulTag = EDIT_WINDOW_TAG;
300  pRval->szFileName = NULL; // explicitly do this, though the bzero would've
301  pRval->pUserCallback = NULL; // explicitly do this, too
302 
303  if(!pFont)
304  {
305  rFontSet = None;//WBGetDefaultFontSet();
306  }
307  else
308  {
309  rFontSet = WBFontSetFromFont(pDisplay, pFont);
310  }
311 
314 
315 // pRval->xTextObject.vtable->set_col(&(pRval->xTextObject), 0);
316 // pRval->xTextObject.vtable->set_row(&(pRval->xTextObject), 0);
317 
318 
319  // create the actual window.
320 
321  iRet = FWInitChildFrame(&(pRval->childframe), pOwner, rFontSet, // NOTE: a copy of rFontSet will be in 'childframe.rFontSet'
322  szFocusMenu, pHandlerArray,
323  FWEditWindowEvent, fFlags);
324 
325  if(rFontSet != None)
326  {
327  XFreeFontSet(pDisplay, rFontSet);
328  rFontSet = None;
329  }
330 
331  if(iRet < 0)
332  {
333  WB_ERROR_PRINT("ERROR: %s - unable to initialize child frame\n", __FUNCTION__);
334 
335  WBFree(pRval);
336 
337  return NULL;
338  }
339 
340 
341  pRval->xTextObject.wIDOwner = pRval->childframe.wID; // TODO: make assigning this an API function?
342 
343 
344  // assign my 'UI' vtable pointer, which will be (intelligently) called by the 'Child Frame' event handler
345  // this standardizes the various UI methods and makes coding a complex UI quite a bit easier
346  pRval->childframe.pUI = &internal_CFUI; // Child Frame UI function vtable
347 
348  // assign my 'destructor', which will be called by FWDestroyChildFrame
349  // THIS must be done LAST, since 'FWInitChildFrame' might call FWDestroyChildFrame on error
350  // and I don't want to call the 'destructor' yet.
351  pRval->childframe.destructor = InternalEditWindowDestructor;
352 
353 
354  // TODO: any other initialization belongs HERE. if error, call FWDestroyChildFrame() and return
355  // a NULL immediately (since that would destroy the child frame AND the Edit Window stuff)
356 
357 
358  internal_update_status_text(pRval); // update status text now.
359 
361  333333, 1, 1); // TODO: use #define for timer ID and period (1/3 second for now))
362  // NOTE: when I unregister the window callback, the timer will be deleted automatically
363 
364  return pRval;
365 }
366 
367 // this function destroys any allocated objects in the WBEditWindow, but doesn't free the pointer
368 static void InternalEditWindowDestroy(WBEditWindow *pEditWindow)
369 {
370  // these next 'things' are private to this particular 'class'
371 
372  if(pEditWindow->szFileName)
373  {
374  WBFree(pEditWindow->szFileName);
375  pEditWindow->szFileName = NULL;
376  }
377 
378  WBDestroyInPlaceTextObject(&(pEditWindow->xTextObject));
379 
380  pEditWindow->ulTag = 0; // not valid any more
381 }
382 
383 static void InternalEditWindowDestructor(WBChildFrame *pC)
384 {
385  WBEditWindow *pEW = (WBEditWindow *)pC;
386 
387 // WB_ERROR_PRINT("TEMPORARY: %s - destroying edit window %p\n", __FUNCTION__, pEW);
388 
389  InternalEditWindowDestroy(pEW);
390 
391  bzero(pEW, sizeof(*pEW)); // in case anything else 'stale' is there
392 
393  WBFree(pEW);
394 
395 // WB_ERROR_PRINT("TEMPORARY: %s - destroyed edit window %p\n", __FUNCTION__, pEW);
396 }
397 
399 {
400  if(!WBIsValidEditWindow(pEditWindow))
401  {
402  WB_ERROR_PRINT("ERROR: %s - invalid Edit Window pointer %p\n", __FUNCTION__, pEditWindow);
403  return;
404  }
405 
406  if(pEditWindow->pUserCallback)
407  {
408  // TODO: Send an aDESTROY_NOTIFY ClientMessage 'destroy' notification (once I document it)
409 
410  // TODO: send a 'DestroyNotify' event instead???
411 
412  pEditWindow->pUserCallback = NULL;
413  }
414 
415  if(pEditWindow->childframe.pUserCallback == FWEditWindowEvent)
416  {
417  pEditWindow->childframe.pUserCallback = NULL; // prevents any kind of recursion from messages (unlikely)
418  }
419 
420  if(pEditWindow->childframe.destructor == NULL)
421  {
422  WB_ERROR_PRINT("ERROR: %s - destructor is NULL - pointer will not be free'd\n", __FUNCTION__);
423 
424  InternalEditWindowDestroy(pEditWindow); // perform the necessary destruction *ANYWAY* but don't free the pointer
425 
426  // TODO: ALWAYS assign the destructor to NULL, and THEN call it directly after calling FWDestroyChildFrame() ?
427  }
428 
429  if(pEditWindow->childframe.wID != None)
430  {
432  pEditWindow->childframe.wID, 1); // the preferred method, when practical, is to delete it explicitly
433  }
434 
435  // the last step destroys the child frame, which will destroy the Edit Window as well
436 
437  FWDestroyChildFrame(&(pEditWindow->childframe)); // destroy window, free up all resources, call destructor (if not NULL)
438 }
439 
441 {
443 
444 
445  if(pRval && !WBIsValidEditWindow(pRval))
446  {
447  pRval = NULL;
448  }
449 
450  return pRval;
451 }
452 
453 
454 int WBEditWindowLoadFile(WBEditWindow *pEditWindow, const char *pszFileName)
455 {
456 char *pBuf = NULL;
457 long cbBuf = 0;
458 int iRval = -1;
459 
460 
461  CALLBACK_TRACKER;
462 
463  if(!pEditWindow || !WBIsValidEditWindow(pEditWindow)
464  || !pszFileName || !*pszFileName)
465  {
466  WBDebugPrint("TEMPORARY: bad parameters in %s\n", __FUNCTION__);
467  return -1;
468  }
469 
470  // implement 'load file'. handle unicode files. UTF-16 files begin with 0xff, 0xfe
471  // UTF-8 files are assumed to be the same as ASCII (with no prefix).
472 
473 
474  if(pEditWindow->szFileName)
475  {
476  WBFree(pEditWindow->szFileName);
477  }
478 
479 // pEditWindow->xTextObject.vtable->init(&(pEditWindow->xTextObject));
480  WBEditWindowClear(pEditWindow);
481 
482  pEditWindow->szFileName = WBCopyString(pszFileName);
483  pEditWindow->llModDateTime = WBGetFileModDateTime(pEditWindow->szFileName);
484 
485  // load the file into a buffer
486 
487  cbBuf = (long)WBReadFileIntoBuffer(pszFileName, &pBuf);
488 
489  if(cbBuf >= 0 && pBuf)
490  {
491  if(cbBuf >= 2 && (unsigned char)pBuf[0] == 0xff && (unsigned char)pBuf[1] == 0xfe)
492  {
493  // TODO: unicode file!
494 // pEditWindow->xTextObject.vtable->set_text(&(pEditWindow->xTextObject), pBuf + 2, cbBuf - 2);
495  }
496  else
497  {
498  // TODO: fix line endings first??
499  pEditWindow->xTextObject.vtable->set_row(&(pEditWindow->xTextObject),0);
500  pEditWindow->xTextObject.vtable->set_col(&(pEditWindow->xTextObject),0);
501 
502 // internal_new_cursor_pos(pE);
503  pEditWindow->xTextObject.vtable->set_text(&(pEditWindow->xTextObject), pBuf, cbBuf);
504 // pEditWindow->xTextObject.vtable->ins_chars(&(pEditWindow->xTextObject), pBuf, cbBuf);
505 
506  pEditWindow->xTextObject.vtable->set_row(&(pEditWindow->xTextObject),0);
507  pEditWindow->xTextObject.vtable->set_col(&(pEditWindow->xTextObject),0);
508  }
509 
510  iRval = 0; // for now; later, check for error state
511  }
512  else
513  {
514  iRval = -1;
515  }
516 
517  if(pBuf)
518  {
519  WBFree(pBuf);
520  }
521 
522  FWChildFrameRecalcLayout(&(pEditWindow->childframe));
523 
524  if(pEditWindow->pUserCallback)
525  {
526  XClientMessageEvent evt;
527 
528  bzero(&evt, sizeof(evt));
529 
530  evt.type=ClientMessage;
531  evt.display=WBGetWindowDisplay(pEditWindow->childframe.wID);
532  evt.window=pEditWindow->childframe.wID;
533  evt.message_type=aEW_EDIT_CHANGE;
534  evt.format=32;
535 
536  evt.data.l[0] = 0; // undo
537  evt.data.l[1] = 0; // cursor x,y
538  evt.data.l[2] = 0;
539 
540  pEditWindow->pUserCallback(pEditWindow->childframe.wID, (XEvent *)&evt);
541  }
542 
543  return iRval;
544 }
545 
546 int WBEditWindowSaveFile(WBEditWindow *pEditWindow, const char *pszFileName)
547 {
548  if(!pEditWindow || !WBIsValidEditWindow(pEditWindow))
549  {
550  return -1;
551  }
552 
553  if(!pszFileName || !*pszFileName)
554  {
555  pszFileName = pEditWindow->szFileName;
556  }
557 
558  if(!pszFileName || !*pszFileName)
559  {
560  return -1; // error (no file name)
561  }
562 
563  // TODO: implement 'file save'
564 
565  pEditWindow->llModDateTime = WBGetFileModDateTime(pEditWindow->szFileName);
566 
567 
568 
569  return -1; // error
570 }
571 
572 void WBEditWindowClear(WBEditWindow *pEditWindow)
573 {
574  if(!pEditWindow || !WBIsValidEditWindow(pEditWindow))
575  {
576  return;
577  }
578 
579  WBDestroyInPlaceTextObject(&(pEditWindow->xTextObject));
580  WBInitializeInPlaceTextObject(&(pEditWindow->xTextObject), pEditWindow->childframe.wID);
581  pEditWindow->xTextObject.vtable->set_linefeed(&(pEditWindow->xTextObject), LineFeed_DEFAULT);
582 
583  FWChildFrameRecalcLayout(&(pEditWindow->childframe));
584 }
585 
586 void WBEditWindowRegisterCallback(WBEditWindow *pEditWindow, WBWinEvent pUserCallback)
587 {
588  if(!pEditWindow || !WBIsValidEditWindow(pEditWindow))
589  {
590  return;
591  }
592 
593  pEditWindow->pUserCallback = pUserCallback;
594 }
595 
596 
597 
599 // //
600 // _____ _ _ _ _ _ //
601 // | ____|__ __ ___ _ __ | |_ | | | | __ _ _ __ __| || | ___ _ __ //
602 // | _| \ \ / // _ \| '_ \ | __| | |_| | / _` || '_ \ / _` || | / _ \| '__| //
603 // | |___ \ V /| __/| | | || |_ | _ || (_| || | | || (_| || || __/| | //
604 // |_____| \_/ \___||_| |_| \__| |_| |_| \__,_||_| |_| \__,_||_| \___||_| //
605 // //
606 // //
608 
609 
610 
611 int FWEditWindowEvent(Window wID, XEvent *pEvent)
612 {
613 WBEditWindow *pE;
614 GC gc;
615 WB_GEOM geom;//, geom2;
616 Display *pDisplay = WBGetWindowDisplay(wID);
617 //XFontSet xFontSet;
618 
619 
620  pE = WBEditWindowFromWindowID(wID);
621  if(!pE)
622  {
623  return 0;
624  }
625 
626  switch(pEvent->type)
627  {
628  case Expose:
629 // WB_ERROR_PRINT("TEMPORARY: %s - expose event\n", __FUNCTION__);
630  geom.x = pEvent->xexpose.x;
631  geom.y = pEvent->xexpose.y;
632  geom.width = pEvent->xexpose.width;
633  geom.height = pEvent->xexpose.height;
634 
635  // TEMPORARY - just erase the background, for now...
636  gc = WBBeginPaintGeom(wID, &geom);
637 
638  XSetBackground(pDisplay, gc, clrBG.pixel);
639 
640 // WBGetWindowGeom(wID, &geom2);
641 //
642 // // this is client geometry, not window geometry, so fix it
643 // geom2.x = 1; // 1-pixel border
644 // geom2.y = 1;
645 // geom2.width -= 2; // 1 pixel border on BOTH sides
646 // geom2.height -= 2;
647 //
648 // NOTE: for some reason this un-does what happens later in do_expose() ... maybe XSync after?
649 // XSetForeground(pDisplay, gc, clrBG.pixel);
650 // XFillRectangle(pDisplay, wID, gc, geom2.x, geom2.y, geom2.width, geom2.height);
651 
652  XSetForeground(pDisplay, gc, clrFG.pixel);
653 
654  // TODO: 'split' handling - 2 different sections must be painted separately
655 
656 // xFontSet = pE->childframe.rFontSet;
657 
658  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->do_expose)(&(pE->xTextObject), pDisplay, wID, gc,
659  &geom, // the GEOM to 'paint to'
660  &(pE->childframe.geom),//NULL,//&geom2, // the GEOM bordering the window's viewport (NULL for ALL)
661  pE->childframe.rFontSet);
662  WBEndPaint(wID, gc);
663 
664 // if(xFontSet)
665 // {
666 // XFreeFontSet(pDisplay, xFontSet);
667 // }
668 
669  return 1; // "handled"
670 
671  case DestroyNotify:
672  // if I'm destroying ME, then I must free up the structure.
673  // if this callback is being called, assume NOT recursive.
674 
675  if(pEvent->xdestroywindow.window == wID)
676  {
677  pE->childframe.wID = None; // assign 'none' as the window ID, since I already destroyed it. don't re-destroy it.
678 
679  WBDestroyEditWindow(pE); // this should fix everything else.
680 
681  return 1; // handled
682  }
683 
684  break;
685 
686  case ClientMessage:
687  if(pEvent->xclient.message_type == aRESIZE_NOTIFY ||
688  pEvent->xclient.message_type == aRECALC_LAYOUT)
689  {
690  WB_RECT rctView;
691 
692  rctView.top = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_row)(&(pE->xTextObject)) : 0;
693  rctView.left = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_col)(&(pE->xTextObject)) : 0;
694 
695  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->get_view)(&(pE->xTextObject), &rctView);
696 
697  // TODO: process re-calculation of the extents, etc.
698 
700  rctView.top,
701  CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_rows)(&(pE->xTextObject)) : 0,
702  rctView.left,
703  CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_cols)(&(pE->xTextObject)) : 0,
705  WBFontSetDescent(pDisplay, pE->childframe.rFontSet)),
706  WBFontSetAvgCharWidth(pDisplay, pE->childframe.rFontSet));
707 // pE->childframe.pFont->ascent + pE->childframe.pFont->ascent + EDIT_WINDOW_LINE_SPACING,
708  }
709  else if(pEvent->xclient.message_type == aWB_TIMER)
710  {
711  static int iTimerThingy = 0;
712 
713  // only when this tab is visible do I call the callback.
714 
715  if(pE->childframe.pOwner && // just in case
716  FWGetChildFrameIndex(pE->childframe.pOwner, NULL) // focus window's tab index
717  == FWGetChildFrameIndex(pE->childframe.pOwner, &(pE->childframe))) // THIS window's tab index
718  {
719 // WB_ERROR_PRINT("TEMPORARY: %s - timer\n", __FUNCTION__);
720 
721  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_blink)(&(pE->xTextObject), 1);
722 
723  if(iTimerThingy >= 0)
724  {
725  iTimerThingy ++; // again, only when I have the focus do I do this
726  iTimerThingy &= 3;
727 
728  if(!iTimerThingy && pE->szFileName && pE->szFileName[0])
729  {
730  // see if the file was modified
731 
732  int iTemp = WBCheckFileModDateTime(pE->szFileName, pE->llModDateTime);
733 
734  if(iTemp != 0)
735  {
736  iTimerThingy = -1; // so I don't recursively do this
737 
738  if(iTemp > 0)
739  {
741  "File Modified", "This file has been modified on disk - reload?")
742  == IDYES)
743  {
744  // TODO: re-load the file
745 do_file_reload:
747  "File Modified", "file re-load not (yet) implemented");
748  }
749  }
750  else if(iTemp < 0)
751  {
753  "File Modified", "file mod date is OLDER than before - what happened?\n\nDo you want to reload it?")
754  == IDYES)
755  {
756  goto do_file_reload;
757  }
758  }
759 
760  pE->llModDateTime = WBGetFileModDateTime(pE->szFileName); // re-assign so I don't show 'mod' again
761 
762  iTimerThingy = 0; // so I don't eternally BLOCK this
763  }
764  }
765  }
766  }
767  }
768  else if(pEvent->xclient.message_type == aQUERY_CLOSE)
769  {
770  if(pE->pUserCallback)
771  {
772  int iRval = pE->pUserCallback(wID, pEvent); // allow the user callback to determine when to close
773 
774  if(iRval)
775  {
776  return iRval;
777  }
778  }
779 
780  return 0; // for now, just return 'ok to close' whether I've saved or not
781  }
782  }
783 
784  return 0; // "not handled"
785 }
786 
787 
788 
790 // //
791 // _ _ ___ ____ _ _ _ _ //
792 // | | | ||_ _| / ___| __ _ | || || |__ __ _ ___ | | __ //
793 // | | | | | | | | / _` || || || '_ \ / _` | / __|| |/ / //
794 // | |_| | | | | |___| (_| || || || |_) || (_| || (__ | < //
795 // \___/ |___| \____|\__,_||_||_||_.__/ \__,_| \___||_|\_\ //
796 // //
797 // //
799 
800 
801 static void internal_update_status_text(WBEditWindow *pE) // called whenever cursor position changes.
802 {
803 WBChildFrame *pC = &(pE->childframe);
804 int iR, iC;
805 char tbuf[1024];
806 
807  CALLBACK_TRACKER;
808 
809  if(!WBIsValidEditWindow(pE))
810  {
811  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
812 
813  return;
814  }
815 
816  internal_get_row_col(pC, &iR, &iC);
817 
818  if(pC->szStatusText)
819  {
820  WBFree(pC->szStatusText);
821  pC->szStatusText = NULL;
822  }
823 
824  snprintf(tbuf, sizeof(tbuf), "Row,Col: %d,%d\tlines: %d width: %d\t%s\t",
825  iR, iC,
826  CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_rows)(&(pE->xTextObject)) : 0,
827  CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_cols)(&(pE->xTextObject)) : 0,
828  (const char *)((CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_insmode)(&(pE->xTextObject)) : 0)
829  == InsertMode_INSERT ? "INS" :
830  (const char *)((CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_insmode)(&(pE->xTextObject)) : 0)
831  == InsertMode_OVERWRITE ? "OVR" : "???")));
832 
833  pC->szStatusText = WBCopyString(tbuf);
834 
835  if(!pC->szStatusText)
836  {
837  WB_ERROR_PRINT("ERROR: %s - not enough memory to display status\n", __FUNCTION__);
838  }
839 
841 }
842 
843 static void internal_new_cursor_pos(WBEditWindow *pE) // called whenever cursor position changes.
844 {
845  CALLBACK_TRACKER;
846 
847  if(WBIsValidEditWindow(pE))
848  {
849  internal_update_status_text(pE);
850 
851  // see if the row exceeds the viewport, and if that's the case, scroll it.
852 
853 
854 
855  // TODO: other things, like messing with the display area, re-calc layout, re-paint, etc.
856  // check to see if top/bottom rows changed, invalidate old line, validate new line, see if
857  // horizontal scrolling entire window or just the cursor, etc. etc. etc.
858  }
859 }
860 
861 static void internal_notify_change(WBChildFrame *pC, int bUndo)
862 {
863 WBEditWindow *pE = (WBEditWindow *)pC;
864 
865  if(!WBIsValidEditWindow(pE))
866  {
867  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
868 
869  return;
870  }
871 
872  if(pE->pUserCallback)
873  {
874  XClientMessageEvent evt;
875 
876  bzero(&evt, sizeof(evt));
877 
878  evt.type=ClientMessage;
879  evt.display=WBGetWindowDisplay(pC->wID);
880  evt.window=pC->wID;
881  evt.message_type=aEW_EDIT_CHANGE;
882  evt.format=32;
883 
884  evt.data.l[0] = bUndo;
885  evt.data.l[1] = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_row)(&(pE->xTextObject)) : 0;
886  evt.data.l[2] = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_col)(&(pE->xTextObject)) : 0;
887 
888  pE->pUserCallback(pC->wID, (XEvent *)&evt);
889  }
890 }
891 
892 static void internal_do_char(WBChildFrame *pC, XClientMessageEvent *pEvent)
893 {
894 WBEditWindow *pE = (WBEditWindow *)pC;
895 int iKey, iACS, nChar;
896 char *pBuf;
897 
898 
899  CALLBACK_TRACKER;
900 
901  if(!WBIsValidEditWindow(pE))
902  {
903  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
904 
905  return;
906  }
907 
908  // TODO: determine whether or not the character is printable
909 
910  iKey = pEvent->data.l[0]; // result from WBKeyEventProcessKey()
911  iACS = pEvent->data.l[1];
912  nChar = pEvent->data.l[2];
913  pBuf = (char *)&(pEvent->data.l[3]);
914 
915  if(iACS && (iACS & WB_KEYEVENT_ACSMASK) != WB_KEYEVENT_SHIFT) // only SHIFT can be used here
916  {
917  // TODO: handle non-printing chars
918 
919  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
920  WB_ERROR_PRINT("TEMPORARY: %s - beep\n", __FUNCTION__);
921  }
922  else if(CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->has_select)(&(pE->xTextObject)) : 0)
923  {
924 // WB_ERROR_PRINT("TEMPORARY: %s - set text to \"%.*s\"\n", __FUNCTION__, nChar, pBuf);
925  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->set_text)(&(pE->xTextObject), pBuf, nChar);
926  internal_notify_change(pC, 0);
927  }
928  else
929  {
930 // WB_ERROR_PRINT("TEMPORARY: %s - inserting \"%.*s\"\n", __FUNCTION__, nChar, pBuf);
931  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->ins_chars)(&(pE->xTextObject), pBuf, nChar);
932  internal_notify_change(pC, 0);
933  }
934 
935 // {
936 // char *p1 = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_text)(&(pE->xTextObject)) : NULL;
937 //
938 // WB_ERROR_PRINT("TEMPORARY: %s - new text \"%s\"\n", __FUNCTION__, (const char *)(p1 ? p1 : "{null}"));
939 //
940 // if(p1)
941 // {
942 // WBFree(p1);
943 // }
944 // }
945 
946  internal_new_cursor_pos((WBEditWindow *)pC);
947 }
948 
949 static void internal_scancode(WBChildFrame *pC, XClientMessageEvent *pEvent)
950 {
951 WBEditWindow *pE = (WBEditWindow *)pC;
952 
953 
954  CALLBACK_TRACKER;
955 
956  if(!WBIsValidEditWindow(pE))
957  {
958  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
959 
960  return;
961  }
962 
963  // TODO: handle things I might want, like 'indent' which might be ctrl+[ or ctrl+], or maybe
964  // ctrl+tab or ctrl+shift+tab
965 
966 
967  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
968 }
969 
970 static void internal_bkspace(WBChildFrame *pC, int iACS)
971 {
972 WBEditWindow *pE = (WBEditWindow *)pC;
973 
974 
975  CALLBACK_TRACKER;
976 
977  if(!WBIsValidEditWindow(pE))
978  {
979  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
980 
981  return;
982  }
983 
984  if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with backspace. yet.
985  {
986  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
987  }
988  else
989  {
990  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->del_chars)(&(pE->xTextObject), -1);
991  internal_notify_change(pC, 0);
992  }
993 
994  internal_new_cursor_pos((WBEditWindow *)pC);
995 }
996 
997 static void internal_del(WBChildFrame *pC, int iACS)
998 {
999 WBEditWindow *pE = (WBEditWindow *)pC;
1000 
1001 
1002  CALLBACK_TRACKER;
1003 
1004  if(!WBIsValidEditWindow(pE))
1005  {
1006  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1007 
1008  return;
1009  }
1010 
1011  // shift+del does 'cut' behavior
1012 
1013  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift+del
1014  {
1015  if(!(CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->has_select)(&(pE->xTextObject)) : 0))
1016  {
1017  // no selection, can't "cut"
1018  XBell(WBGetWindowDisplay(pC->wID), -100);
1019  }
1020  else
1021  {
1022  // copy selection to the clipboard, then delete - same as internal_cut_to_cb()
1023 
1024  char *p1 = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_sel_text)(&(pE->xTextObject), NULL): NULL;
1025  if(p1)
1026  {
1027  WBSetClipboardData(WBGetWindowDisplay(pC->wID), aUTF8_STRING, 8, p1, strlen(p1) + 1);
1028 
1029  WBFree(p1);
1030 
1031  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->del_select)(&(pE->xTextObject));
1032  internal_notify_change(pC, 0);
1033  }
1034  }
1035  }
1036  else if(CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->has_select)(&(pE->xTextObject)) : 0)
1037  {
1038  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->del_select)(&(pE->xTextObject));
1039  internal_notify_change(pC, 0);
1040  }
1041  else
1042  {
1043  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->del_chars)(&(pE->xTextObject), 1);
1044  internal_notify_change(pC, 0);
1045  }
1046 
1047  internal_new_cursor_pos((WBEditWindow *)pC);
1048 }
1049 
1050 static void internal_tab(WBChildFrame *pC, int iACS)
1051 {
1052 WBEditWindow *pE = (WBEditWindow *)pC;
1053 
1054 
1055  CALLBACK_TRACKER;
1056 
1057  if(!WBIsValidEditWindow(pE))
1058  {
1059  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1060 
1061  return;
1062  }
1063 
1064  // if there's a selection, indent it??
1065 
1066  if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with tab. yet.
1067  {
1068  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1069  }
1070  else
1071  {
1072  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->ins_chars)(&(pE->xTextObject), "\t", 1);
1073  internal_notify_change(pC, 0);
1074  }
1075 
1076  internal_new_cursor_pos((WBEditWindow *)pC);
1077 }
1078 
1079 static void internal_enter(WBChildFrame *pC, int iACS)
1080 {
1081 WBEditWindow *pE = (WBEditWindow *)pC;
1082 
1083 
1084  CALLBACK_TRACKER;
1085 
1086  if(!WBIsValidEditWindow(pE))
1087  {
1088  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1089 
1090  return;
1091  }
1092 
1093  if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'enter'. yet.
1094  {
1095  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1096  }
1097  else
1098  {
1099  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->ins_chars)(&(pE->xTextObject), "\n", 1);
1100  internal_notify_change(pC, 0);
1101  }
1102 
1103  internal_new_cursor_pos((WBEditWindow *)pC);
1104 }
1105 
1106 static void internal_properties(WBChildFrame *pC)
1107 {
1108 WBEditWindow *pE = (WBEditWindow *)pC;
1109 WBDialogWindow *pDlg;
1110 int iX, iY;
1111 WB_GEOM geomParent;
1112 Window wIDDlg;
1113 struct _PROPERTY_DLG_ propdlg;
1114 static const char szPropertiesDlgBox[]=
1115  "BEGIN_DIALOG FONT:Variable HEIGHT:200 WIDTH:300 TITLE:\"Document Properties\"\n"
1116  " CONTROL:Text TITLE:\"Document Properties\" X:30 Y:2 WIDTH:240 HEIGHT:17 VISIBLE HALIGN_TEXT_CENTER VALIGN_TEXT_CENTER\n"
1117  " CONTROL:CheckButton ID:1001 TITLE:\"Use Hard _Tabs\" X:40 Y:38 WIDTH:80 HEIGHT:15 VISIBLE\n"
1118  " CONTROL:Text TITLE:\"Line ending:\" X:10 Y:51 WIDTH:60 HEIGHT:17 VISIBLE HALIGN_TEXT_RIGHT VALIGN_TEXT_CENTER NOBORDER\n"
1119  " CONTROL:FirstRadioButton ID:1002 TITLE:\"_LF\" X:70 Y:52 WIDTH:40 HEIGHT:15 VISIBLE HALIGN_TEXT_LEFT VALIGN_TEXT_CENTER CHECKED\n"
1120  " CONTROL:RadioButton ID:1003 TITLE:\"C_R\" X:110 Y:52 WIDTH:40 HEIGHT:15 HALIGN_TEXT_LEFT VALIGN_TEXT_CENTER VISIBLE\n"
1121  " CONTROL:RadioButton ID:1004 TITLE:\"_CR+LF\" X:150 Y:52 WIDTH:40 HEIGHT:15 HALIGN_TEXT_LEFT VALIGN_TEXT_CENTER VISIBLE\n"
1122  " CONTROL:DefPushButton ID:IDOK TITLE:Sa_ve X:80 Y:178 WIDTH:40 HEIGHT:18 VISIBLE\n"
1123  " CONTROL:CancelButton ID:IDCANCEL TITLE:Cancel X:180 Y:178 WIDTH:40 HEIGHT:18 VISIBLE\n"
1124  "END_DIALOG\n";
1125 
1126 
1127  CALLBACK_TRACKER;
1128 
1129  if(!WBIsValidEditWindow(pE))
1130  {
1131  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1132 
1133  return;
1134  }
1135 
1136  // TODO: check for owner-defined property dialog and display default if none
1137 
1138  WBGetWindowGeom0(pC->wID, &geomParent); // parent geometry in absolute coordinates
1139 
1140  iX = geomParent.x + geomParent.border + 50;
1141  iY = geomParent.y + geomParent.border - 50;
1142 
1143  propdlg.pEditWindow = pE; // custom data sent to dialog box
1144 
1145  pDlg = DLGCreateDialogWindow("Document Properties", szPropertiesDlgBox, iX, iY,
1146  300, 200, // the values also specified in the resource
1147  PropertyDialogCallback,
1148  WBDialogWindow_VISIBLE, &propdlg);
1149 
1150 
1151  if(pDlg) // TODO: manage this stuff as part of 'DLGCreateDialogWindow' instead
1152  {
1153  wIDDlg = pDlg->wID;
1154 
1155  if(pC->wID != None) // owned dialog box needs certain properties set
1156  {
1157  Atom a1;
1158  unsigned int ai1[3];
1159 
1160  DLGAssignOwner(pDlg, pC->wID);
1161 
1162  a1 = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE", False);
1163  ai1[0] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", False);
1164  ai1[1] = XInternAtom(WBGetDefaultDisplay(), "_NET_WM_STATE_SKIP_PAGER", False);
1165 
1166  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_ATOM, 32, PropModeReplace, (unsigned char *)ai1, 2);
1167 
1168  a1 = XInternAtom(WBGetWindowDisplay(wIDDlg), "WM_TRANSIENT_FOR", False);
1169  XChangeProperty(WBGetWindowDisplay(wIDDlg), wIDDlg, a1, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&(pC->wID), 1);
1170  }
1171 
1172 // WBSetWindowIcon(wIDDlg, );
1173 // WB_ERROR_PRINT("TEMPORARY: %s - calling WBShowModal\n", __FUNCTION__);
1174 
1175  if(WBShowModal(wIDDlg, 0) == IDOK)
1176  {
1178 // WBInvalidateGeom(pC->wID, NULL, 1); // invalidate and re-paint with new properties, etc. configured
1179  }
1180  }
1181 
1182 }
1183 
1184 static void internal_uparrow(WBChildFrame *pC, int iACS)
1185 {
1186 WBEditWindow *pE = (WBEditWindow *)pC;
1187 
1188 
1189  CALLBACK_TRACKER;
1190 
1191  if(!WBIsValidEditWindow(pE))
1192  {
1193  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1194 
1195  return;
1196  }
1197 
1198  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-uparrow
1199  {
1200  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1201  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_up)(&(pE->xTextObject));
1202  }
1203  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-uparrow
1204  {
1205  // select to start of paragraph?
1206  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1207  }
1208  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'up'. yet.
1209  {
1210  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1211  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1212  }
1213  else
1214  {
1215  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1216  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_up)(&(pE->xTextObject));
1217  }
1218 
1219  internal_new_cursor_pos((WBEditWindow *)pC);
1220 }
1221 
1222 static void internal_downarrow(WBChildFrame *pC, int iACS)
1223 {
1224 WBEditWindow *pE = (WBEditWindow *)pC;
1225 
1226 
1227  CALLBACK_TRACKER;
1228 
1229  if(!WBIsValidEditWindow(pE))
1230  {
1231  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1232 
1233  return;
1234  }
1235 
1236  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-downarrow
1237  {
1238  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1239  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_down)(&(pE->xTextObject));
1240  }
1241  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-downarrow
1242  {
1243  // select to start of paragraph?
1244  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1245  }
1246  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'up'. yet.
1247  {
1248  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1249  }
1250  else
1251  {
1252  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1253  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_down)(&(pE->xTextObject));
1254  }
1255 
1256  internal_new_cursor_pos((WBEditWindow *)pC);
1257 }
1258 
1259 static void internal_leftarrow(WBChildFrame *pC, int iACS)
1260 {
1261 WBEditWindow *pE = (WBEditWindow *)pC;
1262 
1263 
1264  CALLBACK_TRACKER;
1265 
1266  if(!WBIsValidEditWindow(pE))
1267  {
1268  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1269 
1270  return;
1271  }
1272 
1273  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-leftarrow
1274  {
1275  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1276  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_left)(&(pE->xTextObject));
1277  }
1278  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-leftarrow
1279  {
1280  // select to start of previous word? end of previous word?
1281  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1282  }
1283  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'left'. yet.
1284  {
1285  WB_ERROR_PRINT("TEMPORARY: %s - iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1286 
1287  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1288  }
1289  else
1290  {
1291  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1292  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_left)(&(pE->xTextObject));
1293  }
1294 
1295  internal_new_cursor_pos((WBEditWindow *)pC);
1296 }
1297 
1298 static void internal_rightarrow(WBChildFrame *pC, int iACS)
1299 {
1300 WBEditWindow *pE = (WBEditWindow *)pC;
1301 
1302 
1303  CALLBACK_TRACKER;
1304 
1305  if(!WBIsValidEditWindow(pE))
1306  {
1307  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1308 
1309  return;
1310  }
1311 
1312  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-rightarrow
1313  {
1314  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1315  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_right)(&(pE->xTextObject));
1316  }
1317  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-rightarrow
1318  {
1319  // select to end of word? start of next word?
1320  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1321  }
1322  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'right'. yet.
1323  {
1324  WB_ERROR_PRINT("TEMPORARY: %s - iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1325 
1326  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1327  }
1328  else
1329  {
1330  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1331  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_right)(&(pE->xTextObject));
1332  }
1333 
1334  internal_new_cursor_pos((WBEditWindow *)pC);
1335 }
1336 
1337 static void internal_home(WBChildFrame *pC, int iACS)
1338 {
1339 WBEditWindow *pE = (WBEditWindow *)pC;
1340 
1341 
1342  CALLBACK_TRACKER;
1343 
1344  if(!WBIsValidEditWindow(pE))
1345  {
1346  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1347 
1348  return;
1349  }
1350 
1351  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-home
1352  {
1353  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1354  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_home)(&(pE->xTextObject));
1355  }
1356  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-home
1357  {
1358  // select to start of document
1359  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1360  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_top)(&(pE->xTextObject));
1361  }
1362  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control+home
1363  {
1364  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1365  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_top)(&(pE->xTextObject));
1366  }
1367  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling shift, or alt with 'home'. yet.
1368  {
1369  WB_ERROR_PRINT("TEMPORARY: %s - iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1370 
1371  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1372  }
1373  else
1374  {
1375  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1376  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_home)(&(pE->xTextObject));
1377  }
1378 
1379  internal_new_cursor_pos((WBEditWindow *)pC);
1380 }
1381 
1382 static void internal_end(WBChildFrame *pC, int iACS)
1383 {
1384 WBEditWindow *pE = (WBEditWindow *)pC;
1385 
1386 
1387  CALLBACK_TRACKER;
1388 
1389  if(!WBIsValidEditWindow(pE))
1390  {
1391  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1392 
1393  return;
1394  }
1395 
1396  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-end
1397  {
1398  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1399  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_end)(&(pE->xTextObject));
1400  }
1401  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-end
1402  {
1403  // select to end of document
1404  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1405  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_bottom)(&(pE->xTextObject));
1406  }
1407  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control+end
1408  {
1409  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1410  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_bottom)(&(pE->xTextObject));
1411  }
1412  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling shift, or alt with 'end'. yet.
1413  {
1414  WB_ERROR_PRINT("TEMPORARY: %s - iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1415 
1416  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1417  }
1418  else
1419  {
1420  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1421  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->cursor_end)(&(pE->xTextObject));
1422  }
1423 
1424  internal_new_cursor_pos((WBEditWindow *)pC);
1425 }
1426 
1427 static void internal_pgup(WBChildFrame *pC, int iACS)
1428 {
1429 WBEditWindow *pE = (WBEditWindow *)pC;
1430 
1431 
1432  CALLBACK_TRACKER;
1433 
1434  if(!WBIsValidEditWindow(pE))
1435  {
1436  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1437 
1438  return;
1439  }
1440 
1441  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-pgup
1442  {
1443  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1444  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->page_up)(&(pE->xTextObject));
1445  }
1446  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl or alt. yet.
1447  {
1448  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1449  }
1450  else
1451  {
1452 // WB_ERROR_PRINT("TEMPORARY: %s - WBChildFrame calling 'page_up'\n", __FUNCTION__);
1453 
1454  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1455  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->page_up)(&(pE->xTextObject));
1456  }
1457 
1458  internal_new_cursor_pos((WBEditWindow *)pC);
1459 }
1460 
1461 static void internal_pgdown(WBChildFrame *pC, int iACS)
1462 {
1463 WBEditWindow *pE = (WBEditWindow *)pC;
1464 
1465 
1466  CALLBACK_TRACKER;
1467 
1468  if(!WBIsValidEditWindow(pE))
1469  {
1470  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1471 
1472  return;
1473  }
1474 
1475  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-pgdown
1476  {
1477  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1478  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->page_down)(&(pE->xTextObject));
1479  }
1480  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl or alt. yet.
1481  {
1482  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1483  }
1484  else
1485  {
1486 // WB_ERROR_PRINT("TEMPORARY: %s - WBChildFrame calling 'page_down'\n", __FUNCTION__);
1487 
1488  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1489  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->page_down)(&(pE->xTextObject));
1490  }
1491 
1492  internal_new_cursor_pos((WBEditWindow *)pC);
1493 }
1494 
1495 static void internal_pgleft(WBChildFrame *pC, int iACS)
1496 {
1497 WBEditWindow *pE = (WBEditWindow *)pC;
1498 
1499 
1500  CALLBACK_TRACKER;
1501 
1502  if(!WBIsValidEditWindow(pE))
1503  {
1504  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1505 
1506  return;
1507  }
1508 
1509  if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-pgup
1510  {
1511  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1512  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->page_left)(&(pE->xTextObject));
1513  }
1514  else if((iACS & WB_KEYEVENT_ACSMASK) != WB_KEYEVENT_CTRL) // not handling alt with 'pgup'. yet.
1515  {
1516  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1517  }
1518  else // CTRL-pgup
1519  {
1520  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1521  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->page_left)(&(pE->xTextObject));
1522  }
1523 
1524  internal_new_cursor_pos((WBEditWindow *)pC);
1525 }
1526 
1527 static void internal_pgright(WBChildFrame *pC, int iACS)
1528 {
1529 WBEditWindow *pE = (WBEditWindow *)pC;
1530 
1531 
1532  CALLBACK_TRACKER;
1533 
1534  if(!WBIsValidEditWindow(pE))
1535  {
1536  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1537 
1538  return;
1539  }
1540 
1541  if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-pgdn
1542  {
1543  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1544  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->page_right)(&(pE->xTextObject));
1545  }
1546  else if((iACS & WB_KEYEVENT_ACSMASK) != WB_KEYEVENT_CTRL) // not handling alt with 'pgup'. yet.
1547  {
1548  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1549  }
1550  else
1551  {
1552  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_highlight)(&(pE->xTextObject)); // safe to call any time, multiple times
1553  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->page_right)(&(pE->xTextObject));
1554  }
1555 
1556  internal_new_cursor_pos((WBEditWindow *)pC);
1557 }
1558 
1559 static void internal_help(WBChildFrame *pC, int iACS)
1560 {
1561 WBEditWindow *pE = (WBEditWindow *)pC;
1562 
1563 
1564  CALLBACK_TRACKER;
1565 
1566  if(!WBIsValidEditWindow(pE))
1567  {
1568  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1569 
1570  return;
1571  }
1572 
1573 }
1574 
1575 static void internal_hover_notify(WBChildFrame *pC, int x, int y)
1576 {
1577 WBEditWindow *pE = (WBEditWindow *)pC;
1578 
1579 
1580  CALLBACK_TRACKER;
1581 
1582  if(!WBIsValidEditWindow(pE))
1583  {
1584  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1585 
1586  return;
1587  }
1588 
1589 }
1590 
1591 static void internal_hover_cancel(WBChildFrame *pC)
1592 {
1593 WBEditWindow *pE = (WBEditWindow *)pC;
1594 
1595 
1596  CALLBACK_TRACKER;
1597 
1598  if(!WBIsValidEditWindow(pE))
1599  {
1600  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1601 
1602  return;
1603  }
1604 
1605 }
1606 
1607 static int internal_is_ins_mode(WBChildFrame *pC)
1608 {
1609 WBEditWindow *pE = (WBEditWindow *)pC;
1610 
1611 
1612  CALLBACK_TRACKER;
1613 
1614  if(!WBIsValidEditWindow(pE))
1615  {
1616  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1617 
1618  return -1;
1619  }
1620 
1621  return (CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_insmode)(&(pE->xTextObject)) : InsertMode_INSERT)
1622  == InsertMode_INSERT;
1623 }
1624 
1625 static void internal_toggle_ins_mode(WBChildFrame *pC)
1626 {
1627 WBEditWindow *pE = (WBEditWindow *)pC;
1628 int iInsMode;
1629 
1630 
1631  CALLBACK_TRACKER;
1632 
1633  if(!WBIsValidEditWindow(pE))
1634  {
1635  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1636 
1637  return;
1638  }
1639 
1640  iInsMode = (CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_insmode)(&(pE->xTextObject)) : InsertMode_INSERT)
1641  == InsertMode_INSERT;
1642  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->set_insmode)(&(pE->xTextObject), iInsMode ? InsertMode_OVERWRITE : InsertMode_INSERT);
1643 
1644  internal_new_cursor_pos((WBEditWindow *)pC);
1645  internal_update_status_text(pE);
1646 }
1647 
1648 static void internal_copy_to_cb(WBChildFrame *pC)
1649 {
1650 WBEditWindow *pE = (WBEditWindow *)pC;
1651 char *p1;
1652 
1653 
1654  CALLBACK_TRACKER;
1655 
1656  if(!WBIsValidEditWindow(pE))
1657  {
1658  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1659 
1660  return;
1661  }
1662 
1663  // copy selection to the clipboard
1664 
1665  if(CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->has_select)(&(pE->xTextObject)) : 0)
1666  {
1667  p1 = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_sel_text)(&(pE->xTextObject), NULL) : NULL;
1668 
1669  if(p1)
1670  {
1671  WBSetClipboardData(WBGetWindowDisplay(pC->wID), aUTF8_STRING, 8, p1, strlen(p1) + 1);
1672 
1673  WBFree(p1);
1674  }
1675  }
1676  else
1677  {
1678  // no selection, can't "copy"
1679 
1680  XBell(WBGetWindowDisplay(pC->wID), -100);
1681  }
1682 }
1683 
1684 static void internal_paste_from_cb(WBChildFrame *pC)
1685 {
1686 WBEditWindow *pE = (WBEditWindow *)pC;
1687 Atom aType = aUTF8_STRING;
1688 int iFormat = 8;
1689 unsigned long nData = 0;
1690 char *p1;
1691 
1692 
1693  CALLBACK_TRACKER;
1694 
1695  if(!WBIsValidEditWindow(pE))
1696  {
1697  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1698 
1699  return;
1700  }
1701 
1702  // copy selection to the clipboard, then delete - same as internal_cut_to_cb()
1703 
1704  p1 = (char *)WBGetClipboardData(WBGetWindowDisplay(pC->wID), &aType, &iFormat, &nData);
1705  if(!p1) // try regular string, not UTF8
1706  {
1707  aType = aSTRING;
1708  p1 = (char *)WBGetClipboardData(WBGetWindowDisplay(pC->wID), &aType, &iFormat, &nData);
1709  }
1710 
1711  if(p1 && nData > 0)
1712  {
1713  if(!p1[nData - 1])
1714  {
1715  nData--;
1716  }
1717  }
1718 
1719 
1720  if(p1)
1721  {
1722  // TODO: convert to correct format (ASCII)
1723  if(iFormat != 8) // 16-bit unicode is assumed now
1724  {
1725  if(iFormat == 8 * sizeof(wchar_t))
1726  {
1727  char *pNew = WBAlloc(sizeof(wchar_t) * (nData + 2));
1728  if(pNew)
1729  {
1730  bzero(pNew, sizeof(wchar_t) * (nData + 2));
1731  wcstombs(pNew, (const wchar_t *)p1, sizeof(wchar_t) * (nData + 2));
1732  }
1733 
1734  WBFree(p1);
1735  p1 = pNew;
1736  nData = strlen(p1);
1737  }
1738  else
1739  {
1740  XBell(WBGetWindowDisplay(pC->wID), -100);
1741  WB_ERROR_PRINT("TEMPORARY - %s - clipboard format %d, can't 'PASTE'\n", __FUNCTION__, iFormat);
1742 
1743  WBFree(p1);
1744  p1 = NULL; // by convention - also, checked in next section
1745  }
1746  }
1747 
1748  if(p1)
1749  {
1750  WBDebugDump("Edit window 'paste'", p1, nData);
1751 
1752  if(CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->has_select)(&(pE->xTextObject)) : 0)
1753  {
1754  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->replace_select)(&(pE->xTextObject), p1, nData);
1755  internal_notify_change(pC, 0);
1756  }
1757  else
1758  {
1759  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->ins_chars)(&(pE->xTextObject), p1, nData);
1760  internal_notify_change(pC, 0);
1761  }
1762 
1763  WBFree(p1);
1764  p1 = NULL; // by convention
1765  }
1766  }
1767 
1768  internal_new_cursor_pos((WBEditWindow *)pC);
1769 }
1770 
1771 static void internal_cut_to_cb(WBChildFrame *pC)
1772 {
1773 WBEditWindow *pE = (WBEditWindow *)pC;
1774 
1775 
1776  CALLBACK_TRACKER;
1777 
1778  if(!WBIsValidEditWindow(pE))
1779  {
1780  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1781 
1782  return;
1783  }
1784 
1785  if(!(CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->has_select)(&(pE->xTextObject)) : 0))
1786  {
1787  // no selection, can't "cut"
1788  XBell(WBGetWindowDisplay(pC->wID), -100);
1789  }
1790  else
1791  {
1792  // copy selection to the clipboard, then delete - same as internal_cut_to_cb()
1793 
1794  char *p1 = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_sel_text)(&(pE->xTextObject), NULL) : NULL;
1795  if(p1)
1796  {
1797  WBSetClipboardData(WBGetWindowDisplay(pC->wID), aUTF8_STRING, 8, p1, strlen(p1) + 1);
1798 
1799  WBFree(p1);
1800 
1801  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->del_select)(&(pE->xTextObject));
1802  internal_notify_change(pC, 0);
1803  }
1804  }
1805 
1806  internal_new_cursor_pos((WBEditWindow *)pC);
1807 }
1808 
1809 static void internal_delete_sel(WBChildFrame *pC)
1810 {
1811 WBEditWindow *pE = (WBEditWindow *)pC;
1812 
1813 
1814  CALLBACK_TRACKER;
1815 
1816  if(!WBIsValidEditWindow(pE))
1817  {
1818  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1819 
1820  return;
1821  }
1822 
1823  if(!(CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->has_select)(&(pE->xTextObject)) : 0))
1824  {
1825  // no selection, can't "cut"
1826  XBell(WBGetWindowDisplay(pC->wID), -100);
1827  }
1828  else
1829  {
1830  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->del_select)(&(pE->xTextObject));
1831  internal_notify_change(pC, 0);
1832  }
1833 
1834  internal_new_cursor_pos((WBEditWindow *)pC);
1835 }
1836 
1837 static void internal_select_all(WBChildFrame *pC)
1838 {
1839 WBEditWindow *pE = (WBEditWindow *)pC;
1840 WB_RECT rct;
1841 
1842 
1843  CALLBACK_TRACKER;
1844 
1845  if(!WBIsValidEditWindow(pE))
1846  {
1847  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1848 
1849  return;
1850  }
1851 
1852  rct.left = rct.top = 0;
1853  rct.right = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_cols)(&(pE->xTextObject)) : 0;
1854  rct.bottom = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_rows)(&(pE->xTextObject)) : 0;
1855 
1856  WB_ERROR_PRINT("TEMPORARY: %s - selecting %d,%d,%d,%d\n", __FUNCTION__,
1857  rct.left, rct.top, rct.right, rct.bottom);
1858 
1859  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->set_select)(&(pE->xTextObject), &rct); // select 'all'
1860 
1861 //#if 1
1862 // CALLBACK_CHECK_NULL(pE->xTextObject.vtable->get_select)(&(pE->xTextObject), &rct); // get selection for testing
1863 //
1864 // WB_ERROR_PRINT("TEMPORARY: %s - selected %d,%d,%d,%d\n", __FUNCTION__,
1865 // rct.left, rct.top, rct.right, rct.bottom);
1866 //#endif // 1
1867 
1868  internal_new_cursor_pos((WBEditWindow *)pC);
1869 }
1870 
1871 static void internal_select_none(WBChildFrame *pC)
1872 {
1873 WBEditWindow *pE = (WBEditWindow *)pC;
1874 
1875 
1876  CALLBACK_TRACKER;
1877 
1878  if(!WBIsValidEditWindow(pE))
1879  {
1880  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1881 
1882  return;
1883  }
1884 
1885  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->set_select)(&(pE->xTextObject), NULL);
1886 
1887  internal_new_cursor_pos((WBEditWindow *)pC);
1888 }
1889 
1890 static void internal_save(WBChildFrame *pC, const char *szFileName)
1891 {
1892 WBEditWindow *pE = (WBEditWindow *)pC;
1893 
1894 
1895  CALLBACK_TRACKER;
1896 
1897  if(!WBIsValidEditWindow(pE))
1898  {
1899  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1900 
1901  return;
1902  }
1903 
1904  WBEditWindowSaveFile(pE, szFileName);
1905 }
1906 
1907 static WB_PCSTR internal_get_file_name(WBChildFrame *pC)
1908 {
1909 WBEditWindow *pE = (WBEditWindow *)pC;
1910 
1911 
1912  CALLBACK_TRACKER;
1913 
1914  if(!WBIsValidEditWindow(pE))
1915  {
1916  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1917 
1918  return NULL;
1919  }
1920 
1921  return pE->szFileName;
1922 }
1923 
1924 static void internal_mouse_click(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1925 {
1926 WBEditWindow *pE = (WBEditWindow *)pC;
1927 
1928 
1929  CALLBACK_TRACKER;
1930 
1931  if(!WBIsValidEditWindow(pE))
1932  {
1933  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1934 
1935  return;
1936  }
1937 
1938  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->mouse_click)(&(pE->xTextObject), iX, iY, iButtonMask, iACS);
1939 
1940  internal_new_cursor_pos((WBEditWindow *)pC);
1941 }
1942 
1943 static void internal_mouse_dblclick(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1944 {
1945 WBEditWindow *pE = (WBEditWindow *)pC;
1946 
1947 
1948  CALLBACK_TRACKER;
1949 
1950  if(!WBIsValidEditWindow(pE))
1951  {
1952  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1953 
1954  return;
1955  }
1956 
1957  // TODO: select the current 'word'?
1958 
1959  internal_new_cursor_pos((WBEditWindow *)pC);
1960 }
1961 
1962 static void internal_mouse_drag(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1963 {
1964 WBEditWindow *pE = (WBEditWindow *)pC;
1965 
1966 
1967  CALLBACK_TRACKER;
1968 
1969  if(!WBIsValidEditWindow(pE))
1970  {
1971  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1972 
1973  return;
1974  }
1975 
1976  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->begin_mouse_drag)(&(pE->xTextObject));
1977 
1978  internal_new_cursor_pos((WBEditWindow *)pC);
1979 }
1980 
1981 static void internal_mouse_drop(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1982 {
1983 WBEditWindow *pE = (WBEditWindow *)pC;
1984 
1985 
1986  CALLBACK_TRACKER;
1987 
1988  if(!WBIsValidEditWindow(pE))
1989  {
1990  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1991 
1992  return;
1993  }
1994 
1995  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->end_mouse_drag)(&(pE->xTextObject));
1996 
1997  internal_new_cursor_pos((WBEditWindow *)pC);
1998 }
1999 
2000 static void internal_mouse_move(WBChildFrame *pC, int iX, int iY)
2001 {
2002 WBEditWindow *pE = (WBEditWindow *)pC;
2003 
2004 
2005  CALLBACK_TRACKER;
2006 
2007  if(!WBIsValidEditWindow(pE))
2008  {
2009  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2010 
2011  return;
2012  }
2013 
2014  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->mouse_click)(&(pE->xTextObject), iX, iY, 0, 0); // report mouse motion
2015 
2016  internal_new_cursor_pos((WBEditWindow *)pC);
2017 }
2018 
2019 static void internal_scroll_vert(WBChildFrame *pC, int iMode, int iValue)
2020 {
2021 WBEditWindow *pE = (WBEditWindow *)pC;
2022 
2023  CALLBACK_TRACKER;
2024 
2025  if(!WBIsValidEditWindow(pE))
2026  {
2027  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2028 
2029  return;
2030  }
2031 
2032  // TODO: check scroll mode for scroll lock?
2033 
2034  if(iMode == 0) // absolute
2035  {
2036  if(pE->xTextObject.vtable->get_view)
2037  {
2038  WB_RECT rctView;
2039  WB_POINT ptScroll;
2040 
2041  pE->xTextObject.vtable->get_view(&(pE->xTextObject), &rctView);
2042 
2043  if(iValue == rctView.top) // not moving
2044  {
2045  return;
2046  }
2047 
2048  ptScroll.x = rctView.left;
2049  ptScroll.y = iValue;
2050 
2051  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->set_view_orig)(&(pE->xTextObject), &ptScroll);
2052 
2053  FWSetChildFrameScrollInfo(pC, ptScroll.y, pC->extent.height,
2054  pC->origin.x, pC->extent.width,
2055  pC->iRowHeight, pC->iColWidth);
2056  }
2057  }
2058  else
2059  {
2060  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->scroll_vertical)(&(pE->xTextObject), iValue);
2061 
2063  CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_row)(&(pE->xTextObject))
2064  : pC->origin.y,
2065  pC->extent.height,
2066  pC->origin.x, pC->extent.width,
2067  pC->iRowHeight, pC->iColWidth);
2068  }
2069 
2070  internal_new_cursor_pos((WBEditWindow *)pC);
2071 }
2072 
2073 static void internal_scroll_horiz(WBChildFrame *pC, int iMode, int iValue)
2074 {
2075 WBEditWindow *pE = (WBEditWindow *)pC;
2076 
2077 
2078  CALLBACK_TRACKER;
2079 
2080  if(!WBIsValidEditWindow(pE))
2081  {
2082  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2083 
2084  return;
2085  }
2086 
2087  // TODO: check scroll mode for scroll lock?
2088 
2089  if(iMode == 0) // absolute
2090  {
2091  if(pE->xTextObject.vtable->get_view)
2092  {
2093  WB_RECT rctView;
2094  WB_POINT ptScroll;
2095 
2096  pE->xTextObject.vtable->get_view(&(pE->xTextObject), &rctView);
2097 
2098  if(iValue == rctView.top) // not moving
2099  {
2100  return;
2101  }
2102 
2103  ptScroll.x = iValue;
2104  ptScroll.y = rctView.top;
2105 
2106  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->set_view_orig)(&(pE->xTextObject), &ptScroll);
2107 
2109  ptScroll.x, pC->extent.width,
2110  pC->iRowHeight, pC->iColWidth);
2111  }
2112  }
2113  else
2114  {
2115  CALLBACK_CHECK_NULL(pE->xTextObject.vtable->scroll_horizontal)(&(pE->xTextObject), iValue);
2116 
2118  CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_col)(&(pE->xTextObject))
2119  : pC->origin.x,
2120  pC->extent.width,
2121  pC->iRowHeight, pC->iColWidth);
2122  }
2123 
2124  internal_new_cursor_pos((WBEditWindow *)pC);
2125 }
2126 
2127 static void internal_mouse_cancel(WBChildFrame *pC)
2128 {
2129 WBEditWindow *pE = (WBEditWindow *)pC;
2130 
2131 
2132  CALLBACK_TRACKER;
2133 
2134  if(!WBIsValidEditWindow(pE))
2135  {
2136  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2137 
2138  return;
2139  }
2140 
2141 
2142  internal_new_cursor_pos((WBEditWindow *)pC);
2143 }
2144 
2145 static void internal_get_row_col(WBChildFrame *pC, int *piR, int *piC)
2146 {
2147 WBEditWindow *pE = (WBEditWindow *)pC;
2148 
2149 
2150  CALLBACK_TRACKER;
2151 
2152  if(!WBIsValidEditWindow(pE))
2153  {
2154  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2155 
2156  return;
2157  }
2158 
2159  if(piC)
2160  {
2161  *piC = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_col)(&(pE->xTextObject)) : 0;
2162  }
2163 
2164  if(piR)
2165  {
2166  *piR = CALLBACK_CHECK_NULL2(pE->xTextObject.vtable->get_row)(&(pE->xTextObject)) : 0;
2167  }
2168 }
2169 
2170 static int internal_has_selection(WBChildFrame *pC)
2171 {
2172 WBEditWindow *pE = (WBEditWindow *)pC;
2173 
2174 
2175  CALLBACK_TRACKER;
2176 
2177  if(!WBIsValidEditWindow(pE))
2178  {
2179  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2180 
2181  return 0;
2182  }
2183 
2184  if(pE->xTextObject.vtable->get_select)
2185  {
2186  WB_RECT rctSel;
2187 
2188  pE->xTextObject.vtable->get_select(&(pE->xTextObject), &rctSel);
2189 
2190 // WB_ERROR_PRINT("TEMPORARY: %s - selection rectangle %d,%d,%d,%d\n", __FUNCTION__,
2191 // rctSel.left, rctSel.top, rctSel.right, rctSel.bottom);
2192 
2193  if(rctSel.left != rctSel.right || rctSel.bottom != rctSel.top) // NOT empty
2194  {
2195  return 1; // has a selection
2196  }
2197  }
2198 
2199  return 0; // no current selection
2200 }
2201 
2202 static void internal_undo(WBChildFrame *pC)
2203 {
2204 WBEditWindow *pE = (WBEditWindow *)pC;
2205 
2206 
2207  CALLBACK_TRACKER;
2208 
2209  if(!WBIsValidEditWindow(pE))
2210  {
2211  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2212 
2213  return;
2214  }
2215 
2216  // perform an un-do operation
2217 }
2218 
2219 static void internal_redo(WBChildFrame *pC)
2220 {
2221 WBEditWindow *pE = (WBEditWindow *)pC;
2222 
2223 
2224  CALLBACK_TRACKER;
2225 
2226  if(!WBIsValidEditWindow(pE))
2227  {
2228  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2229 
2230  return;
2231  }
2232 
2233  // perform a re-do operation
2234 }
2235 
2236 static int internal_can_undo(WBChildFrame *pC)
2237 {
2238 WBEditWindow *pE = (WBEditWindow *)pC;
2239 
2240 
2241  CALLBACK_TRACKER;
2242 
2243  if(!WBIsValidEditWindow(pE))
2244  {
2245  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2246 
2247  return 0;
2248  }
2249 
2250  return 0; // can't un-do
2251 }
2252 
2253 static int internal_can_redo(WBChildFrame *pC)
2254 {
2255 WBEditWindow *pE = (WBEditWindow *)pC;
2256 
2257 
2258  CALLBACK_TRACKER;
2259 
2260  if(!WBIsValidEditWindow(pE))
2261  {
2262  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2263 
2264  return 0;
2265  }
2266 
2267  return 0; // can't re-do
2268 }
2269 
2270 
2271 static int internal_is_empty(WBChildFrame *pC)
2272 {
2273 WBEditWindow *pE = (WBEditWindow *)pC;
2274 
2275 
2276  CALLBACK_TRACKER;
2277 
2278  if(!WBIsValidEditWindow(pE))
2279  {
2280  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2281 
2282  return -1; // return '-1' on error
2283  }
2284 
2285  // if the contents are NOT NULL, it's not 'empty'
2286 
2287  if((pE->xTextObject.vtable->get_rows && pE->xTextObject.vtable->get_rows(&(pE->xTextObject)) > 0) ||
2288  (pE->xTextObject.vtable->get_cols && pE->xTextObject.vtable->get_cols(&(pE->xTextObject)) > 0))
2289  {
2290  return 0; // NOT empty
2291  }
2292 
2293  return 1; // empty (for now; later, do I dive directly into xTextObject ??? new API for vtable?)
2294 }
2295 
2296 
2297 
2298 // Properties dialog
2299 
2300 static int PropertyDialogCallback(Window wID, XEvent *pEvent)
2301 {
2303 //struct _PROPERTY_DLG_ *pUserData = (struct _PROPERTY_DLG_ *)(pDlg ? pDlg->pUserData : NULL);
2304 
2305 
2306  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aDIALOG_INIT)
2307  {
2308  if(!pDlg)
2309  {
2310  WB_ERROR_PRINT("%s - no WBDialogWindow structure in DIALOG_INIT for %d (%08xH) %p %08xH %08xH\n", __FUNCTION__,
2311  (unsigned int)wID, (unsigned int)wID, WBGetWindowData(wID, 0), DIALOG_WINDOW_TAG, ((WBDialogWindow *)WBGetWindowData(wID, 0))->ulTag);
2312  return 0; // can't process any messages now
2313  }
2314  else
2315  {
2316 // // assigning the correct icon
2317 //
2318 // Window wIDIcon = DLGGetDialogControl(pDlg, 1000); // ID 1000 for icon
2319 // WBDialogControl *pCtrl = DLGGetDialogControlStruct(wIDIcon);
2320 //
2321 // if(pCtrl)
2322 // {
2323 // Pixmap pixmap2 = None;
2324 // Pixmap pixmap = PXM_GetIconPixmap(GetMessageBoxIconPixmapID(pUserData->iType & MessageBox_ICON_MASK),
2325 // NULL, &pixmap2);
2326 //
2327 // if(pixmap != None)
2328 // {
2329 // WBDialogControlSetIconPixmap(pCtrl, pixmap, pixmap2);
2330 // }
2331 // }
2332  }
2333 
2334 // // assign the caption text to the caption window (which varies and must be assigned at run time)
2335 //
2336 // DLGSetControlCaption((WBDialogWindow *)pDlg, 1001, pUserData->szMessage);
2337 
2338  return 1;
2339  }
2340 
2341  if(!pDlg)
2342  {
2343  WB_WARN_PRINT("MessageBoxCallback - no WBDialogWindow structure\n");
2344  return 0; // can't process any messages now
2345  }
2346 
2347  if(pEvent->type == ClientMessage && pEvent->xclient.message_type == aCONTROL_NOTIFY)
2348  {
2349  WB_DEBUG_PRINT(DebugLevel_Light | DebugSubSystem_Event | DebugSubSystem_Dialog,
2350  "%s - MessageBox ClientMessage CONTROL_NOTIFY\n", __FUNCTION__);
2351 
2352  switch(pEvent->xclient.data.l[1]) // control ID
2353  {
2354  case IDOK:
2355  // TODO: save data
2356 
2357  case IDCANCEL:
2358  if(pEvent->xclient.data.l[0] == aBUTTON_PRESS)
2359  {
2360  WBEndModal(wID, pEvent->xclient.data.l[1]);
2361  }
2362 
2363  break;
2364 
2365  default:
2366  WB_WARN_PRINT("%s - MessageBox ClientMessage CONTROL_NOTIFY client id=%lx\n",
2367  __FUNCTION__, pEvent->xclient.data.l[1]);
2368  }
2369  }
2370 
2371  return 0;
2372 }
2373 
#define IDOK
struct __WBChildFrameUI__ * pUI
pointer to &#39;WBChildFrameUI&#39; function pointer table (assigned by &#39;superclass&#39;)
Definition: frame_window.h:460
int WBEditWindowLoadFile(WBEditWindow *pEditWindow, const char *pszFileName)
Open an existing file and read its contents into the Edit Window, storing the file name for later ref...
Definition: edit_window.c:454
&#39;window helper&#39; main header file for the X11workbench Toolkit API
static __inline__ Display * WBGetDefaultDisplay(void)
Returns the default Display.
int FWInitChildFrame(WBChildFrame *pChildFrame, WBFrameWindow *pOwner, XFontSet rFontSet, const char *szFocusMenu, const WBFWMenuHandler *pHandlerArray, WBWinEvent pUserCallback, int fFlags)
Initialize a child frame (assumed to be a base &#39;class&#39; for the window)
Definition: child_frame.c:118
const TEXT_OBJECT_VTABLE * vtable
method function pointers (similar to C++ virtual member functions)
Definition: text_object.h:951
#define WB_DEBUG_PRINT(L,...)
Preferred method of implementing conditional debug output.
Definition: debug_helper.h:299
void * WBGetWindowData(Window wID, int iIndex)
Gets the data associated with this window and the specified index.
int(* get_rows)(const struct _text_object_ *pThis)
Call this function to obtain the total number of rows for display purposes.
Definition: text_object.h:371
Utilities for copying and drawing text, determining text extents, and so on.
char *(* get_sel_text)(const struct _text_object_ *pThis, const WB_RECT *pRct)
get the current selection rectangle as WB_RECT
Definition: text_object.h:519
void(* scroll_horizontal)(struct _text_object_ *pThis, int nCols)
Scroll the cursor to the right/left a specified number of columns.
Definition: text_object.h:775
WBDialogWindow * DLGCreateDialogWindow(const char *szTitle, const char *szDialogResource, int iX, int iY, int iWidth, int iHeight, WBWinEvent pUserCallback, int iFlags, void *pUserData)
create a dialog window using a text resource
void(* end_highlight)(struct _text_object_ *pThis)
End a highlight block.
Definition: text_object.h:665
int(* get_insmode)(const struct _text_object_ *pThis)
Get the current insert mode for the object.
Definition: text_object.h:427
Window wID
Window id for the frame window.
Definition: frame_window.h:277
void(* end_mouse_drag)(struct _text_object_ *pThis)
End a mouse &#39;drag&#39; operation.
Definition: text_object.h:701
#define LOAD_COLOR0(X, Y)
macro to load a color, mostly for readability
Icon - white question mark in green triangle.
void(* cursor_top)(struct _text_object_ *pThis)
Move the cursor to the top line.
Definition: text_object.h:758
int(* get_col)(const struct _text_object_ *pThis)
Get the current column cursor for the object.
Definition: text_object.h:538
WBFrameWindow * pOwner
a pointer to the WBFrameWindow owner
Definition: frame_window.h:430
int FWGetChildFrameIndex(WBFrameWindow *pFW, WBChildFrame *pCont)
Sets the focus to a specific contained window using its tab order index.
void(* page_right)(struct _text_object_ *pThis)
Move the current cursor position right one page.
Definition: text_object.h:743
int WBShowModal(Window wID, int bMenuSplashFlag)
Shows a &#39;modal&#39; window by processing events until the window closes.
Edit Window API functions.
int(* get_cols)(struct _text_object_ *pThis)
Call this function to obtain the estimated column extent of the document.
Definition: text_object.h:385
void(* cursor_left)(struct _text_object_ *pThis)
Move the current cursor position left one column.
Definition: text_object.h:718
static __inline__ void WBInitializeInPlaceTextObject(TEXT_OBJECT *pTextObject, Window wIDOwner)
initialize an &#39;in-place&#39; TEXT_OBJECT structure
Definition: text_object.h:1028
int(* get_row)(const struct _text_object_ *pThis)
Get the current row cursor for the object.
Definition: text_object.h:525
unsigned long long WBGetFileModDateTime(const char *szFileName)
Obtain the &#39;time_t&#39; value for a file&#39;s modification date/time (unix time, seconds since the epoch) ...
Definition: file_help.c:1609
void WBDebugDump(const char *szTitle, void *pData, int cbData)
conditionally dumps binary data to debug message output
GC WBBeginPaintGeom(Window wID, WB_GEOM *pgBounds)
&#39;Paint&#39; helper, creates a GC for use in updating the window for a specified rectangular area ...
Structure that defines a Child Frame within a Frame Window.
Definition: frame_window.h:426
default for OS
Definition: text_object.h:133
void(* set_text)(struct _text_object_ *pThis, const char *szText, unsigned long cbLen)
Call this function to re-assign all text in the control.
Definition: text_object.h:359
#define CHILD_FRAME_UI_TAG
TAG for the WBChildFrameUI structure.
Definition: child_frame.h:99
XFontSet WBFontSetFromFont(Display *pDisplay, const XFontStruct *pFont)
Creates an &#39;XFontSet&#39; from an XFontStruct for a given display.
Definition: font_helper.c:1750
unsigned int border
void(* cursor_home)(struct _text_object_ *pThis)
Move the cursor &#39;home&#39; (left or BOL)
Definition: text_object.h:748
Button Bits - Yes button plus No button.
int WBTextObjectCalculateLineHeight(int iAscent, int iDescent)
Calculate the correct per-line height (in pixels) for a specified font ascent and descent...
Definition: text_object.c:835
Button Bits - OK button.
&#39;configuration helper&#39; main header file for the X11 Work Bench Toolkit API
void FWChildFrameStatusChanged(WBChildFrame *pChildFrame)
Notify Child Frame to update status text in Frame Window.
Definition: child_frame.c:889
Atom aRECALC_LAYOUT
notify window that it should re-calculate things like scrollbars and viewports
Atom aDIALOG_INIT
DIALOG_INIT ClientMessage, sent to dialog window callback on frame create.
int WBSetClipboardData(Display *pDisplay, Atom aType, int iFormat, const void *pData, unsigned long nData)
Get clipboard data of requested type.
WB_POINT origin
viewport &#39;origin&#39; in &#39;client units&#39; (such as chars and lines) - determines scroll behavior ...
Definition: frame_window.h:435
Atom aEW_EDIT_CHANGE
&#39;Edit Change&#39; notification to user-callback, sent via ClientMessage event
Definition: edit_window.c:210
Icon - red stop sign.
#define IDYES
void DeleteTimer(Display *pDisplay, Window wID, long lID)
Deletes an existing timer&#39;s resources.
int WBCheckFileModDateTime(const char *szFileName, unsigned long long tVal)
Compare a 64-bit unsigned integer value against a file&#39;s modification date/time (unix time...
Definition: file_help.c:1635
void FWChildFrameRecalcLayout(WBChildFrame *pChildFrame)
Child frame notification callback (called by frame window)
Definition: child_frame.c:837
unsigned int width
the &#39;width&#39; value of the extent.
#define DIALOG_WINDOW_TAG
int y
the &#39;y&#39; value of the point. can be negative.
TEXT_OBJECT xTextObject
the &#39;TEXT_OBJECT&#39; member, that does MOST of the work
Definition: edit_window.h:174
char * szStatusText
Status text (&#39;WBAlloc&#39;d) to display when this child frame window has the input focus. Updated by &#39;superclass&#39;. can be NULL.
Definition: frame_window.h:452
void WBEditWindowRegisterCallback(WBEditWindow *pEditWindow, WBWinEvent pUserCallback)
Clear the contents in the Edit Window, and NULL the stored file name.
Definition: edit_window.c:586
static __inline__ WBChildFrame * FWGetChildFrameStruct(Window wID)
Obtain the associated WBChildFrame structure pointer for a Window ID.
Definition: child_frame.h:376
void(* destructor)(struct __WBChildFrame__ *)
pointer to a &#39;superclass&#39; destructor. If not NULL, will be called by FWDestroyChildFrame() ...
Definition: frame_window.h:459
size_t WBReadFileIntoBuffer(const char *szFileName, char **ppBuf)
read a file&#39;s contents into a buffer, returning the length of the buffer
Definition: file_help.c:572
void * WBAlloc(int nSize)
High performance memory sub-allocator &#39;allocate&#39;.
int(* has_select)(const struct _text_object_ *pThis)
Returns a non-zero value if there is currently a &#39;selection&#39;.
Definition: text_object.h:505
unsigned int width
void(* scroll_vertical)(struct _text_object_ *pThis, int nRows)
Scroll the viewport up/down by the specified number of rows.
Definition: text_object.h:769
void(* do_expose)(struct _text_object_ *pThis, Display *pDisplay, Window wID, GC gc, const WB_GEOM *pPaintGeom, const WB_GEOM *pViewGeom, XFontSet rFontSet)
Member function to properly render the text in a window (Expose event)
Definition: text_object.h:813
unsigned int height
int WBFontSetAvgCharWidth(Display *pDisplay, XFontSet fontSet)
Get the average character width for a font set.
Definition: font_helper.c:1227
#define WB_ERROR_PRINT(...)
Preferred method of implementing an &#39;error level&#39; debug message for all subsystems.
Definition: debug_helper.h:356
Window wID
window ID of the dialog (frame) window
XFontSet rFontSet
default font for the window
Definition: frame_window.h:431
void WBFree(void *pBuf)
High performance memory sub-allocator &#39;free&#39;.
void(* set_col)(struct _text_object_ *pThis, int iCol)
Set the current column cursor for the object.
Definition: text_object.h:549
#define IDCANCEL
structure for managing menu callbacks
Definition: frame_window.h:217
#define WB_KEYEVENT_SHIFT
&#39;AltCtrlShift&#39; bit flag for Shift modifier for WBKeyEventProcessKey()
void(* page_up)(struct _text_object_ *pThis)
Move the current cursor position up one page.
Definition: text_object.h:728
void(* ins_chars)(struct _text_object_ *pThis, const char *pChar, int nChar)
Insert &#39;n&#39; characters (including new lines) from the current cursor.
Definition: text_object.h:586
#define EDIT_WINDOW_TAG
TAG for the WBEditWindow structure.
Definition: edit_window.h:73
void(* set_insmode)(struct _text_object_ *pThis, int iInsMode)
Set the current insert mode for the object.
Definition: text_object.h:434
void FWSetChildFrameScrollInfo(WBChildFrame *pChildFrame, int iRow, int iMaxRow, int iCol, int iMaxCol, int iRowHeight, int iColWidth)
Set the X,Y extent for the child frame (notifies everything)
Definition: child_frame.c:796
void FWDestroyChildFrame(WBChildFrame *pChildFrame)
Destroy an Child Frame.
Definition: child_frame.c:321
void(* cursor_right)(struct _text_object_ *pThis)
Move the current cursor position right one column.
Definition: text_object.h:723
void(* cursor_bottom)(struct _text_object_ *pThis)
Move the cursor to the last line.
Definition: text_object.h:763
unsigned long long llModDateTime
file&#39;s mod date/time - see WBGetFileModDateTime()
Definition: edit_window.h:167
void(* get_select)(const struct _text_object_ *pThis, WB_RECT *pRct)
Get the current selection rectangle as WB_RECT.
Definition: text_object.h:492
void(* get_view)(const struct _text_object_ *pThis, WB_RECT *pRct)
Get the current viewport (in characters). The return value is not relevant if the expose method has n...
Definition: text_object.h:630
internal wrapper struct for &#39;rectangle&#39; definition
Structure that defines a Child Frame&#39;s UI, mainly for a &#39;superclass&#39;.
Definition: frame_window.h:677
void(* set_row)(struct _text_object_ *pThis, int iRow)
Set the current row cursor for the object.
Definition: text_object.h:532
Atom WBGetAtom(Display *pDisplay, const char *szAtomName)
Lookup and/or allocate an internal Atom for a named string (lookups include X11 atoms) ...
#define LOAD_COLOR(X, Y, Z)
macro to load a color with a fallback, mostly for readability
#define WB_KEYEVENT_ACSMASK
&#39;AltCtrlShift&#39; bit mask for Alt+Ctrl+Shift bits for WBKeyEventProcessKey()
int WBFontSetDescent(Display *pDisplay, XFontSet fontSet)
Get the maximum character descent from a font set.
Definition: font_helper.c:1094
int(* WBWinEvent)(Window wID, XEvent *pEvent)
event callback function type for window events
void(* begin_highlight)(struct _text_object_ *pThis)
Begin a highlight block.
Definition: text_object.h:655
void(* cursor_up)(struct _text_object_ *pThis)
Move the current cursor position up one line.
Definition: text_object.h:708
int WBFontSetAscent(Display *pDisplay, XFontSet fontSet)
Get the maximum character ascent from a font set.
Definition: font_helper.c:1136
WBWinEvent pUserCallback
user callback function to receive notifications and unhandled messages
Definition: edit_window.h:172
void DLGAssignOwner(WBDialogWindow *pDlg, Window wIDOwner)
Assign owning window to dialog.
void(* replace_select)(struct _text_object_ *pThis, const char *szText, unsigned long cbLen)
Replace the current selection assigned via &#39;set_select&#39; with new text.
Definition: text_object.h:563
Atom aQUERY_CLOSE
query if it&#39;s ok to close (and optionally destroy yourself if ok) a window
int iRowHeight
cached &#39;row height&#39; (height of line including interline spacing)
Definition: frame_window.h:438
Window wID
window identifier for the &#39;Child Frame&#39; window. may contain &#39;None&#39; while being destroyed ...
Definition: frame_window.h:429
Display * WBGetWindowDisplay(Window wID)
returns the Display associated with a window
Atom aCONTROL_NOTIFY
dialog control and child window notification messages
WB_EXTENT extent
viewport &#39;extent&#39; in &#39;client units&#39; (such as chars and lines) - determines scroll behavior ...
Definition: frame_window.h:436
static __inline__ WBDialogWindow * DLGGetDialogWindowStruct(Window wID)
Returns a pointer to the dialog window&#39;s WBDialogWindow structure.
void(* mouse_click)(struct _text_object_ *pThis, int iMouseXDelta, int iMouseYDelta, int iType, int iACS)
Translate mouse cursor position into actual row/column. This function is irrelevant if the expose met...
Definition: text_object.h:683
Atom aEW_HOVER_NOTIFY
Hover notification to user-callback, sent via ClientMessage event.
Definition: edit_window.c:192
void(* page_left)(struct _text_object_ *pThis)
Move the current cursor position left one page.
Definition: text_object.h:738
void(* set_view_orig)(struct _text_object_ *pThis, const WB_POINT *pOrig)
Set the current viewport (in characters). Only &#39;left&#39; and &#39;top&#39; are relevant if the expose method has...
Definition: text_object.h:642
internal wrapper struct for &#39;point&#39; definition
WBEditWindow * WBEditWindowFromWindowID(Window wID)
Obtain the associated WBEditWindow structure pointer for a Window ID.
Definition: edit_window.c:440
char * szFileName
malloc&#39;d name of file associated with this edit window (NULL if none)
Definition: edit_window.h:164
int iColWidth
cached &#39;column width&#39; (width of 1 character)
Definition: frame_window.h:439
WBEditWindow * WBCreateEditWindow(WBFrameWindow *pOwner, XFontStruct *pFont, const char *szFocusMenu, const WBFWMenuHandler *pHandlerArray, int fFlags)
Create an Edit Window.
Definition: edit_window.c:268
WBChildFrame childframe
elements common to a &#39;child frame&#39; (derived object)
Definition: edit_window.h:160
void(* del_chars)(struct _text_object_ *pThis, int nChar)
Delete &#39;n&#39; characters from the current cursor. Negative deletes BEFORE the cursor. &#39;newline&#39; counts as 1 character.
Definition: text_object.h:570
main controlling structure for frame windows
Definition: frame_window.h:274
Structure identifying a dialog (frame) window.
Atom aBUTTON_PRESS
CONTROL_NOTIFY ClientMessage for BUTTON_PRESS event.
void WBDebugPrint(const char *pFmt,...) __attribute__((format(printf
conditional debug message output
void(* begin_mouse_drag)(struct _text_object_ *pThis)
Begin a mouse &#39;drag&#39; operation.
Definition: text_object.h:693
Atom aWB_TIMER
timer notifications generated by API
#define WB_KEYEVENT_CTRL
&#39;AltCtrlShift&#39; bit flag for Control modifier for WBKeyEventProcessKey()
Visibility flag.
void(* cursor_blink)(struct _text_object_ *pThis, int bHasFocus)
Periodic callback to &#39;blink&#39; the cursor.
Definition: text_object.h:825
int CreateTimer(Display *pDisplay, Window wID, unsigned long lInterval, long lID, int iPeriodic)
Creates a one-shot or periodic timer.
void WBEndModal(Window wID, int iRval)
End a modal window with a specific return value.
char * WBCopyString(const char *pSrc)
A simple utility that returns a WBAlloc() copy of a 0-byte terminated string.
void(* set_linefeed)(struct _text_object_ *pThis, int iLineFeed)
Set the current linefeed type for the object.
Definition: text_object.h:421
int WBEditWindowSaveFile(WBEditWindow *pEditWindow, const char *pszFileName)
Save the contents from the Edit Window to a file, overwriting the file if it already exists...
Definition: edit_window.c:546
unsigned int height
the &#39;height&#39; value of the extent.
Structure that defines an Edit Window.
Definition: edit_window.h:158
void WBDestroyEditWindow(WBEditWindow *pEditWindow)
Destroy an Edit Window.
Definition: edit_window.c:398
void * WBGetClipboardData(Display *pDisplay, Atom *paType, int *piFormat, unsigned long *pnData)
Get clipboard data of requested type.
void(* cursor_down)(struct _text_object_ *pThis)
Move the current cursor position down one line.
Definition: text_object.h:713
Atom aRESIZE_NOTIFY
notification of window re-size via ClientMessage
void WBEditWindowClear(WBEditWindow *pEditWindow)
Clear the contents in the Edit Window, and NULL the stored file name.
Definition: edit_window.c:572
static __inline__ void WBDestroyInPlaceTextObject(TEXT_OBJECT *pTextObject)
Destroy a previously initialized &#39;in-place&#39; TEXT_OBJECT structure.
Definition: text_object.h:1053
static __inline__ int WBIsValidEditWindow(WBEditWindow *pEditWindow)
Check for valid WBEditWindow pointer.
Definition: edit_window.h:281
void WBGetWindowGeom0(Window wID, WB_GEOM *pGeom)
Returns the ABSOLUTE window geometry relative the screen.
void(* cursor_end)(struct _text_object_ *pThis)
Move the cursor to &#39;end&#39; (full doc width or EOL)
Definition: text_object.h:753
WBWinEvent pUserCallback
message callback function pointer (can be NULL)
Definition: frame_window.h:458
void(* set_select)(struct _text_object_ *pThis, const WB_RECT *pRct)
Set the current selection rectangle as WB_RECT.
Definition: text_object.h:499
const char * WB_PCSTR
pointer to const char string - a convenience typedef
internal wrapper struct for X11 &#39;geometry&#39; definition
void(* page_down)(struct _text_object_ *pThis)
Move the current cursor position down one page.
Definition: text_object.h:733
INSERT mode, character inserted at cursor.
Definition: text_object.h:162
void WBEndPaint(Window wID, GC gc)
&#39;Paint&#39; helper, frees resources and marks the update region &#39;valid&#39;
Atom aSTRING
STRING Atom for the clipboard - uses XA_STRING.
int x
the &#39;x&#39; value of the point. can be negative.
#define WB_WARN_PRINT(...)
Preferred method of implementing a &#39;warning level&#39; debug message for all subsystems.
Definition: debug_helper.h:349
void(* del_select)(struct _text_object_ *pThis)
Delete the current selection assigned via &#39;set_select&#39;.
Definition: text_object.h:555
OVERWRITE mode, character inserted on top of character to the right of the cursor (if any)...
Definition: text_object.h:163
WB_GEOM geom
total client-area geometry (excludes scroll bars) in &#39;pixels&#39;
Definition: frame_window.h:433
int DLGMessageBox(int iType, Window wIDOwner, const char *szTitle, const char *szMessage)
Display a modal &#39;message box&#39; dialog window with a specific title, message, and button combination...
Definition: dialog_impl.c:231
Atom aUTF8_STRING
UTF8_STRING Atom for the clipboard.
Window wIDOwner
owner window (cached from paint/expose handling and/or cursor blink)
Definition: text_object.h:954
unsigned int ulTag
&#39;Tag&#39; identifying this structure as a WBEditWindow
Definition: edit_window.h:162