X11 Work Bench 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-2016 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 
65 #if 1 // assign to 0 to disable this trace-style debugging ALL of the time
66 #define CALLBACK_TRACKER WBDebugPrint("TEMPORARY - edit_window.c: %s - callback tracker\n", __FUNCTION__);
67 #else //
68 #define CALLBACK_TRACKER WB_DEBUG_PRINT((DebugLevel_Heavy | DebugSubSystem_EditWindow), "edit_window.c: %s - callback tracker\n", __FUNCTION__);
69 #endif // 0,1
70 
71 #define EDIT_WINDOW_LINE_SPACING 4 /* 4 spaces between each line */
72 
73 
74 int FWEditWindowEvent(Window wID, XEvent *pEvent);
75 static void InternalEditWindowDestructor(WBChildFrame *pC);
76 static void InternalEditWindowDestroy(WBEditWindow *pEditWindow);
77 
78 // UI callbacks for WBChildFrameUI
79 
80 static void internal_do_char(WBChildFrame *, XClientMessageEvent *); // handler for regular WM_CHAR Client Messages (WBChildFrame *, typed-in characters)
81 static void internal_scancode(WBChildFrame *, XClientMessageEvent *); // handler for 'other scan code' WM_CHAR Client Messages (WBChildFrame *, typed-in characters)
82 static void internal_bkspace(WBChildFrame *, int iACS); // 'backspace' delete character (WBChildFrame *, backspace equivalent). 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
83 static void internal_del(WBChildFrame *, int iACS); // 'delete' char under cursor (WBChildFrame *, delete equivalent). 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
84 static void internal_tab(WBChildFrame *, int iACS); // 'tab' char, or tab navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
85 static void internal_enter(WBChildFrame *, int iACS); // 'enter' char, or 'enter' for navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
86 static void internal_uparrow(WBChildFrame *, int iACS); // 'up' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
87 static void internal_downarrow(WBChildFrame *, int iACS); // 'down' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
88 static void internal_leftarrow(WBChildFrame *, int iACS); // 'left' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
89 static void internal_rightarrow(WBChildFrame *, int iACS); // 'right' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
90 static void internal_home(WBChildFrame *, int iACS); // 'home' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
91 static void internal_end(WBChildFrame *, int iACS); // 'end' arrow navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
92 static void internal_pgup(WBChildFrame *, int iACS); // 'page up' navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
93 static void internal_pgdown(WBChildFrame *, int iACS); // 'page down' navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
94 static void internal_pgleft(WBChildFrame *, int iACS); // 'page left' navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
95 static void internal_pgright(WBChildFrame *, int iACS); // 'page right' navigation. 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
96 static void internal_help(WBChildFrame *, int iACS); // 'help' context (WBChildFrame *, F1). 'iACS' is the Alt/Ctrl/Shift flags. \sa aWM_CHAR
97 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)
98 static void internal_hover_cancel(WBChildFrame *); // 'mouse hover' cancel notification (WBChildFrame *, cancel any 'hover' action)
99 static int internal_is_ins_mode(WBChildFrame *); // returns non-zero if in 'insert' mode, 0 for 'overwrite'
100 static void internal_toggle_ins_mode(WBChildFrame *); // toggles insert mode on/off (WBChildFrame *, press 'INS' key)
101 static void internal_copy_to_cb(WBChildFrame *); // copy selection to clipboard
102 static void internal_paste_from_cb(WBChildFrame *); // paste from clipboard
103 static void internal_cut_to_cb(WBChildFrame *); // delete selection, copying to clipboard first
104 static void internal_delete_sel(WBChildFrame *); // delete selection only
105 static void internal_select_all(WBChildFrame *); // select all
106 static void internal_select_none(WBChildFrame *); // select none
107 static void internal_save(WBChildFrame *, const char *szFileName); // save to specified file name (WBChildFrame *, NULL to keep same file name)
108 static WB_PCSTR internal_get_file_name(WBChildFrame *); // get (const) pointer to file name string
109 static void internal_mouse_click(WBChildFrame *, int iX, int iY,
110  int iButtonMask, int iACS); // 'mouse click' notification. \sa aWM_POINTER
111 static void internal_mouse_dblclick(WBChildFrame *, int iX, int iY,
112  int iButtonMask, int iACS); // 'mouse double click' notification. \sa aWM_POINTER
113 static void internal_mouse_drag(WBChildFrame *, int iX, int iY,
114  int iButtonMask, int iACS); // 'mouse drag' (begin) notification. \sa aWM_POINTER
115 static void internal_mouse_drop(WBChildFrame *, int iX, int iY,
116  int iButtonMask, int iACS); // 'mouse drop' (drag end) notification. \sa aWM_POINTER
117 static void internal_mouse_move(WBChildFrame *, int iX, int iY); // 'mouse motion' notification. \sa aWM_POINTER
118 static void internal_mouse_scrollup(WBChildFrame *, int iX, int iY,
119  int iButtonMask, int iACS); // 'mouse scroll up' notification. \sa aWM_POINTER
120 static void internal_mouse_scrolldown(WBChildFrame *, int iX, int iY,
121  int iButtonMask, int iACS); // 'mouse scroll down' notification. \sa aWM_POINTER
122 static void internal_mouse_cancel(WBChildFrame *); // 'mouse cancel' notification (cancel 'drag', etc.). \sa aWM_POINTER
123 static void internal_get_row_col(WBChildFrame *pC, int *piR, int *piC);// get row/col (etc.)
124 static int internal_has_selection(WBChildFrame *pC); // returns non-zero value if there is a selection
125 static void internal_undo(WBChildFrame *); // perform an undo
126 static void internal_redo(WBChildFrame *); // perform a re-do
127 static int internal_can_undo(WBChildFrame *); // returns non-zero value if 'can undo'
128 static int internal_can_redo(WBChildFrame *); // returns non-zero value if 'can redo'
129 static int internal_is_empty(WBChildFrame *); // returns non-zero value if 'empty'
130 
131 
132 static void internal_update_status_text(WBEditWindow *); // called whenever status text should change
133 static void internal_new_cursor_pos(WBEditWindow *); // called whenever cursor position changes.
134 
135 
136 static XColor clrFG, clrBG, clrAFG, clrABG;
137 static int iInitColorFlag = 0;
138 
139 
140 static WBChildFrameUI internal_CFUI =
141 {
143  internal_do_char, internal_scancode, internal_bkspace, internal_del,
144  internal_tab, internal_enter, internal_uparrow, internal_downarrow,
145  internal_leftarrow, internal_rightarrow, internal_home, internal_end,
146  internal_pgup, internal_pgdown, internal_pgleft, internal_pgright,
147  internal_help, internal_hover_notify, internal_hover_cancel, internal_is_ins_mode,
148  internal_toggle_ins_mode, internal_copy_to_cb, internal_paste_from_cb, internal_cut_to_cb,
149  internal_delete_sel, internal_select_all, internal_select_none, internal_save,
150  internal_get_file_name, internal_mouse_click, internal_mouse_dblclick, internal_mouse_drag,
151  internal_mouse_drop, internal_mouse_move, internal_mouse_scrollup, internal_mouse_scrolldown,
152  internal_mouse_cancel, internal_get_row_col, internal_has_selection, internal_undo,
153  internal_redo, internal_can_undo, internal_can_redo, internal_is_empty
154 };
155 
156 
157 
175 
192 Atom aEW_EDIT_CHANGE=None;
193 
194 
195 
196 
197 #define LOAD_COLOR0(X,Y) if(CHGetResourceString(WBGetDefaultDisplay(), X, Y, sizeof(Y)) > 0) { }
198 #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); }
199 
200 static void InternalCheckEWColorsAndAtoms(void)
201 {
202  Colormap colormap;
203 
204  // *Frame.background, *Frame.foreground, *WmFrame.background, *WmFrame.foreground,
205  // *Form.background, *Form.foreground, *background, *foreground
206 
207  if(aEW_EDIT_CHANGE == None)
208  {
209  aEW_EDIT_CHANGE = WBGetAtom(WBGetDefaultDisplay(), "EW_EDIT_CHANGE");
210  }
211 
212  if(aEW_HOVER_NOTIFY == None)
213  {
214  aEW_HOVER_NOTIFY = WBGetAtom(WBGetDefaultDisplay(), "EW_HOVER_NOTIFY");
215  }
216 
217  if(!iInitColorFlag)
218  {
219  char szFG[16], szBG[16], szAFG[16], szABG[16]; // note colors can typically be up to 13 characters + 0 byte
220 
221  colormap = DefaultColormap(WBGetDefaultDisplay(), DefaultScreen(WBGetDefaultDisplay()));
222 
223  // (these color names and standards have changed *WAY* too many times...)
224 
225  LOAD_COLOR0("*Text.foreground",szFG) else LOAD_COLOR0("*Edit.foreground", szFG)
226  else LOAD_COLOR("*foreground", szFG, "#000000");
227  LOAD_COLOR0("*Text.background",szBG) else LOAD_COLOR0("*Edit.background", szBG)
228  else LOAD_COLOR("*background", szBG, "white"); // pure white background by default
229 
230  LOAD_COLOR("selected_bg_color", szABG, "#0040FF"); // a slightly greenish blue for the 'selected' BG color
231  LOAD_COLOR("selected_fg_color", szAFG, "white"); // white FG when selected
232 
233  WB_ERROR_PRINT("TEMPORARY: %s - edit window colors: FG=%s BG=%s AFG=%s ABG=%s\n", __FUNCTION__,
234  szFG, szBG, szAFG, szABG);
235 
236  XParseColor(WBGetDefaultDisplay(), colormap, szFG, &clrFG);
237  XAllocColor(WBGetDefaultDisplay(), colormap, &clrFG);
238  XParseColor(WBGetDefaultDisplay(), colormap, szBG, &clrBG);
239  XAllocColor(WBGetDefaultDisplay(), colormap, &clrBG);
240  XParseColor(WBGetDefaultDisplay(), colormap, szAFG, &clrAFG);
241  XAllocColor(WBGetDefaultDisplay(), colormap, &clrAFG);
242  XParseColor(WBGetDefaultDisplay(), colormap, szABG, &clrABG);
243  XAllocColor(WBGetDefaultDisplay(), colormap, &clrABG);
244 
245  iInitColorFlag = 1;
246  }
247 }
248 
249 
250 WBEditWindow *WBCreateEditWindow(WBFrameWindow *pOwner, XFontStruct *pFont,
251  const char *szFocusMenu, const WBFWMenuHandler *pHandlerArray,
252  int fFlags)
253 {
254 WBEditWindow *pRval;
255 XFontSet rFontSet;
256 Display *pDisplay;
257 int iRet;
258 
259 
260  CALLBACK_TRACKER;
261 
262  InternalCheckEWColorsAndAtoms();
263 
264  if(!pOwner)
265  {
266  return NULL;
267  }
268 
269  pDisplay = WBGetWindowDisplay(pOwner->wID);
270 
271  pRval = (WBEditWindow *)WBAlloc(sizeof(*pRval));
272 
273  if(!pRval)
274  {
275  WB_ERROR_PRINT("ERROR: %s - not enough memory\n", __FUNCTION__);
276  return NULL;
277  }
278 
279  bzero(pRval, sizeof(*pRval));
280 
281  pRval->ulTag = EDIT_WINDOW_TAG;
282  pRval->szFileName = NULL; // explicitly do this, though the bzero would've
283  pRval->pUserCallback = NULL; // explicitly do this, too
284 
285  if(!pFont)
286  {
287  rFontSet = None;//WBGetDefaultFontSet();
288  }
289  else
290  {
291  rFontSet = WBFontSetFromFont(pDisplay, pFont);
292  }
293 
296 
297 // pRval->xTextObject.vtable->set_col(&(pRval->xTextObject), 0);
298 // pRval->xTextObject.vtable->set_row(&(pRval->xTextObject), 0);
299 
300 
301  // create the actual window.
302 
303  iRet = FWInitChildFrame(&(pRval->childframe), pOwner, rFontSet, // NOTE: a copy of rFontSet will be in 'childframe.rFontSet'
304  szFocusMenu, pHandlerArray,
305  FWEditWindowEvent, fFlags);
306 
307  if(rFontSet != None)
308  {
309  XFreeFontSet(pDisplay, rFontSet);
310  rFontSet = None;
311  }
312 
313  if(iRet < 0)
314  {
315  WB_ERROR_PRINT("ERROR: %s - unable to initialize child frame\n", __FUNCTION__);
316 
317  WBFree(pRval);
318 
319  return NULL;
320  }
321 
322 
323  pRval->xTextObject.wIDOwner = pRval->childframe.wID; // TODO: make assigning this an API function?
324 
325 
326  // assign my 'UI' vtable pointer, which will be (intelligently) called by the 'Child Frame' event handler
327  // this standardizes the various UI methods and makes coding a complex UI quite a bit easier
328  pRval->childframe.pUI = &internal_CFUI; // UI function vtable
329 
330  // assign my 'destructor', which will be called by FWDestroyChildFrame
331  // THIS must be done LAST, since 'FWInitChildFrame' might call FWDestroyChildFrame on error
332  // and I don't want to call the 'destructor' yet.
333  pRval->childframe.destructor = InternalEditWindowDestructor;
334 
335 
336  // TODO: any other initialization belongs HERE. if error, call FWDestroyChildFrame() and return
337  // a NULL immediately (since that would destroy the child frame AND the Edit Window stuff)
338 
339 
340  internal_update_status_text(pRval); // update status text now.
341 
343  333333, 1, 1); // TODO: use #define for timer ID and period (1/3 second for now))
344  // NOTE: when I unregister the window callback, the timer will be deleted automatically
345 
346  return pRval;
347 }
348 
349 // this function destroys any allocated objects in the WBEditWindow, but doesn't free the pointer
350 static void InternalEditWindowDestroy(WBEditWindow *pEditWindow)
351 {
352  // these next 'things' are private to this particular 'class'
353 
354  if(pEditWindow->szFileName)
355  {
356  WBFree(pEditWindow->szFileName);
357  pEditWindow->szFileName = NULL;
358  }
359 
360  WBDestroyInPlaceTextObject(&(pEditWindow->xTextObject));
361 
362  pEditWindow->ulTag = 0; // not valid any more
363 }
364 
365 static void InternalEditWindowDestructor(WBChildFrame *pC)
366 {
367  WBEditWindow *pEW = (WBEditWindow *)pC;
368 
369 // WB_ERROR_PRINT("TEMPORARY: %s - destroying edit window %p\n", __FUNCTION__, pEW);
370 
371  InternalEditWindowDestroy(pEW);
372 
373  bzero(pEW, sizeof(*pEW)); // in case anything else 'stale' is there
374 
375  WBFree(pEW);
376 
377 // WB_ERROR_PRINT("TEMPORARY: %s - destroyed edit window %p\n", __FUNCTION__, pEW);
378 }
379 
381 {
382  if(!WBIsValidEditWindow(pEditWindow))
383  {
384  WB_ERROR_PRINT("ERROR: %s - invalid Edit Window pointer %p\n", __FUNCTION__, pEditWindow);
385  return;
386  }
387 
388  if(pEditWindow->pUserCallback)
389  {
390  // TODO: Send an aDESTROY_NOTIFY ClientMessage 'destroy' notification (once I document it)
391 
392  // TODO: send a 'DestroyNotify' event instead???
393 
394  pEditWindow->pUserCallback = NULL;
395  }
396 
397  if(pEditWindow->childframe.pUserCallback == FWEditWindowEvent)
398  {
399  pEditWindow->childframe.pUserCallback = NULL; // prevents any kind of recursion from messages (unlikely)
400  }
401 
402  if(pEditWindow->childframe.destructor == NULL)
403  {
404  WB_ERROR_PRINT("ERROR: %s - destructor is NULL - pointer will not be free'd\n", __FUNCTION__);
405 
406  InternalEditWindowDestroy(pEditWindow); // perform the necessary destruction *ANYWAY* but don't free the pointer
407 
408  // TODO: ALWAYS assign the destructor to NULL, and THEN call it directly after calling FWDestroyChildFrame() ?
409  }
410 
411  if(pEditWindow->childframe.wID != None)
412  {
414  pEditWindow->childframe.wID, 1); // the preferred method, when practical, is to delete it explicitly
415  }
416 
417  // the last step destroys the child frame, which will destroy the Edit Window as well
418 
419  FWDestroyChildFrame(&(pEditWindow->childframe)); // destroy window, free up all resources, call destructor (if not NULL)
420 }
421 
423 {
425 
426 
427  if(pRval && !WBIsValidEditWindow(pRval))
428  {
429  pRval = NULL;
430  }
431 
432  return pRval;
433 }
434 
435 
436 int WBEditWindowLoadFile(WBEditWindow *pEditWindow, const char *pszFileName)
437 {
438 char *pBuf = NULL;
439 long cbBuf = 0;
440 int iRval = -1;
441 
442 
443  CALLBACK_TRACKER;
444 
445  if(!pEditWindow || !WBIsValidEditWindow(pEditWindow)
446  || !pszFileName || !*pszFileName)
447  {
448  WBDebugPrint("TEMPORARY: bad parameters in WBEditWindowLoadFile\n");
449  return -1;
450  }
451 
452  // implement 'load file'. handle unicode files. UTF-16 files begin with 0xff, 0xfe
453  // UTF-8 files are assumed to be the same as ASCII (with no prefix).
454 
455 
456  if(pEditWindow->szFileName)
457  {
458  WBFree(pEditWindow->szFileName);
459  }
460 
461 // pEditWindow->xTextObject.vtable->init(&(pEditWindow->xTextObject));
462  WBEditWindowClear(pEditWindow);
463 
464  pEditWindow->szFileName = WBCopyString(pszFileName);
465 
466  // load the file into a buffer
467 
468  cbBuf = (long)WBReadFileIntoBuffer(pszFileName, &pBuf);
469 
470  if(cbBuf >= 0 && pBuf)
471  {
472  if(cbBuf >= 2 && (unsigned char)pBuf[0] == 0xff && (unsigned char)pBuf[1] == 0xfe)
473  {
474  // TODO: unicode file!
475 // pEditWindow->xTextObject.vtable->set_text(&(pEditWindow->xTextObject), pBuf + 2, cbBuf - 2);
476  }
477  else
478  {
479  // TODO: fix line endings first??
480  pEditWindow->xTextObject.vtable->set_row(&(pEditWindow->xTextObject),0);
481  pEditWindow->xTextObject.vtable->set_col(&(pEditWindow->xTextObject),0);
482 
483 // internal_new_cursor_pos(pE);
484  pEditWindow->xTextObject.vtable->set_text(&(pEditWindow->xTextObject), pBuf, cbBuf);
485 // pEditWindow->xTextObject.vtable->ins_chars(&(pEditWindow->xTextObject), pBuf, cbBuf);
486 
487  pEditWindow->xTextObject.vtable->set_row(&(pEditWindow->xTextObject),0);
488  pEditWindow->xTextObject.vtable->set_col(&(pEditWindow->xTextObject),0);
489  }
490 
491  iRval = 0; // for now; later, check for error state
492  }
493  else
494  {
495  iRval = -1;
496  }
497 
498  if(pBuf)
499  {
500  WBFree(pBuf);
501  }
502 
503  if(pEditWindow->pUserCallback)
504  {
505  XClientMessageEvent evt;
506 
507  bzero(&evt, sizeof(evt));
508 
509  evt.type=ClientMessage;
510  evt.display=WBGetWindowDisplay(pEditWindow->childframe.wID);
511  evt.window=pEditWindow->childframe.wID;
512  evt.message_type=aEW_EDIT_CHANGE;
513  evt.format=32;
514 
515  evt.data.l[0] = 0; // undo
516  evt.data.l[1] = 0; // cursor x,y
517  evt.data.l[2] = 0;
518 
519  pEditWindow->pUserCallback(pEditWindow->childframe.wID, (XEvent *)&evt);
520  }
521 
522  WBDebugPrint("TEMPORARY WBEditWindowLoadFile() returning %d\n", iRval);
523 
524  return iRval;
525 }
526 
527 int WBEditWindowSaveFile(WBEditWindow *pEditWindow, const char *pszFileName)
528 {
529  if(!pEditWindow || !WBIsValidEditWindow(pEditWindow))
530  {
531  return -1;
532  }
533 
534  if(!pszFileName || !*pszFileName)
535  {
536  pszFileName = pEditWindow->szFileName;
537  }
538 
539  if(!pszFileName || !*pszFileName)
540  {
541  return -1; // error (no file name)
542  }
543 
544 
545  // TODO: implement 'file save'
546 
547 
548  return -1; // error
549 }
550 
551 void WBEditWindowClear(WBEditWindow *pEditWindow)
552 {
553  if(!pEditWindow || !WBIsValidEditWindow(pEditWindow))
554  {
555  return;
556  }
557 
558  WBDestroyInPlaceTextObject(&(pEditWindow->xTextObject));
559  WBInitializeInPlaceTextObject(&(pEditWindow->xTextObject), pEditWindow->childframe.wID);
560  pEditWindow->xTextObject.vtable->set_linefeed(&(pEditWindow->xTextObject), LineFeed_DEFAULT);
561 
562  FWChildFrameRecalcLayout(&(pEditWindow->childframe));
563 }
564 
565 void WBEditWindowRegisterCallback(WBEditWindow *pEditWindow, WBWinEvent pUserCallback)
566 {
567  if(!pEditWindow || !WBIsValidEditWindow(pEditWindow))
568  {
569  return;
570  }
571 
572  pEditWindow->pUserCallback = pUserCallback;
573 }
574 
575 
576 
578 // //
579 // _____ _ _ _ _ _ //
580 // | ____|__ __ ___ _ __ | |_ | | | | __ _ _ __ __| || | ___ _ __ //
581 // | _| \ \ / // _ \| '_ \ | __| | |_| | / _` || '_ \ / _` || | / _ \| '__| //
582 // | |___ \ V /| __/| | | || |_ | _ || (_| || | | || (_| || || __/| | //
583 // |_____| \_/ \___||_| |_| \__| |_| |_| \__,_||_| |_| \__,_||_| \___||_| //
584 // //
585 // //
587 
588 
589 
590 int FWEditWindowEvent(Window wID, XEvent *pEvent)
591 {
592 WBEditWindow *pE;
593 GC gc;
594 WB_GEOM geom;//, geom2;
595 Display *pDisplay = WBGetWindowDisplay(wID);
596 //XFontSet xFontSet;
597 
598 
599  pE = WBEditWindowFromWindowID(wID);
600  if(!pE)
601  {
602  return 0;
603  }
604 
605  switch(pEvent->type)
606  {
607  case Expose:
608 // WB_ERROR_PRINT("TEMPORARY: %s - expose event\n", __FUNCTION__);
609  geom.x = pEvent->xexpose.x;
610  geom.y = pEvent->xexpose.y;
611  geom.width = pEvent->xexpose.width;
612  geom.height = pEvent->xexpose.height;
613 
614  // TEMPORARY - just erase the background, for now...
615  gc = WBBeginPaintGeom(wID, &geom);
616 
617  XSetBackground(pDisplay, gc, clrBG.pixel);
618 
619 // WBGetWindowGeom(wID, &geom2);
620 //
621 // // this is client geometry, not window geometry, so fix it
622 // geom2.x = 1; // 1-pixel border
623 // geom2.y = 1;
624 // geom2.width -= 2; // 1 pixel border on BOTH sides
625 // geom2.height -= 2;
626 //
627 // NOTE: for some reason this un-does what happens later in do_expose() ... maybe XSync after?
628 // XSetForeground(pDisplay, gc, clrBG.pixel);
629 // XFillRectangle(pDisplay, wID, gc, geom2.x, geom2.y, geom2.width, geom2.height);
630 
631  XSetForeground(pDisplay, gc, clrFG.pixel);
632 
633  // TODO: 'split' handling - 2 different sections must be painted separately
634 
635 // xFontSet = pE->childframe.rFontSet;
636 
637  pE->xTextObject.vtable->do_expose(&(pE->xTextObject), pDisplay, wID, gc,
638  &geom, // the GEOM to 'paint to'
639  &(pE->childframe.geom),//NULL,//&geom2, // the GEOM bordering the window's viewport (NULL for ALL)
640  pE->childframe.rFontSet);
641  WBEndPaint(wID, gc);
642 
643 // if(xFontSet)
644 // {
645 // XFreeFontSet(pDisplay, xFontSet);
646 // }
647 
648  return 1; // "handled"
649 
650  case DestroyNotify:
651  // if I'm destroying ME, then I must free up the structure.
652  // if this callback is being called, assume NOT recursive.
653 
654  if(pEvent->xdestroywindow.window == wID)
655  {
656  pE->childframe.wID = None; // assign 'none' as the window ID, since I already destroyed it. don't re-destroy it.
657 
658  WBDestroyEditWindow(pE); // this should fix everything else.
659 
660  return 1; // handled
661  }
662 
663  break;
664 
665  case ClientMessage:
666  if(pEvent->xclient.message_type == aRESIZE_NOTIFY ||
667  pEvent->xclient.message_type == aRECALC_LAYOUT)
668  {
669  // TODO: process re-calculation of the extents, etc.
670 
672  pE->xTextObject.vtable->get_row(&(pE->xTextObject)),
673  pE->xTextObject.vtable->get_rows(&(pE->xTextObject)),
674  pE->xTextObject.vtable->get_col(&(pE->xTextObject)),
675  pE->xTextObject.vtable->get_cols(&(pE->xTextObject)),
677  WBFontSetDescent(pDisplay, pE->childframe.rFontSet)),
678  WBFontSetAvgCharWidth(pDisplay, pE->childframe.rFontSet));
679 // pE->childframe.pFont->ascent + pE->childframe.pFont->ascent + EDIT_WINDOW_LINE_SPACING,
680  }
681  else if(pEvent->xclient.message_type == aWM_TIMER)
682  {
683  // only when this tab is visible do I call the callback.
684 
685  if(pE->childframe.pOwner && // just in case
686  FWGetChildFrameIndex(pE->childframe.pOwner, NULL) // focus window's tab index
687  == FWGetChildFrameIndex(pE->childframe.pOwner, &(pE->childframe))) // THIS window's tab index
688  {
689 // WB_ERROR_PRINT("TEMPORARY: %s - timer\n", __FUNCTION__);
690 
691  pE->xTextObject.vtable->cursor_blink(&(pE->xTextObject), 1);
692  }
693  }
694  else if(pEvent->xclient.message_type == aQUERY_CLOSE)
695  {
696  if(pE->pUserCallback)
697  {
698  int iRval = pE->pUserCallback(wID, pEvent); // allow the user callback to determine when to close
699 
700  if(iRval)
701  {
702  return iRval;
703  }
704  }
705 
706  return 0; // for now, just return 'ok to close' whether I've saved or not
707  }
708  }
709 
710  return 0; // "not handled"
711 }
712 
713 
714 
716 // //
717 // _ _ ___ ____ _ _ _ _ //
718 // | | | ||_ _| / ___| __ _ | || || |__ __ _ ___ | | __ //
719 // | | | | | | | | / _` || || || '_ \ / _` | / __|| |/ / //
720 // | |_| | | | | |___| (_| || || || |_) || (_| || (__ | < //
721 // \___/ |___| \____|\__,_||_||_||_.__/ \__,_| \___||_|\_\ //
722 // //
723 // //
725 
726 
727 static void internal_update_status_text(WBEditWindow *pE) // called whenever cursor position changes.
728 {
729 WBChildFrame *pC = &(pE->childframe);
730 int iR, iC;
731 char tbuf[1024];
732 
733  CALLBACK_TRACKER;
734 
735  if(!WBIsValidEditWindow(pE))
736  {
737  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
738 
739  return;
740  }
741 
742  internal_get_row_col(pC, &iR, &iC);
743 
744  if(pC->szStatusText)
745  {
746  WBFree(pC->szStatusText);
747  pC->szStatusText = NULL;
748  }
749 
750  snprintf(tbuf, sizeof(tbuf), "Row,Col: %d,%d\tlines: %d width: %d\t%s\t",
751  iR,
752  iC,
753  pE->xTextObject.vtable->get_rows(&(pE->xTextObject)),
754  pE->xTextObject.vtable->get_cols(&(pE->xTextObject)),
755  (const char *)(pE->xTextObject.vtable->get_insmode(&(pE->xTextObject)) == InsertMode_INSERT ? "INS" :
756  (const char *)(pE->xTextObject.vtable->get_insmode(&(pE->xTextObject)) == InsertMode_OVERWRITE ? "OVR" : "???")));
757 
758  pC->szStatusText = WBCopyString(tbuf);
759 
760  if(!pC->szStatusText)
761  {
762  WB_ERROR_PRINT("ERROR: %s - not enough memory to display status\n", __FUNCTION__);
763  }
764 
766 }
767 
768 static void internal_new_cursor_pos(WBEditWindow *pE) // called whenever cursor position changes.
769 {
770  CALLBACK_TRACKER;
771 
772  if(WBIsValidEditWindow(pE))
773  {
774  internal_update_status_text(pE);
775 
776  // see if the row exceeds the viewport, and if that's the case, scroll it.
777 
778 
779 
780  // TODO: other things, like messing with the display area, re-calc layout, re-paint, etc.
781  // check to see if top/bottom rows changed, invalidate old line, validate new line, see if
782  // horizontal scrolling entire window or just the cursor, etc. etc. etc.
783  }
784 }
785 
786 static void internal_notify_change(WBChildFrame *pC, int bUndo)
787 {
788 WBEditWindow *pE = (WBEditWindow *)pC;
789 
790  if(!WBIsValidEditWindow(pE))
791  {
792  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
793 
794  return;
795  }
796 
797  if(pE->pUserCallback)
798  {
799  XClientMessageEvent evt;
800 
801  bzero(&evt, sizeof(evt));
802 
803  evt.type=ClientMessage;
804  evt.display=WBGetWindowDisplay(pC->wID);
805  evt.window=pC->wID;
806  evt.message_type=aEW_EDIT_CHANGE;
807  evt.format=32;
808 
809  evt.data.l[0] = bUndo;
810  evt.data.l[1] = pE->xTextObject.vtable->get_row(&(pE->xTextObject));
811  evt.data.l[2] = pE->xTextObject.vtable->get_col(&(pE->xTextObject));
812 
813  pE->pUserCallback(pC->wID, (XEvent *)&evt);
814  }
815 }
816 
817 static void internal_do_char(WBChildFrame *pC, XClientMessageEvent *pEvent)
818 {
819 WBEditWindow *pE = (WBEditWindow *)pC;
820 int iKey, iACS, nChar;
821 char *pBuf;
822 
823 
824  CALLBACK_TRACKER;
825 
826  if(!WBIsValidEditWindow(pE))
827  {
828  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
829 
830  return;
831  }
832 
833  // TODO: determine whether or not the character is printable
834 
835  iKey = pEvent->data.l[0]; // result from WBKeyEventProcessKey()
836  iACS = pEvent->data.l[1];
837  nChar = pEvent->data.l[2];
838  pBuf = (char *)&(pEvent->data.l[3]);
839 
840  if(iACS && (iACS & WB_KEYEVENT_ACSMASK) != WB_KEYEVENT_SHIFT) // only SHIFT can be used here
841  {
842  // TODO: handle non-printing chars
843 
844  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
845  WB_ERROR_PRINT("TEMPORARY: %s - beep\n", __FUNCTION__);
846  }
847  else if(pE->xTextObject.vtable->has_select(&(pE->xTextObject)))
848  {
849 // WB_ERROR_PRINT("TEMPORARY: %s - set text to \"%.*s\"\n", __FUNCTION__, nChar, pBuf);
850  pE->xTextObject.vtable->set_text(&(pE->xTextObject), pBuf, nChar);
851  internal_notify_change(pC, 0);
852  }
853  else
854  {
855 // WB_ERROR_PRINT("TEMPORARY: %s - inserting \"%.*s\"\n", __FUNCTION__, nChar, pBuf);
856  pE->xTextObject.vtable->ins_chars(&(pE->xTextObject), pBuf, nChar);
857  internal_notify_change(pC, 0);
858  }
859 
860 // {
861 // char *p1 = pE->xTextObject.vtable->get_text(&(pE->xTextObject));
862 //
863 // WB_ERROR_PRINT("TEMPORARY: %s - new text \"%s\"\n", __FUNCTION__, p1);
864 //
865 // if(p1)
866 // {
867 // WBFree(p1);
868 // }
869 // }
870 
871  internal_new_cursor_pos((WBEditWindow *)pC);
872 }
873 
874 static void internal_scancode(WBChildFrame *pC, XClientMessageEvent *pEvent)
875 {
876 WBEditWindow *pE = (WBEditWindow *)pC;
877 
878 
879  CALLBACK_TRACKER;
880 
881  if(!WBIsValidEditWindow(pE))
882  {
883  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
884 
885  return;
886  }
887 
888  // TODO: handle things I might want, like 'indent' which might be ctrl+[ or ctrl+], or maybe
889  // ctrl+tab or ctrl+shift+tab
890 
891 
892  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
893 }
894 
895 static void internal_bkspace(WBChildFrame *pC, int iACS)
896 {
897 WBEditWindow *pE = (WBEditWindow *)pC;
898 
899 
900  CALLBACK_TRACKER;
901 
902  if(!WBIsValidEditWindow(pE))
903  {
904  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
905 
906  return;
907  }
908 
909  if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with backspace. yet.
910  {
911  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
912  }
913  else
914  {
915  pE->xTextObject.vtable->del_chars(&(pE->xTextObject), -1);
916  internal_notify_change(pC, 0);
917  }
918 
919  internal_new_cursor_pos((WBEditWindow *)pC);
920 }
921 
922 static void internal_del(WBChildFrame *pC, int iACS)
923 {
924 WBEditWindow *pE = (WBEditWindow *)pC;
925 
926 
927  CALLBACK_TRACKER;
928 
929  if(!WBIsValidEditWindow(pE))
930  {
931  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
932 
933  return;
934  }
935 
936  // shift+del does 'cut' behavior
937 
938  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift+del
939  {
940  if(!pE->xTextObject.vtable->has_select(&(pE->xTextObject)))
941  {
942  // no selection, can't "cut"
943  XBell(WBGetWindowDisplay(pC->wID), -100);
944  }
945  else
946  {
947  // copy selection to the clipboard, then delete - same as internal_cut_to_cb()
948 
949  char *p1 = pE->xTextObject.vtable->get_sel_text(&(pE->xTextObject), NULL);
950  if(p1)
951  {
952  WBSetClipboardData(WBGetWindowDisplay(pC->wID), aUTF8_STRING, 8, p1, strlen(p1) + 1);
953 
954  WBFree(p1);
955 
957  internal_notify_change(pC, 0);
958  }
959  }
960  }
961  else if(pE->xTextObject.vtable->has_select(&(pE->xTextObject)))
962  {
964  internal_notify_change(pC, 0);
965  }
966  else
967  {
968  pE->xTextObject.vtable->del_chars(&(pE->xTextObject), 1);
969  internal_notify_change(pC, 0);
970  }
971 
972  internal_new_cursor_pos((WBEditWindow *)pC);
973 }
974 
975 static void internal_tab(WBChildFrame *pC, int iACS)
976 {
977 WBEditWindow *pE = (WBEditWindow *)pC;
978 
979 
980  CALLBACK_TRACKER;
981 
982  if(!WBIsValidEditWindow(pE))
983  {
984  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
985 
986  return;
987  }
988 
989  // if there's a selection, indent it??
990 
991  if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with tab. yet.
992  {
993  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
994  }
995  else
996  {
997  pE->xTextObject.vtable->ins_chars(&(pE->xTextObject), "\t", 1);
998  internal_notify_change(pC, 0);
999  }
1000 
1001  internal_new_cursor_pos((WBEditWindow *)pC);
1002 }
1003 
1004 static void internal_enter(WBChildFrame *pC, int iACS)
1005 {
1006 WBEditWindow *pE = (WBEditWindow *)pC;
1007 
1008 
1009  CALLBACK_TRACKER;
1010 
1011  if(!WBIsValidEditWindow(pE))
1012  {
1013  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1014 
1015  return;
1016  }
1017 
1018  if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'enter'. yet.
1019  {
1020  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1021  }
1022  else
1023  {
1024  pE->xTextObject.vtable->ins_chars(&(pE->xTextObject), "\n", 1);
1025  internal_notify_change(pC, 0);
1026  }
1027 
1028  internal_new_cursor_pos((WBEditWindow *)pC);
1029 }
1030 
1031 static void internal_uparrow(WBChildFrame *pC, int iACS)
1032 {
1033 WBEditWindow *pE = (WBEditWindow *)pC;
1034 
1035 
1036  CALLBACK_TRACKER;
1037 
1038  if(!WBIsValidEditWindow(pE))
1039  {
1040  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1041 
1042  return;
1043  }
1044 
1045  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-uparrow
1046  {
1047  pE->xTextObject.vtable->begin_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1048  pE->xTextObject.vtable->cursor_up(&(pE->xTextObject));
1049  }
1050  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-uparrow
1051  {
1052  // select to start of paragraph?
1053  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1054  }
1055  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'up'. yet.
1056  {
1057  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1058  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1059  }
1060  else
1061  {
1062  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1063  pE->xTextObject.vtable->cursor_up(&(pE->xTextObject));
1064  }
1065 
1066  internal_new_cursor_pos((WBEditWindow *)pC);
1067 }
1068 
1069 static void internal_downarrow(WBChildFrame *pC, int iACS)
1070 {
1071 WBEditWindow *pE = (WBEditWindow *)pC;
1072 
1073 
1074  CALLBACK_TRACKER;
1075 
1076  if(!WBIsValidEditWindow(pE))
1077  {
1078  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1079 
1080  return;
1081  }
1082 
1083  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-downarrow
1084  {
1085  pE->xTextObject.vtable->begin_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1087  }
1088  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-downarrow
1089  {
1090  // select to start of paragraph?
1091  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1092  }
1093  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'up'. yet.
1094  {
1095  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1096  }
1097  else
1098  {
1099  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1101  }
1102 
1103  internal_new_cursor_pos((WBEditWindow *)pC);
1104 }
1105 
1106 static void internal_leftarrow(WBChildFrame *pC, int iACS)
1107 {
1108 WBEditWindow *pE = (WBEditWindow *)pC;
1109 
1110 
1111  CALLBACK_TRACKER;
1112 
1113  if(!WBIsValidEditWindow(pE))
1114  {
1115  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1116 
1117  return;
1118  }
1119 
1120  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-leftarrow
1121  {
1122  pE->xTextObject.vtable->begin_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1124  }
1125  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-leftarrow
1126  {
1127  // select to start of previous word? end of previous word?
1128  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1129  }
1130  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'left'. yet.
1131  {
1132  WB_ERROR_PRINT("TEMPORARY: %s - iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1133 
1134  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1135  }
1136  else
1137  {
1138  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1140  }
1141 
1142  internal_new_cursor_pos((WBEditWindow *)pC);
1143 }
1144 
1145 static void internal_rightarrow(WBChildFrame *pC, int iACS)
1146 {
1147 WBEditWindow *pE = (WBEditWindow *)pC;
1148 
1149 
1150  CALLBACK_TRACKER;
1151 
1152  if(!WBIsValidEditWindow(pE))
1153  {
1154  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1155 
1156  return;
1157  }
1158 
1159  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-rightarrow
1160  {
1161  pE->xTextObject.vtable->begin_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1163  }
1164  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-rightarrow
1165  {
1166  // select to end of word? start of next word?
1167  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1168  }
1169  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling ctrl, shift, or alt with 'right'. yet.
1170  {
1171  WB_ERROR_PRINT("TEMPORARY: %s - iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1172 
1173  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1174  }
1175  else
1176  {
1177  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1179  }
1180 
1181  internal_new_cursor_pos((WBEditWindow *)pC);
1182 }
1183 
1184 static void internal_home(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-home
1199  {
1200  pE->xTextObject.vtable->begin_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1202  }
1203  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-home
1204  {
1205  // select to start of document
1206  pE->xTextObject.vtable->begin_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1208  }
1209  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control+home
1210  {
1211  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1213  }
1214  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling shift, or alt with 'home'. yet.
1215  {
1216  WB_ERROR_PRINT("TEMPORARY: %s - iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1217 
1218  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1219  }
1220  else
1221  {
1222  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1224  }
1225 
1226  internal_new_cursor_pos((WBEditWindow *)pC);
1227 }
1228 
1229 static void internal_end(WBChildFrame *pC, int iACS)
1230 {
1231 WBEditWindow *pE = (WBEditWindow *)pC;
1232 
1233 
1234  CALLBACK_TRACKER;
1235 
1236  if(!WBIsValidEditWindow(pE))
1237  {
1238  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1239 
1240  return;
1241  }
1242 
1243  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift-end
1244  {
1245  pE->xTextObject.vtable->begin_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1247  }
1248  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_SHIFT | WB_KEYEVENT_CTRL)) // ctrl-shift-end
1249  {
1250  // select to end of document
1251  pE->xTextObject.vtable->begin_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1253  }
1254  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control+end
1255  {
1256  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1258  }
1259  else if(iACS & WB_KEYEVENT_ACSMASK) // not handling shift, or alt with 'end'. yet.
1260  {
1261  WB_ERROR_PRINT("TEMPORARY: %s - iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1262 
1263  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1264  }
1265  else
1266  {
1267  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1269  }
1270 
1271  internal_new_cursor_pos((WBEditWindow *)pC);
1272 }
1273 
1274 static void internal_pgup(WBChildFrame *pC, int iACS)
1275 {
1276 WBEditWindow *pE = (WBEditWindow *)pC;
1277 
1278 
1279  CALLBACK_TRACKER;
1280 
1281  if(!WBIsValidEditWindow(pE))
1282  {
1283  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1284 
1285  return;
1286  }
1287 
1288  if(iACS) // not handling ctrl, shift, or alt with 'enter'. yet.
1289  {
1290  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1291  }
1292  else
1293  {
1294  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1295  pE->xTextObject.vtable->page_up(&(pE->xTextObject));
1296  }
1297 
1298  internal_new_cursor_pos((WBEditWindow *)pC);
1299 }
1300 
1301 static void internal_pgdown(WBChildFrame *pC, int iACS)
1302 {
1303 WBEditWindow *pE = (WBEditWindow *)pC;
1304 
1305 
1306  CALLBACK_TRACKER;
1307 
1308  if(!WBIsValidEditWindow(pE))
1309  {
1310  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1311 
1312  return;
1313  }
1314 
1315  if(iACS) // not handling ctrl, shift, or alt with 'enter'. yet.
1316  {
1317  XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1318  }
1319  else
1320  {
1321  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1322  pE->xTextObject.vtable->page_down(&(pE->xTextObject));
1323  }
1324 
1325  internal_new_cursor_pos((WBEditWindow *)pC);
1326 }
1327 
1328 static void internal_pgleft(WBChildFrame *pC, int iACS)
1329 {
1330 WBEditWindow *pE = (WBEditWindow *)pC;
1331 
1332 
1333  CALLBACK_TRACKER;
1334 
1335  if(!WBIsValidEditWindow(pE))
1336  {
1337  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1338 
1339  return;
1340  }
1341 
1342 // if(iACS) // not handling ctrl, shift, or alt with 'enter'. yet.
1343 // {
1344 // XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1345 // }
1346 // else
1347  {
1348  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1349  pE->xTextObject.vtable->page_left(&(pE->xTextObject));
1350  }
1351 
1352  internal_new_cursor_pos((WBEditWindow *)pC);
1353 }
1354 
1355 static void internal_pgright(WBChildFrame *pC, int iACS)
1356 {
1357 WBEditWindow *pE = (WBEditWindow *)pC;
1358 
1359 
1360  CALLBACK_TRACKER;
1361 
1362  if(!WBIsValidEditWindow(pE))
1363  {
1364  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1365 
1366  return;
1367  }
1368 
1369 // if(iACS) // not handling ctrl, shift, or alt with 'enter'. yet.
1370 // {
1371 // XBell(WBGetWindowDisplay(pC->wID), -100); // for now give audible feedback that I'm ignoring it
1372 // }
1373 // else
1374  {
1375  pE->xTextObject.vtable->end_highlight(&(pE->xTextObject)); // safe to call any time, multiple times
1377  }
1378 
1379  internal_new_cursor_pos((WBEditWindow *)pC);
1380 }
1381 
1382 static void internal_help(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 }
1397 
1398 static void internal_hover_notify(WBChildFrame *pC, int x, int y)
1399 {
1400 WBEditWindow *pE = (WBEditWindow *)pC;
1401 
1402 
1403  CALLBACK_TRACKER;
1404 
1405  if(!WBIsValidEditWindow(pE))
1406  {
1407  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1408 
1409  return;
1410  }
1411 
1412 }
1413 
1414 static void internal_hover_cancel(WBChildFrame *pC)
1415 {
1416 WBEditWindow *pE = (WBEditWindow *)pC;
1417 
1418 
1419  CALLBACK_TRACKER;
1420 
1421  if(!WBIsValidEditWindow(pE))
1422  {
1423  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1424 
1425  return;
1426  }
1427 
1428 }
1429 
1430 static int internal_is_ins_mode(WBChildFrame *pC)
1431 {
1432 WBEditWindow *pE = (WBEditWindow *)pC;
1433 
1434 
1435  CALLBACK_TRACKER;
1436 
1437  if(!WBIsValidEditWindow(pE))
1438  {
1439  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1440 
1441  return -1;
1442  }
1443 
1445 }
1446 
1447 static void internal_toggle_ins_mode(WBChildFrame *pC)
1448 {
1449 WBEditWindow *pE = (WBEditWindow *)pC;
1450 int iInsMode;
1451 
1452 
1453  CALLBACK_TRACKER;
1454 
1455  if(!WBIsValidEditWindow(pE))
1456  {
1457  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1458 
1459  return;
1460  }
1461 
1462  iInsMode = pE->xTextObject.vtable->get_insmode(&(pE->xTextObject)) == InsertMode_INSERT;
1464 
1465  internal_new_cursor_pos((WBEditWindow *)pC);
1466  internal_update_status_text(pE);
1467 }
1468 
1469 static void internal_copy_to_cb(WBChildFrame *pC)
1470 {
1471 WBEditWindow *pE = (WBEditWindow *)pC;
1472 char *p1;
1473 
1474 
1475  CALLBACK_TRACKER;
1476 
1477  if(!WBIsValidEditWindow(pE))
1478  {
1479  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1480 
1481  return;
1482  }
1483 
1484  // copy selection to the clipboard
1485 
1486  if(pE->xTextObject.vtable->has_select(&(pE->xTextObject)))
1487  {
1488  p1 = pE->xTextObject.vtable->get_sel_text(&(pE->xTextObject), NULL);
1489 
1490  if(p1)
1491  {
1492  WBSetClipboardData(WBGetWindowDisplay(pC->wID), aUTF8_STRING, 8, p1, strlen(p1) + 1);
1493 
1494  WBFree(p1);
1495  }
1496  }
1497  else
1498  {
1499  // no selection, can't "copy"
1500 
1501  XBell(WBGetWindowDisplay(pC->wID), -100);
1502  }
1503 }
1504 
1505 static void internal_paste_from_cb(WBChildFrame *pC)
1506 {
1507 WBEditWindow *pE = (WBEditWindow *)pC;
1508 Atom aType = aUTF8_STRING;
1509 int iFormat = 8;
1510 unsigned long nData = 0;
1511 char *p1;
1512 
1513 
1514  CALLBACK_TRACKER;
1515 
1516  if(!WBIsValidEditWindow(pE))
1517  {
1518  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1519 
1520  return;
1521  }
1522 
1523  // copy selection to the clipboard, then delete - same as internal_cut_to_cb()
1524 
1525  p1 = (char *)WBGetClipboardData(WBGetWindowDisplay(pC->wID), &aType, &iFormat, &nData);
1526  if(!p1) // try regular string, not UTF8
1527  {
1528  aType = aSTRING;
1529  p1 = (char *)WBGetClipboardData(WBGetWindowDisplay(pC->wID), &aType, &iFormat, &nData);
1530  }
1531 
1532  if(p1 && nData > 0)
1533  {
1534  if(!p1[nData - 1])
1535  {
1536  nData--;
1537  }
1538  }
1539 
1540 
1541  if(p1)
1542  {
1543  // TODO: convert to correct format (ASCII)
1544  if(iFormat != 8) // 16-bit unicode is assumed now
1545  {
1546  if(iFormat == 8 * sizeof(wchar_t))
1547  {
1548  char *pNew = WBAlloc(sizeof(wchar_t) * (nData + 2));
1549  if(pNew)
1550  {
1551  bzero(pNew, sizeof(wchar_t) * (nData + 2));
1552  wcstombs(pNew, (const wchar_t *)p1, sizeof(wchar_t) * (nData + 2));
1553  }
1554 
1555  WBFree(p1);
1556  p1 = pNew;
1557  nData = strlen(p1);
1558  }
1559  else
1560  {
1561  XBell(WBGetWindowDisplay(pC->wID), -100);
1562  WB_ERROR_PRINT("TEMPORARY - %s - clipboard format %d, can't 'PASTE'\n", __FUNCTION__, iFormat);
1563 
1564  WBFree(p1);
1565  p1 = NULL; // by convention - also, checked in next section
1566  }
1567  }
1568 
1569  if(p1)
1570  {
1571  WBDebugDump("Edit window 'paste'", p1, nData);
1572 
1573  if(pE->xTextObject.vtable->has_select(&(pE->xTextObject)))
1574  {
1575  pE->xTextObject.vtable->replace_select(&(pE->xTextObject), p1, nData);
1576  internal_notify_change(pC, 0);
1577  }
1578  else
1579  {
1580  pE->xTextObject.vtable->ins_chars(&(pE->xTextObject), p1, nData);
1581  internal_notify_change(pC, 0);
1582  }
1583 
1584  WBFree(p1);
1585  p1 = NULL; // by convention
1586  }
1587  }
1588 
1589  internal_new_cursor_pos((WBEditWindow *)pC);
1590 }
1591 
1592 static void internal_cut_to_cb(WBChildFrame *pC)
1593 {
1594 WBEditWindow *pE = (WBEditWindow *)pC;
1595 
1596 
1597  CALLBACK_TRACKER;
1598 
1599  if(!WBIsValidEditWindow(pE))
1600  {
1601  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1602 
1603  return;
1604  }
1605 
1606  if(!pE->xTextObject.vtable->has_select(&(pE->xTextObject)))
1607  {
1608  // no selection, can't "cut"
1609  XBell(WBGetWindowDisplay(pC->wID), -100);
1610  }
1611  else
1612  {
1613  // copy selection to the clipboard, then delete - same as internal_cut_to_cb()
1614 
1615  char *p1 = pE->xTextObject.vtable->get_sel_text(&(pE->xTextObject), NULL);
1616  if(p1)
1617  {
1618  WBSetClipboardData(WBGetWindowDisplay(pC->wID), aUTF8_STRING, 8, p1, strlen(p1) + 1);
1619 
1620  WBFree(p1);
1621 
1623  internal_notify_change(pC, 0);
1624  }
1625  }
1626 
1627  internal_new_cursor_pos((WBEditWindow *)pC);
1628 }
1629 
1630 static void internal_delete_sel(WBChildFrame *pC)
1631 {
1632 WBEditWindow *pE = (WBEditWindow *)pC;
1633 
1634 
1635  CALLBACK_TRACKER;
1636 
1637  if(!WBIsValidEditWindow(pE))
1638  {
1639  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1640 
1641  return;
1642  }
1643 
1644  if(!pE->xTextObject.vtable->has_select(&(pE->xTextObject)))
1645  {
1646  // no selection, can't "cut"
1647  XBell(WBGetWindowDisplay(pC->wID), -100);
1648  }
1649  else
1650  {
1652  internal_notify_change(pC, 0);
1653  }
1654 
1655  internal_new_cursor_pos((WBEditWindow *)pC);
1656 }
1657 
1658 static void internal_select_all(WBChildFrame *pC)
1659 {
1660 WBEditWindow *pE = (WBEditWindow *)pC;
1661 WB_RECT rct;
1662 
1663 
1664  CALLBACK_TRACKER;
1665 
1666  if(!WBIsValidEditWindow(pE))
1667  {
1668  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1669 
1670  return;
1671  }
1672 
1673  rct.left = rct.top = 0;
1674  rct.right = pE->xTextObject.vtable->get_cols(&(pE->xTextObject));
1675  rct.bottom = pE->xTextObject.vtable->get_rows(&(pE->xTextObject));
1676 
1677  WB_ERROR_PRINT("TEMPORARY: %s - selecting %d,%d,%d,%d\n", __FUNCTION__,
1678  rct.left, rct.top, rct.right, rct.bottom);
1679 
1680  pE->xTextObject.vtable->set_select(&(pE->xTextObject), &rct); // select 'all'
1681 
1682 //#if 1
1683 // pE->xTextObject.vtable->get_select(&(pE->xTextObject), &rct); // get selection for testing
1684 //
1685 // WB_ERROR_PRINT("TEMPORARY: %s - selected %d,%d,%d,%d\n", __FUNCTION__,
1686 // rct.left, rct.top, rct.right, rct.bottom);
1687 //#endif // 1
1688 
1689  internal_new_cursor_pos((WBEditWindow *)pC);
1690 }
1691 
1692 static void internal_select_none(WBChildFrame *pC)
1693 {
1694 WBEditWindow *pE = (WBEditWindow *)pC;
1695 
1696 
1697  CALLBACK_TRACKER;
1698 
1699  if(!WBIsValidEditWindow(pE))
1700  {
1701  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1702 
1703  return;
1704  }
1705 
1706  pE->xTextObject.vtable->set_select(&(pE->xTextObject), NULL);
1707 
1708  internal_new_cursor_pos((WBEditWindow *)pC);
1709 }
1710 
1711 static void internal_save(WBChildFrame *pC, const char *szFileName)
1712 {
1713 WBEditWindow *pE = (WBEditWindow *)pC;
1714 
1715 
1716  CALLBACK_TRACKER;
1717 
1718  if(!WBIsValidEditWindow(pE))
1719  {
1720  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1721 
1722  return;
1723  }
1724 
1725  WBEditWindowSaveFile(pE, szFileName);
1726 }
1727 
1728 static WB_PCSTR internal_get_file_name(WBChildFrame *pC)
1729 {
1730 WBEditWindow *pE = (WBEditWindow *)pC;
1731 
1732 
1733  CALLBACK_TRACKER;
1734 
1735  if(!WBIsValidEditWindow(pE))
1736  {
1737  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1738 
1739  return NULL;
1740  }
1741 
1742  return pE->szFileName;
1743 }
1744 
1745 static void internal_mouse_click(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1746 {
1747 WBEditWindow *pE = (WBEditWindow *)pC;
1748 
1749 
1750  CALLBACK_TRACKER;
1751 
1752  if(!WBIsValidEditWindow(pE))
1753  {
1754  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1755 
1756  return;
1757  }
1758 
1759  pE->xTextObject.vtable->mouse_click(&(pE->xTextObject), iX, iY, iButtonMask, iACS);
1760 
1761  internal_new_cursor_pos((WBEditWindow *)pC);
1762 }
1763 
1764 static void internal_mouse_dblclick(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1765 {
1766 WBEditWindow *pE = (WBEditWindow *)pC;
1767 
1768 
1769  CALLBACK_TRACKER;
1770 
1771  if(!WBIsValidEditWindow(pE))
1772  {
1773  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1774 
1775  return;
1776  }
1777 
1778  // TODO: select the current 'word'?
1779 
1780  internal_new_cursor_pos((WBEditWindow *)pC);
1781 }
1782 
1783 static void internal_mouse_drag(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1784 {
1785 WBEditWindow *pE = (WBEditWindow *)pC;
1786 
1787 
1788  CALLBACK_TRACKER;
1789 
1790  if(!WBIsValidEditWindow(pE))
1791  {
1792  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1793 
1794  return;
1795  }
1796 
1798 
1799  internal_new_cursor_pos((WBEditWindow *)pC);
1800 }
1801 
1802 static void internal_mouse_drop(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1803 {
1804 WBEditWindow *pE = (WBEditWindow *)pC;
1805 
1806 
1807  CALLBACK_TRACKER;
1808 
1809  if(!WBIsValidEditWindow(pE))
1810  {
1811  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1812 
1813  return;
1814  }
1815 
1817 
1818  internal_new_cursor_pos((WBEditWindow *)pC);
1819 }
1820 
1821 static void internal_mouse_move(WBChildFrame *pC, int iX, int iY)
1822 {
1823 WBEditWindow *pE = (WBEditWindow *)pC;
1824 
1825 
1826  CALLBACK_TRACKER;
1827 
1828  if(!WBIsValidEditWindow(pE))
1829  {
1830  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1831 
1832  return;
1833  }
1834 
1835  pE->xTextObject.vtable->mouse_click(&(pE->xTextObject), iX, iY, 0, 0); // report mouse motion
1836 
1837  internal_new_cursor_pos((WBEditWindow *)pC);
1838 }
1839 
1840 static void internal_mouse_scrollup(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1841 {
1842 WBEditWindow *pE = (WBEditWindow *)pC;
1843 
1844 
1845  CALLBACK_TRACKER;
1846 
1847  if(!WBIsValidEditWindow(pE))
1848  {
1849  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1850 
1851  return;
1852  }
1853 
1854 
1855 
1856  internal_new_cursor_pos((WBEditWindow *)pC);
1857 }
1858 
1859 static void internal_mouse_scrolldown(WBChildFrame *pC, int iX, int iY, int iButtonMask, int iACS)
1860 {
1861 WBEditWindow *pE = (WBEditWindow *)pC;
1862 
1863 
1864  CALLBACK_TRACKER;
1865 
1866  if(!WBIsValidEditWindow(pE))
1867  {
1868  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1869 
1870  return;
1871  }
1872 
1873 
1874 
1875  internal_new_cursor_pos((WBEditWindow *)pC);
1876 }
1877 
1878 static void internal_mouse_cancel(WBChildFrame *pC)
1879 {
1880 WBEditWindow *pE = (WBEditWindow *)pC;
1881 
1882 
1883  CALLBACK_TRACKER;
1884 
1885  if(!WBIsValidEditWindow(pE))
1886  {
1887  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1888 
1889  return;
1890  }
1891 
1892 
1893  internal_new_cursor_pos((WBEditWindow *)pC);
1894 }
1895 
1896 static void internal_get_row_col(WBChildFrame *pC, int *piR, int *piC)
1897 {
1898 WBEditWindow *pE = (WBEditWindow *)pC;
1899 
1900 
1901  CALLBACK_TRACKER;
1902 
1903  if(!WBIsValidEditWindow(pE))
1904  {
1905  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1906 
1907  return;
1908  }
1909 
1910  if(piC)
1911  {
1912  *piC = pE->xTextObject.vtable->get_col(&(pE->xTextObject));
1913  }
1914 
1915  if(piR)
1916  {
1917  *piR = pE->xTextObject.vtable->get_row(&(pE->xTextObject));
1918  }
1919 }
1920 
1921 static int internal_has_selection(WBChildFrame *pC)
1922 {
1923 WBEditWindow *pE = (WBEditWindow *)pC;
1924 
1925 
1926  CALLBACK_TRACKER;
1927 
1928  if(!WBIsValidEditWindow(pE))
1929  {
1930  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1931 
1932  return 0;
1933  }
1934 
1935  if(pE->xTextObject.vtable->get_select)
1936  {
1937  WB_RECT rctSel;
1938 
1939  pE->xTextObject.vtable->get_select(&(pE->xTextObject), &rctSel);
1940 
1941 // WB_ERROR_PRINT("TEMPORARY: %s - selection rectangle %d,%d,%d,%d\n", __FUNCTION__,
1942 // rctSel.left, rctSel.top, rctSel.right, rctSel.bottom);
1943 
1944  if(rctSel.left != rctSel.right || rctSel.bottom != rctSel.top) // NOT empty
1945  {
1946  return 1; // has a selection
1947  }
1948  }
1949 
1950  return 0; // no current selection
1951 }
1952 
1953 static void internal_undo(WBChildFrame *pC)
1954 {
1955 WBEditWindow *pE = (WBEditWindow *)pC;
1956 
1957 
1958  CALLBACK_TRACKER;
1959 
1960  if(!WBIsValidEditWindow(pE))
1961  {
1962  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1963 
1964  return;
1965  }
1966 
1967  // perform an un-do operation
1968 }
1969 
1970 static void internal_redo(WBChildFrame *pC)
1971 {
1972 WBEditWindow *pE = (WBEditWindow *)pC;
1973 
1974 
1975  CALLBACK_TRACKER;
1976 
1977  if(!WBIsValidEditWindow(pE))
1978  {
1979  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1980 
1981  return;
1982  }
1983 
1984  // perform a re-do operation
1985 }
1986 
1987 static int internal_can_undo(WBChildFrame *pC)
1988 {
1989 WBEditWindow *pE = (WBEditWindow *)pC;
1990 
1991 
1992  CALLBACK_TRACKER;
1993 
1994  if(!WBIsValidEditWindow(pE))
1995  {
1996  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
1997 
1998  return 0;
1999  }
2000 
2001  return 0; // can't un-do
2002 }
2003 
2004 static int internal_can_redo(WBChildFrame *pC)
2005 {
2006 WBEditWindow *pE = (WBEditWindow *)pC;
2007 
2008 
2009  CALLBACK_TRACKER;
2010 
2011  if(!WBIsValidEditWindow(pE))
2012  {
2013  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2014 
2015  return 0;
2016  }
2017 
2018  return 0; // can't re-do
2019 }
2020 
2021 
2022 static int internal_is_empty(WBChildFrame *pC)
2023 {
2024 WBEditWindow *pE = (WBEditWindow *)pC;
2025 
2026 
2027  CALLBACK_TRACKER;
2028 
2029  if(!WBIsValidEditWindow(pE))
2030  {
2031  WB_ERROR_PRINT("ERROR: %s - WBChildFrame and/or WBEditWindow not valid, %p\n", __FUNCTION__, pE);
2032 
2033  return -1; // return '-1' on error
2034  }
2035 
2036  // if the contents are NOT NULL, it's not 'empty'
2037 
2038  if((pE->xTextObject.vtable->get_rows && pE->xTextObject.vtable->get_rows(&(pE->xTextObject)) > 0) ||
2039  (pE->xTextObject.vtable->get_cols && pE->xTextObject.vtable->get_cols(&(pE->xTextObject)) > 0))
2040  {
2041  return 0; // NOT empty
2042  }
2043 
2044  return 1; // empty (for now; later, do I dive directly into xTextObject ??? new API for vtable?)
2045 }
2046 
const char * WB_PCSTR
pointer to const char string - a convenience typedef
struct __WBChildFrameUI__ * pUI
pointer to &#39;WBChildFrameUI&#39; function pointer table (assigned by &#39;superclass&#39;)
Definition: frame_window.h:443
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:436
&#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:109
const TEXT_OBJECT_VTABLE * vtable
method function pointers (similar to C++ virtual member functions)
Definition: text_object.h:862
static __inline__ void WBDestroyInPlaceTextObject(TEXT_OBJECT *pTextObject)
Destroy a previously initialized &#39;in-place&#39; TEXT_OBJECT structure.
Definition: text_object.h:959
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:321
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:469
void(* end_highlight)(struct _text_object_ *pThis)
End a highlight block.
Definition: text_object.h:612
int(* get_insmode)(const struct _text_object_ *pThis)
Get the current insert mode for the object.
Definition: text_object.h:377
INSERT mode, character inserted at cursor.
Definition: text_object.h:121
Window wID
Window id for the frame window.
Definition: frame_window.h:267
void(* end_mouse_drag)(struct _text_object_ *pThis)
End a mouse &#39;drag&#39; operation.
Definition: text_object.h:648
#define LOAD_COLOR0(X, Y)
macro to load a color, mostly for readability
void(* cursor_top)(struct _text_object_ *pThis)
Move the cursor to the top line.
Definition: text_object.h:705
int(* get_col)(const struct _text_object_ *pThis)
Get the current column cursor for the object.
Definition: text_object.h:488
WBFrameWindow * pOwner
a pointer to the WBFrameWindow owner
Definition: frame_window.h:413
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:690
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:335
void(* cursor_left)(struct _text_object_ *pThis)
Move the current cursor position left one column.
Definition: text_object.h:665
Atom aQUERY_CLOSE
query if it&#39;s ok to close (and optionally destroy yourself if ok) a window
int(* get_row)(const struct _text_object_ *pThis)
Get the current row cursor for the object.
Definition: text_object.h:475
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:409
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:309
#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:1749
Atom aWM_TIMER
timer notifications generated by API
void(* cursor_home)(struct _text_object_ *pThis)
Move the cursor &#39;home&#39; (left or BOL)
Definition: text_object.h:695
&#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:879
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:756
static __inline__ void WBInitializeInPlaceTextObject(TEXT_OBJECT *pTextObject, Window wIDOwner)
initialize an &#39;in-place&#39; TEXT_OBJECT structure
Definition: text_object.h:934
int WBSetClipboardData(Display *pDisplay, Atom aType, int iFormat, const void *pData, unsigned long nData)
Get clipboard data of requested type.
Atom aEW_EDIT_CHANGE
&#39;Edit Change&#39; notification to user-callback, sent via ClientMessage event
Definition: edit_window.c:192
OVERWRITE mode, character inserted on top of character to the right of the cursor (if any)...
Definition: text_object.h:122
void DeleteTimer(Display *pDisplay, Window wID, long lID)
Deletes an existing timer&#39;s resources.
void FWChildFrameRecalcLayout(WBChildFrame *pChildFrame)
Child frame notification callback (called by frame window)
Definition: child_frame.c:799
TEXT_OBJECT xTextObject
the &#39;TEXT_OBJECT&#39; member, that does MOST of the work
Definition: edit_window.h:166
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:435
void WBEditWindowRegisterCallback(WBEditWindow *pEditWindow, WBWinEvent pUserCallback)
Clear the contents in the Edit Window, and NULL the stored file name.
Definition: edit_window.c:565
static __inline__ WBChildFrame * FWGetChildFrameStruct(Window wID)
Obtain the associated WBChildFrame structure pointer for a Window ID.
Definition: child_frame.h:371
void(* destructor)(struct __WBChildFrame__ *)
pointer to a &#39;superclass&#39; destructor. If not NULL, will be called by FWDestroyChildFrame() ...
Definition: frame_window.h:442
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:455
unsigned int width
static __inline int WBIsValidEditWindow(WBEditWindow *pEditWindow)
Check for valid WBEditWindow pointer.
Definition: edit_window.h:273
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:761
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:268
default for OS
Definition: text_object.h:96
XFontSet rFontSet
default font for the window
Definition: frame_window.h:414
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:499
structure for managing menu callbacks
Definition: frame_window.h:215
#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:675
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:536
#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:384
Atom aRESIZE_NOTIFY
notification of window re-size via ClientMessage
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:761
void FWDestroyChildFrame(WBChildFrame *pChildFrame)
Destroy an Child Frame.
Definition: child_frame.c:312
void(* cursor_right)(struct _text_object_ *pThis)
Move the current cursor position right one column.
Definition: text_object.h:670
void(* cursor_bottom)(struct _text_object_ *pThis)
Move the cursor to the last line.
Definition: text_object.h:710
void(* get_select)(const struct _text_object_ *pThis, WB_RECT *pRct)
Get the current selection rectangle as WB_RECT.
Definition: text_object.h:442
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:662
void(* set_row)(struct _text_object_ *pThis, int iRow)
Set the current row cursor for the object.
Definition: text_object.h:482
#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:602
void(* cursor_up)(struct _text_object_ *pThis)
Move the current cursor position up one line.
Definition: text_object.h:655
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:164
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:513
Window wID
window identifier for the &#39;Child Frame&#39; window. may contain &#39;None&#39; while being destroyed ...
Definition: frame_window.h:412
Display * WBGetWindowDisplay(Window wID)
returns the Display associated with a window
Atom aRECALC_LAYOUT
notify window that it should re-calculate things like scrollbars and viewports
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:630
Atom aEW_HOVER_NOTIFY
Hover notification to user-callback, sent via ClientMessage event.
Definition: edit_window.c:174
void(* page_left)(struct _text_object_ *pThis)
Move the current cursor position left one page.
Definition: text_object.h:685
WBEditWindow * WBEditWindowFromWindowID(Window wID)
Obtain the associated WBEditWindow structure pointer for a Window ID.
Definition: edit_window.c:422
char * szFileName
malloc&#39;d name of file associated with this edit window (NULL if none)
Definition: edit_window.h:162
WBEditWindow * WBCreateEditWindow(WBFrameWindow *pOwner, XFontStruct *pFont, const char *szFocusMenu, const WBFWMenuHandler *pHandlerArray, int fFlags)
Create an Edit Window.
Definition: edit_window.c:250
WBChildFrame childframe
elements common to a &#39;child frame&#39; (derived object)
Definition: edit_window.h:158
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:520
main controlling structure for frame windows
Definition: frame_window.h:264
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:640
#define WB_KEYEVENT_CTRL
&#39;AltCtrlShift&#39; bit flag for Control modifier for WBKeyEventProcessKey()
void(* cursor_blink)(struct _text_object_ *pThis, int bHasFocus)
Periodic callback to &#39;blink&#39; the cursor.
Definition: text_object.h:773
int CreateTimer(Display *pDisplay, Window wID, unsigned long lInterval, long lID, int iPeriodic)
Creates a one-shot or periodic timer.
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:371
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:527
Structure that defines an Edit Window.
Definition: edit_window.h:156
void WBDestroyEditWindow(WBEditWindow *pEditWindow)
Destroy an Edit Window.
Definition: edit_window.c:380
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:660
void WBEditWindowClear(WBEditWindow *pEditWindow)
Clear the contents in the Edit Window, and NULL the stored file name.
Definition: edit_window.c:551
void(* cursor_end)(struct _text_object_ *pThis)
Move the cursor to &#39;end&#39; (full doc width or EOL)
Definition: text_object.h:700
WBWinEvent pUserCallback
message callback function pointer (can be NULL)
Definition: frame_window.h:441
void(* set_select)(struct _text_object_ *pThis, const WB_RECT *pRct)
Set the current selection rectangle as WB_RECT.
Definition: text_object.h:449
internal wrapper struct for X11 &#39;geometry&#39; definition
Atom WBGetAtom(Display *pDisplay, const char *szAtomName)
Lookup and/or allocate an internal Atom for a named string (lookups include X11 atoms) ...
void(* page_down)(struct _text_object_ *pThis)
Move the current cursor position down one page.
Definition: text_object.h:680
void WBEndPaint(Window wID, GC gc)
&#39;Paint&#39; helper, frees resources and marks the update region &#39;valid&#39;
Atom aSTRING
Atoms for the clipboard.
void(* del_select)(struct _text_object_ *pThis)
Delete the current selection assigned via &#39;set_select&#39;.
Definition: text_object.h:505
WB_GEOM geom
total client-area geometry (excludes scroll bars) in &#39;pixels&#39;
Definition: frame_window.h:416
Atom aUTF8_STRING
Atoms for the clipboard.
Window wIDOwner
owner window (cached from paint/expose handling and/or cursor blink)
Definition: text_object.h:865
unsigned int ulTag
&#39;Tag&#39; identifying this structure as a WBEditWindow
Definition: edit_window.h:160