X11 Work Bench Toolkit  1.0
child_frame.c
1 
2 // _ _ _ _ __ //
3 // ___| |__ (_) | __| | / _|_ __ __ _ _ __ ___ ___ ___ //
4 // / __| '_ \| | |/ _` | | |_| '__/ _` | '_ ` _ \ / _ \ / __| //
5 // | (__| | | | | | (_| | | _| | | (_| | | | | | | __/| (__ //
6 // \___|_| |_|_|_|\__,_|___|_| |_| \__,_|_| |_| |_|\___(_)___| //
7 // |_____| //
8 // //
9 // a window that exists as a tab in a frame window //
10 // //
11 // (part of the 'frame window' support API) //
12 // //
14 
15 /*****************************************************************************
16 
17  X11workbench - X11 programmer's 'work bench' application and toolkit
18  Copyright (c) 2010-2016 by Bob Frazier (aka 'Big Bad Bombastic Bob')
19  all rights reserved
20 
21  DISCLAIMER: The X11workbench application and toolkit software are supplied
22  'as-is', with no warranties, either implied or explicit.
23  Any claims to alleged functionality or features should be
24  considered 'preliminary', and might not function as advertised.
25 
26  BSD-like license:
27 
28  There is no restriction as to what you can do with this software, so long
29  as you include the above copyright notice and DISCLAIMER for any distributed
30  work that is equal to or derived from this one, along with this paragraph
31  that explains the terms of the license if the source is also being made
32  available. A "derived work" describes a work that uses a significant portion
33  of the source files or algorithms that are included with this one.
34  Specifically excluded from this are files that were generated by the software,
35  or anything that is included with the software that is part of another package
36  (such as files that were created or added during the 'configure' process).
37  Specifically included is the use of part or all of any of the X11 workbench
38  toolkit source or header files in your distributed application. If you do not
39  ship the source, the above copyright statement is still required to be placed
40  in a reasonably prominent place, such as documentation, splash screens, and/or
41  'about the application' dialog boxes.
42 
43  Use and distribution are in accordance with GPL, LGPL, and/or the above
44  BSD-like license. See COPYING and README files for more information.
45 
46 
47  Additional information at http://sourceforge.net/projects/X11workbench
48 
49 ******************************************************************************/
50 
51 
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <memory.h>
55 #include <string.h>
56 #include <strings.h>
57 
58 #include "window_helper.h"
59 #include "font_helper.h"
60 #include "child_frame.h"
61 #include "draw_text.h"
62 #include "menu_popup.h"
63 
64 
65 static int ChildFrameEditCutHandler(XClientMessageEvent *);
66 static int ChildFrameEditCopyHandler(XClientMessageEvent *);
67 static int ChildFrameEditPasteHandler(XClientMessageEvent *);
68 static int ChildFrameEditDeleteHandler(XClientMessageEvent *);
69 static int ChildFrameEditSelectAllHandler(XClientMessageEvent *);
70 static int ChildFrameEditSelectNoneHandler(XClientMessageEvent *);
71 static int ChildFrameEditCutUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem);
72 static int ChildFrameEditCopyUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem);
73 static int ChildFrameEditPasteUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem);
74 static int ChildFrameEditDeleteUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem);
75 static int ChildFrameEditSelectAllUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem);
76 static int ChildFrameEditSelectNoneUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem);
77 
87 FW_MENU_HANDLER_BEGIN(aChildFrameMenuHandler)
88 
89  FW_MENU_HANDLER_ENTRY(FW_EDIT_CUT_MENU, ChildFrameEditCutHandler, ChildFrameEditCutUIHandler)
90  FW_MENU_HANDLER_ENTRY(FW_EDIT_COPY_MENU, ChildFrameEditCopyHandler, ChildFrameEditCopyUIHandler)
91  FW_MENU_HANDLER_ENTRY(FW_EDIT_PASTE_MENU, ChildFrameEditPasteHandler, ChildFrameEditPasteUIHandler)
92  FW_MENU_HANDLER_ENTRY(FW_EDIT_DELETE_MENU, ChildFrameEditDeleteHandler, ChildFrameEditDeleteUIHandler)
93  FW_MENU_HANDLER_ENTRY(FW_EDIT_SELECT_ALL_MENU, ChildFrameEditSelectAllHandler, ChildFrameEditSelectAllUIHandler)
94  FW_MENU_HANDLER_ENTRY(FW_EDIT_SELECT_NONE_MENU, ChildFrameEditSelectNoneHandler, ChildFrameEditSelectNoneUIHandler)
95 
97 
98 
99 
100 static int ChildFrameDoPointerEvent(XClientMessageEvent *pEvent, Display *pDisplay,
101  Window wID, WBChildFrame *pC, WBChildFrameUI *pUI);
102 
103 static int ChildFrameDoCharEvent(XClientMessageEvent *pEvent, Display *pDisplay,
104  Window wID, WBChildFrame *pC, WBChildFrameUI *pUI);
105 
106 static WBChildFrame *pChildFrames = NULL; // pointer to linked list of 'Child Frame' windows
107 
108 
109 int FWInitChildFrame(WBChildFrame *pChildFrame, WBFrameWindow *pOwner, XFontSet rFontSet,
110  const char *szFocusMenu, const WBFWMenuHandler *pHandlerArray,
111  WBWinEvent pUserCallback, int fFlags)
112 {
113 WBChildFrame *pC;
114 XSetWindowAttributes xswa; /* Temporary Set Window Attribute struct */
115 Display *pDisplay = WBGetDefaultDisplay();
116 int iRval = -1;
117 
118 
119  if(!pChildFrame || !pOwner || pOwner->wID == None)
120  {
121  // TODO: validate 'pOwner' as a valid WBFrameWindow ??
122 
123  WB_ERROR_PRINT("%s - invalid pointers or owner window does not exist\n", __FUNCTION__);
124 
125  return -1;
126  }
127 
128  // zero out entire structure beforehand
129  bzero(pChildFrame, sizeof(*pChildFrame));
130 
131 
132  // FIRST, attach the child frame to my list o' child frames, making sure
133  // that it is not already there [if it is assume this was called twice]
134  // while I'm at it, zero out the structure BEFORE I assign 'pNext'
135 
136  if(!pChildFrames)
137  {
138  pChildFrames = pChildFrame;
139  pChildFrame->pNext = NULL; // make sure
140  }
141  else
142  {
143  pC = pChildFrames;
144 
145  while(pC->pNext)
146  {
147  if(pC == pChildFrame) // just in case
148  {
149  WB_ERROR_PRINT("%s - unexpected error condition, did you call this function before?\n", __FUNCTION__);
150 
151  return -2;
152  }
153 
154  pC = pC->pNext;
155  }
156 
157  if(pC)
158  {
159  // zero out entire structure beforehand
160  bzero(pChildFrame, sizeof(*pChildFrame));
161 
162  pC->pNext = pChildFrame;
163  pChildFrame->pNext = NULL;
164  }
165  else
166  {
167  // internal error, flag it for now and return "fail"
168  WB_ERROR_PRINT("%s - unexpected condition, returning error\n", __FUNCTION__);
169 
170  return -3;
171  }
172  }
173 
174  // if the owner is valid, but NOT tabbed, and it already has
175  // a WBChildFrame, then I fail to create this one.
176 
177  if((WBFrameWindow_NO_TABS & pOwner->iFlags)) // window has NO tabs
178  {
179  if(FWGetNumContWindows(pOwner)) // error *OR* > 0, doesn't matter, can ONLY have one tab in the frame
180  {
181  FWDestroyChildFrame(pChildFrame); // this unhooks everything (alloc'd things are zero'd by bzero)
182 
183  return -4; // can't create, SDI
184  }
185  }
186 
187 
188  // NEXT, set up all of the various 'things' in the structure that are simple assignments
189  pChildFrame->ulTag = CHILD_FRAME_TAG;
190  pChildFrame->destructor = NULL; // make sure
191 
192  if(rFontSet == None)
193  {
194  pChildFrame->rFontSet = None;
195  }
196  else
197  {
198  pChildFrame->rFontSet = WBCopyModifyFontSet(pDisplay, rFontSet, 0, 0);
199  }
200 
201  if(szFocusMenu)
202  {
203  pChildFrame->pszMenuResource = WBCopyString(szFocusMenu);
204 
205  if(!pChildFrame->pszMenuResource)
206  {
207  FWDestroyChildFrame(pChildFrame); // this unhooks everything (alloc'd things are zero'd by bzero)
208  return -5; // not enough memory
209  }
210  }
211  else
212  {
213  pChildFrame->pszMenuResource = NULL;
214  }
215 
216  if(pHandlerArray)
217  {
218  const WBFWMenuHandler *pH;
219  int iN;
220 
221  // count the number of entries in the menu handler
222  for(iN=0, pH = pHandlerArray; pH->lMenuID || pH->callback || pH->UIcallback; iN++, pH++)
223  {
224  // NOTHING inside the loop. just count.
225  }
226 
227  // allocate space and make a copy
228 
229  pChildFrame->pMenuHandler = (WBFWMenuHandler *)WBAlloc(sizeof(WBFWMenuHandler)
230  * (iN + 1
231  + sizeof(aChildFrameMenuHandler)
232  / sizeof(aChildFrameMenuHandler[0])
233  )
234  );
235 
236  if(pChildFrame->pMenuHandler)
237  {
238  if(iN > 0)
239  {
240  memcpy(pChildFrame->pMenuHandler, pHandlerArray,
241  sizeof(WBFWMenuHandler) * iN);
242  }
243 
244  memcpy(pChildFrame->pMenuHandler + iN,
245  aChildFrameMenuHandler,
246  sizeof(aChildFrameMenuHandler)); // this includes the NULL entry at the end
247  }
248  else
249  {
250  FWDestroyChildFrame(pChildFrame); // this unhooks everything (alloc'd things are zero'd by bzero)
251  return -5; // not enough memory
252  }
253  }
254 
255  // Next, I need to create the window via 'WBCreateWindow()'
256 
257  bzero(&xswa, sizeof(xswa));
258 
259  xswa.border_pixel = FWGetDefaultBD().pixel;
260  xswa.background_pixel = FWGetDefaultBG().pixel; // typically a 'grey' color
261  xswa.colormap = DefaultColormap(pDisplay, DefaultScreen(pDisplay));
262  xswa.bit_gravity = CenterGravity;
263 
264  pChildFrame->wID = WBCreateWindow(pDisplay, pOwner->wID, FWChildFrameEvent, "ChildFrame",
265  pOwner->iClientX, pOwner->iClientY,
266  pOwner->iClientWidth - 2, pOwner->iClientHeight - 2, // border is 1 pixel, so subtract 2
267  1, InputOutput,
268  CWBorderPixel | CWBackPixel | CWColormap | CWBitGravity,
269  &xswa);
270 
271  if(pChildFrame->wID == None)
272  {
273  FWDestroyChildFrame(pChildFrame);
274  return -6; // could not create the window
275  }
276 
277  // immediately identify this window's data struct using window data
278  WBSetWindowData(pChildFrame->wID, 0, (void *)pChildFrame); // window data is pointer to this struct
279  pChildFrame->pUserCallback = pUserCallback;
280 
281 
282  // create the default graphics context using the frame's color info
283  WBCreateWindowDefaultGC(pChildFrame->wID, FWGetDefaultFG().pixel, FWGetDefaultBG().pixel);
284 
285  // now allow specific kinds of input messages. I won't need 'structure notify' as they won't work
286  // anyway. those end up going to the frame window, and it passes them (as needed) to me.
287  XSelectInput(pDisplay, pChildFrame->wID,
289 
290 
291  // FINALLY, inform the frame window, which will set up some other stuff for me
292 
293  pChildFrame->pOwner = pOwner;
294  iRval = FWAddContainedWindow(pOwner, pChildFrame); // TODO: make THIS assign the owner pointer?
295 
296  if(iRval < 0) // error? (returns negative on error, otherwise the tab index)
297  {
298  FWDestroyChildFrame(pChildFrame); // this frees up all of the resources (but does not free the mem block)
299  }
300 
301  // TODO: other things
302 
303  return iRval;
304 }
305 
307 {
308 WBChildFrame *pC, *pC2;
309 Window wID;
310 
311 
312  if(!pChildFrame)
313  {
314  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
315 
316  return;
317  }
318 
319  wID = pChildFrame->wID; // make a copy of it
320 
321  // FIRST, tell the owner to remove me from the list
322 
323  if(pChildFrame->pOwner)
324  {
325  FWRemoveContainedWindow(pChildFrame->pOwner, pChildFrame);
326 
327  if(pChildFrame->pOwner != NULL)
328  {
329  WB_ERROR_PRINT("ERROR: %s - owner pointer was nut 'NULL'd out\n", __FUNCTION__);
330  }
331 
332  pChildFrame->pOwner = NULL;
333  }
334 
335  // NOW, free up any resources that were WBAlloc'd - they must also be free'd
336 
337  if(pChildFrame->szDisplayName)
338  {
339  WBFree(pChildFrame->szDisplayName);
340  pChildFrame->szDisplayName = NULL;
341  }
342 
343  if(pChildFrame->rFontSet)
344  {
345  XFreeFontSet(WBGetDefaultDisplay(), pChildFrame->rFontSet);
346  pChildFrame->rFontSet = None;
347  }
348 
349  if(pChildFrame->pMenuHandler)
350  {
351  WBFree(pChildFrame->pMenuHandler);
352  pChildFrame->pMenuHandler = NULL;
353  }
354 
355  if(pChildFrame->szStatusText)
356  {
357  WBFree(pChildFrame->szStatusText);
358  pChildFrame->szStatusText = NULL;
359  }
360 
361  if(pChildFrame->pszMenuResource)
362  {
363  WBFree(pChildFrame->pszMenuResource);
364  pChildFrame->pszMenuResource = NULL;
365  }
366 
367  // And, NOW, destroy the window itself [if it's valid]
368  //
369  // NOTE: to prevent recursion problems, a 'DestroyNotify' would mark the window ID 'None'
370  // before calling this function. this will happen within my OWN proc, if the superclass doesn't do it
371 
372  if(pChildFrame->wID != None) // if there's a chance of recursion, I detect it here
373  {
374  WBDestroyWindow(pChildFrame->wID);
375  pChildFrame->wID = None; // make sure
376  }
377 
378  // FINALLY, unlink this object from the child frame list. Do it by walking the list, looking for
379  // this entry in the list. If I find it, I unlink it [otherwise, the 'pNext' link might be *stale*]
380 
381  if(pChildFrames) // just in case, walk the list - do not rely on possibly stale pointers
382  {
383  pC2 = NULL;
384  pC = pChildFrames;
385 
386  while(pC)
387  {
388  if(pC == pChildFrame) // just in case
389  {
390  if(pC2)
391  {
392  pC2->pNext = pC->pNext; // remove from link list
393  }
394  else
395  {
396  pChildFrames = pC->pNext; // it was the head of the chain
397  }
398 
399  pC->pNext = NULL;
400 
401  break;
402  }
403 
404  pC2 = pC;
405  pC = pC->pNext;
406  }
407  }
408 
409  pChildFrame->pNext = NULL; // make sure it's not a pointer someplace that can cause problems
410 
411  // if the 'superclass' destructor was specified, call it NOW.
412 
413  if(pChildFrame->destructor)
414  {
415  // at this point, we ALWAYS destroy the callback function.
416  // "it is assumed" that I won't be needing 'DestroyNotify' to
417  // trigger any destruction. That happens *AFTER* the window was
418  // destroyed, and happens asynchronously, typically before the
419  // frame window was destroyed.
420 
421  // so, to make sure that I don't get an event callback that references
422  // the window object after it's free'd, I need to remove the callback.
423 
424  if(wID != None)
425  {
426  WBUnregisterWindowCallback(wID); // no more event handling
427  WBSetWindowData(wID, 0, (void *)NULL); // window data is no longer pointing here
428  }
429 
430  // and THEN, it's safe to call the destructor on the original object.
431  pChildFrame->destructor(pChildFrame); // this should auto-delete as well
432  }
433  else
434  {
435  // TODO: should I perform a 'Destroy Notify' callback of my own?
436 
437  // NOTE: NOT calling 'WBunregisterWindowCallback()' so 'Destroy Notify' does its job. hopefully.
438  }
439 
440  // NOTE: I have to leave the tag alone at this point, to validate that it's
441  // a 'Child Frame' structure. But everything else needs to be zero'd out
442  // (I used to use 'bzero' but I'm just commenting it here, for reference)
443  // so... make sure everything that's free'd gets ZERO'd as well. this is
444  // because a 'DestroyNotify' handler that frees up the memory (and destroys
445  // any 'superclass') will probably call this function again, and it might
446  // happen asynchronously. In fact, it probably WILL happen asynchronously.
447 
448  // bzero(pChildFrame, sizeof(*pChildFrame)); // zero it out (as a matter of course)
449 
450  // note that I do *NOT* free the WBChildFrame HERE - this simply releases all resources for it.
451  // If there is NO DESTRUCTOR, the 'Destroy Notify' handler needs to do that, or at least SOMETHING.
452  // *NOT* handling this properly can result in 'use after free' problems.
453 }
454 
455 void FWSetChildFrameMenu(WBChildFrame *pChildFrame, const char *szFocusMenu)
456 {
457  if(!pChildFrame || pChildFrame->ulTag != CHILD_FRAME_TAG)
458  {
459  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
460 
461  return;
462  }
463 
464  if(pChildFrame->pszMenuResource)
465  {
466  WBFree(pChildFrame->pszMenuResource);
467  }
468 
469  if(szFocusMenu)
470  {
471  pChildFrame->pszMenuResource = WBCopyString(szFocusMenu);
472  }
473  else
474  {
475  pChildFrame->pszMenuResource = NULL;
476  }
477 
478 }
479 
480 void FWSetChildFrameMenuHandlers(WBChildFrame *pChildFrame, const WBFWMenuHandler *pHandlerArray)
481 {
482  if(!pChildFrame || pChildFrame->ulTag != CHILD_FRAME_TAG)
483  {
484  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
485 
486  return;
487  }
488 
489  if(pChildFrame->pMenuHandler)
490  {
491  WBFree(pChildFrame->pMenuHandler);
492  }
493 
494  if(pHandlerArray)
495  {
496  const WBFWMenuHandler *pH;
497  int iN;
498 
499  // count the number of entries in the menu handler
500  for(iN=0, pH = pHandlerArray; pH->lMenuID || pH->callback || pH->UIcallback; iN++, pH++)
501  {
502  // NOTHING inside the loop. just count.
503  }
504 
505  // allocate space and make a copy
506 
507  pChildFrame->pMenuHandler = (WBFWMenuHandler *)WBAlloc(sizeof(WBFWMenuHandler)
508  * (iN + 1
509  + sizeof(aChildFrameMenuHandler)
510  / sizeof(aChildFrameMenuHandler[0])
511  )
512  );
513 
514  if(pChildFrame->pMenuHandler)
515  {
516  if(iN > 0)
517  {
518  memcpy(pChildFrame->pMenuHandler, pHandlerArray,
519  sizeof(WBFWMenuHandler) * iN);
520  }
521 
522  // this adds MY menu default handlers to the end of the list
523  // so it's possible to override them, if the owner wants to
524 
525  memcpy(pChildFrame->pMenuHandler + iN,
526  aChildFrameMenuHandler,
527  sizeof(aChildFrameMenuHandler)); // this includes the NULL entry at the end
528  }
529  }
530  else
531  {
532  pChildFrame->pMenuHandler = NULL;
533  }
534 }
535 
536 void FWSetChildFrameDisplayName(WBChildFrame *pChildFrame, const char *szDisplayName)
537 {
538  if(!pChildFrame || pChildFrame->ulTag != CHILD_FRAME_TAG)
539  {
540  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
541 
542  return;
543  }
544 
545  if(pChildFrame->szDisplayName)
546  {
547  WBFree(pChildFrame->szDisplayName);
548  }
549 
550  if(!szDisplayName)
551  {
552  return;
553  }
554 
555  pChildFrame->szDisplayName = WBCopyString(szDisplayName);
556 }
557 
558 void FWSetChildFrameImageAtom(WBChildFrame *pChildFrame, Atom aImage)
559 {
560  if(!pChildFrame || pChildFrame->ulTag != CHILD_FRAME_TAG)
561  {
562  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
563 
564  return;
565  }
566 
567  pChildFrame->aImageAtom = aImage;
568 }
569 
570 void FWSetChildFrameExtent(WBChildFrame *pChildFrame, int iXExtent, int iYExtent)
571 {
572  if(!pChildFrame || pChildFrame->ulTag != CHILD_FRAME_TAG)
573  {
574  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
575 
576  return;
577  }
578 
579 
580 
581 
582  // NOTE: see (and maybe call) FWChildFrameRecalcLayout, below
583 
584  FWChildFrameRecalcLayout(pChildFrame); // for now, do it [later change mind?]
585 }
586 
587 
588 void FWSetChildFrameScrollInfo(WBChildFrame *pChildFrame, int iRow, int iMaxRow, int iCol, int iMaxCol,
589  int iRowHeight, int iColWidth)
590 {
591  if(!pChildFrame || pChildFrame->ulTag != CHILD_FRAME_TAG)
592  {
593  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
594 
595  return;
596  }
597 
598  // NOTE: this function must *NOT* call FWChildFrameRecalcLayout, nor FWSetChildFrameExtent, in
599  // order to prevent problems with recursion. Instead, it must 'nuke out' (aka 'derive')
600  // all of those things, independently.
601 
602  WB_ERROR_PRINT("TODO: %s - implement. %p %u (%08xH) %d, %d, %d, %d, %d, %d\n", __FUNCTION__,
603  pChildFrame, (int)pChildFrame->wID, (int)pChildFrame->wID,
604  iRow, iMaxRow, iCol, iMaxCol, iRowHeight, iColWidth);
605 
606 }
607 
608 
610 {
611 WBFrameWindow *pOwner;
612 Display *pDisplay;
613 int iL, iT, iW, iH;
614 
615 
616  if(!pChildFrame || pChildFrame->ulTag != CHILD_FRAME_TAG)
617  {
618  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
619 
620  return;
621  }
622 
623 
624  pDisplay = WBGetWindowDisplay(pChildFrame->wID);
625  pOwner = pChildFrame->pOwner;
626 
627  if(!pOwner) // irrelevant if NULL. TODO: properly validate this (anal retentive if DEBUG build)
628  {
629  WB_ERROR_PRINT("ERROR: %s - pOwner is NULL for Child Frame\n", __FUNCTION__);
630 
631  return;
632  }
633 
634  iL = pOwner->iClientX;
635  iT = pOwner->iClientY;
636  iW = pOwner->iClientWidth;
637  iH = pOwner->iClientHeight;
638 
639  // resize the window accordingly
640  XMoveWindow(pDisplay, pChildFrame->wID, iL, iT);
641  XResizeWindow(pDisplay, pChildFrame->wID, iW - 2, iH - 2); // allow 1 pixel for border
642 
643  // calculate new client 'geom', backing out 2 additional pixels in all 4 directions
644 
645  pChildFrame->geom.x = 2;
646  pChildFrame->geom.y = 2;
647  pChildFrame->geom.width = iW - 6;
648  pChildFrame->geom.height = iH - 6; // the new width/height of client area
649 
650 
651  // TODO: anything ELSE that I need to do when re-calculating the layout, scrollbars, whatever
652  // just apply that to geom so that it reflects the correct viewpoirt in pixels
653  // minus any border, decorations, scrollbars, whatever, with 0,0 being top,left
654  // for the window [in this case, border is 1 pixel already]
655 
656 
657 
658  // TODO: if I need to show scrollbars, subtract height/width of bar (plus border) from
659  // the geometry width and height, as needed
660 
661 
662 // pChildFrame->iLeft = iL converted to correct units and scrolled;
663 // pChildFrame->iTop = iT converted to correct units and scrolled;
664 // pChildRrame->iWidth = iW converted to correct units;
665 // pChildFrame->iHeight = iH converted to correct units;
666 
667 
668 
669  // NOW, tell the user callback function (if any) what's happening.
670  // I must assume that the owning frame is valid and has already re-calc'd its layout
671 
672  if(pChildFrame->pUserCallback)
673  {
674  Display *pDisplay;
675  XClientMessageEvent evt;
676 
677  pDisplay = WBGetWindowDisplay(pChildFrame->wID);
678 
679  bzero(&evt, sizeof(evt));
680  evt.type = ClientMessage;
681 
682  evt.display = pDisplay;
683  evt.window = pChildFrame->wID;
684  evt.message_type = aRESIZE_NOTIFY;
685  evt.format = 32; // always
686  evt.data.l[0] = pChildFrame->geom.x; // left
687  evt.data.l[1] = pChildFrame->geom.y; // top
688  evt.data.l[2] = pChildFrame->geom.x + pChildFrame->geom.width; // right
689  evt.data.l[3] = pChildFrame->geom.y + pChildFrame->geom.height; // bottom
690 
691  // required implementation. superclass must process this and fix up scroll info
692  pChildFrame->pUserCallback(evt.window, (XEvent *)&evt);
693  }
694 
695 
696  // TODO: fix the scrollbars and invalidate rectangles
697 
698 }
699 
701 {
702  if(!pChildFrame || pChildFrame->ulTag != CHILD_FRAME_TAG)
703  {
704  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
705 
706  return;
707  }
708 
709  // for now, don't mess with the tabs, just set the text
710  // later, I may need to store the tab info.
711 
712  FWSetStatusText(pChildFrame->pOwner, pChildFrame->szStatusText);
713 }
714 
715 
717 {
718 Display *pDisplay;
719 XClientMessageEvent evt;
720 
721 
722  if(!pChildFrame || pChildFrame->ulTag != CHILD_FRAME_TAG)
723  {
724  WB_ERROR_PRINT("ERROR: %s - pChildFrame not valid\n", __FUNCTION__);
725 
726  return -1; // an error
727  }
728 
729  if(!pChildFrame->pUserCallback)
730  {
731  return 0; // return 'ok to close' when there's no 'user callback' function to query
732  }
733 
734  pDisplay = WBGetWindowDisplay(pChildFrame->wID);
735 
736  bzero(&evt, sizeof(evt));
737  evt.type = ClientMessage;
738 
739  evt.display = pDisplay;
740  evt.window = pChildFrame->wID;
741  evt.message_type = aQUERY_CLOSE;
742  evt.format = 32; // always
743 
744  return pChildFrame->pUserCallback(evt.window, (XEvent *)&evt);
745 }
746 
747 
748 // DEFAULT WINDOW EVENT HANDLER FOR CHILD FRAME
749 
750 int FWChildFrameEvent(Window wID, XEvent *pEvent)
751 {
752 int iRval = 0;
753 WBChildFrame *pC;
754 WBFrameWindow *pFW;
755 #ifndef NO_DEBUG
756 char tbuf[32]; // for keyboard input
757 int nChar = sizeof(tbuf);
758 #endif // NO_DEBUG
759 
760 
761  pC = FWGetChildFrameStruct(wID);
762 
763  if(!pC)
764  {
765 #ifndef NO_DEBUG
766  WB_ERROR_PRINT("ERROR: %s - no child frame structure, window data is %p\n", __FUNCTION__, WBGetWindowData(wID, 0));
767 
768  WBDebugDumpEvent(pEvent);
769 #endif // NO_DEBUG
770 
771  return 0;
772  }
773 
774  pFW = pC->pOwner; // make sure I know my owning frame window
775 
776 
777  // TODO: messages I handle myself, before any user callbacks
778  // (and perhaps messages that I don't pass to the callback at all)
779 
780  if(pC->pUserCallback)
781  {
782  iRval = pC->pUserCallback(wID, pEvent);
783  }
784 
785 
786  // TODO: menu and menu UI handler? For now, no. rely on frame window.
787 
788  if(pEvent->type == ClientMessage &&
789  (pEvent->xclient.message_type == aMENU_COMMAND ||
790  pEvent->xclient.message_type == aMENU_UI_COMMAND))
791  {
792  // TODO: special handling?
793 
794  return iRval; // default behavior for these
795  }
796 
797 
798  // regardless, for a 'DestroyNotify, assign wID to 'None' in the ChildFrame class
799 
800  if(!iRval)
801  {
802  // TODO: default handling of messages NOT handled by user callback
803 
804  switch(pEvent->type)
805  {
806  case KeyPress:
807  {
808 #ifndef NO_DEBUG
809  int iACS = 0;
810  int iKey = WBKeyEventProcessKey((XKeyEvent *)pEvent, tbuf, &nChar, &iACS);
811 
813  "%s KEY PRESS for KEY %d KEYCODE %d MASK=%d (%xH)\n",
814  __FUNCTION__, iKey, ((XKeyEvent *)pEvent)->keycode,
815  ((XKeyEvent *)pEvent)->state, ((XKeyEvent *)pEvent)->state);
816 #endif // NO_DEBUG
817 
818  // check for menu and hotkey activation.
819 // if(nChar > 0) // only for "real" characters (i.e. not just the ALT key)
820  if(pFW)
821  {
823 
824  if(pMenuBar) // menu bar exists?
825  {
827  "%s call to MBMenuProcessHotKey for menu window %d (%08xH)\n",
828  __FUNCTION__, (int)pMenuBar->wSelf, (int)pMenuBar->wSelf);
829 
830  iRval = MBMenuProcessHotKey(pMenuBar->pMenu, (XKeyEvent *)pEvent);
831  }
832  }
833  }
834  break;
835 
836  case KeyRelease:
837  {
838  // KeyRelease
839 #ifndef NO_DEBUG
840  int iACS = 0, iKey = WBKeyEventProcessKey((XKeyEvent *)pEvent, tbuf, &nChar, &iACS);
841 
842  if(nChar > 0)
843  {
845  "%s KEY RELEASE for KEY %d KEYCODE %d MASK=%d (%xH)\n",
846  __FUNCTION__, iKey, ((XKeyEvent *)pEvent)->keycode,
847  ((XKeyEvent *)pEvent)->state, ((XKeyEvent *)pEvent)->state);
848 
849  }
850 #endif // NO_DEBUG
851 
852  }
853 
854  break;
855 
856  case ClientMessage:
857  if(pEvent->xclient.message_type == aWM_CHAR) // generated by WBDefault
858  {
859  if(pC->pUI)
860  {
861  iRval = ChildFrameDoCharEvent(&pEvent->xclient, WBGetWindowDisplay(wID), wID, pC, pC->pUI);
862  }
863 // else
864 // {
865 // WB_ERROR_PRINT("TEMPORARY: %s - WM_CHAR, no UI\n", __FUNCTION__);
866 // WBDebugDumpEvent((XEvent *)pEvent);
867 // }
868  }
869  else if(pEvent->xclient.message_type == aWM_POINTER) // generated by WBDefault
870  {
871  if(pC->pUI)
872  {
873  iRval = ChildFrameDoPointerEvent(&pEvent->xclient, WBGetWindowDisplay(wID), wID, pC, pC->pUI);
874  }
875 // else
876 // {
877 // WB_ERROR_PRINT("TEMPORARY: %s - WM_POINTER, no UI\n", __FUNCTION__);
878 // WBDebugDumpEvent((XEvent *)pEvent);
879 // }
880  }
881 
882  break;
883  }
884  }
885 
886 
887  if(pEvent->type == DestroyNotify &&
888  pEvent->xdestroywindow.window == wID)
889  {
891  "%s - DestroyNotify\n", __FUNCTION__);
892 
893  if(!iRval)
894  {
895  WB_ERROR_PRINT("TEMPORARY: %s - DestroyNotify *NOT* handled by superclass\n", __FUNCTION__);
896  }
897 
898  pC = FWGetChildFrameStruct(wID); // re-get the structure (it may have been deleted, probably SHOULD have been)
899 
900  if(pC && pC->wID != None) // haven't called FWDestroyChildFrame yet?
901  {
902  // mark window ID 'None', then call FWDestroyChildFrame from here
903  // by design it's safe to do that...
904 
905  pC->wID = None; // since window already 'destroyed' - I'm getting the notification after all
906 
907  // set the window callback to NULL - this disconnects me from the message processor also
908  // as well as freeing up everything
909 
910  FWDestroyChildFrame(pC); // make sure it's destroyed, unlinked, etc. (pointer may not be valid now)
911 
912  WB_ERROR_PRINT("TEMPORARY: %s - DestroyNotify handled by Child Window base class\n", __FUNCTION__);
913  }
914 
915  WBUnregisterWindowCallback(wID); // prevents any more messages from being dispatched to this function
916 
917  WB_DEBUG_PRINT(DebugLevel_ERROR/*DebugLevel_Verbose | DebugSubSystem_Event | DebugSubSystem_Frame*/,
918  "%s - child frame window destroyed\n", __FUNCTION__);
919  return 1;
920  }
921 
922 
923  return iRval;
924 }
925 
926 
927 
928 static int ChildFrameDoPointerEvent(XClientMessageEvent *pEvent, Display *pDisplay,
929  Window wID, WBChildFrame *pC, WBChildFrameUI *pUI)
930 {
931 int iACS;
932 int iX, iY;
933 int iButtonMask;
934 
935 
936  if(wID == None || !pC || !pUI ||
937  pEvent->type != ClientMessage ||
938  pEvent->message_type != aWM_POINTER)
939  {
940  return 0; // sanity check (temporary?)
941  }
942 
943 #ifndef NO_DEBUG
944  WB_ERROR_PRINT("TEMPORARY: %s - WM_POINTER\n", __FUNCTION__);
945  WBDebugDumpEvent((XEvent *)pEvent);
946 #endif // NO_DEBUG
947 
948 
949  // left-click - position cursor, cancel selection
950  // shift-left-click - select from cursor to THIS point
951  // (other modifiers, ignore the modifier key)
952  // right-click - drop-down edit menu
953  // middle click - select word? paste?
954  // scroll wheel up/down - should be handled by scrollbar thingy
955  // left-drag - select from starting position
956  // right-drag - drag/drop?
957  // middle-drag - ?
958 
959  iButtonMask = pEvent->data.l[1]; // WB_POINTER_BUTTON1 through WB_POINTER_BUTTON5 (bitmask)
960 
961  iACS = pEvent->data.l[2];
962 
963  iX = pEvent->data.l[3];
964  iY = pEvent->data.l[4];
965 
966  switch(pEvent->data.l[0])
967  {
968  case WB_POINTER_CLICK:
969  if(pUI->mouse_click)
970  {
971  pUI->mouse_click(pC, iX, iY, iButtonMask, iACS);
972  return 1; // handled
973  }
974 
975  break;
976 
977  case WB_POINTER_DBLCLICK:
978  if(pUI->mouse_dblclick)
979  {
980  pUI->mouse_dblclick(pC, iX, iY, iButtonMask, iACS);
981  return 1; // handled
982  }
983 
984  break;
985 
986  case WB_POINTER_DRAG:
987  if(pUI->mouse_drag)
988  {
989  pUI->mouse_drag(pC, iX, iY, iButtonMask, iACS);
990 
991  return wID; // do this to support pointer drag (it sets up a few things correctly)
992  // NOTE: if the function isn't NULL it's expected to perform the correct operation
993  // and if there's an error, it can post a 'DRAG CANCEL' request
994  }
995 
996  break;
997 
998  case WB_POINTER_DROP:
999  if(pUI->mouse_drop)
1000  {
1001  pUI->mouse_drop(pC, iX, iY, iButtonMask, iACS);
1002  return 1; // handled
1003  }
1004 
1005  break;
1006 
1007  case WB_POINTER_MOVE:
1008  if(pUI->mouse_move)
1009  {
1010  pUI->mouse_move(pC, iX, iY); // assumes button/flags haven't changed since last time (useful only for drags)
1011  return 1; // handled
1012  }
1013 
1014  break;
1015 
1016  case WB_POINTER_CANCEL:
1017  if(pUI->mouse_cancel)
1018  {
1019  pUI->mouse_cancel(pC);
1020  return 1; // handled
1021  }
1022 
1023  break;
1024 
1025  case WB_POINTER_SCROLLUP:
1026  if(pUI->mouse_scrollup)
1027  {
1028  pUI->mouse_scrollup(pC, iX, iY, iButtonMask, iACS);
1029  return 1; // handled
1030  }
1031 
1032  break;
1033 
1034  case WB_POINTER_SCROLLDOWN:
1035  if(pUI->mouse_scrollup)
1036  {
1037  pUI->mouse_scrolldown(pC, iX, iY, iButtonMask, iACS);
1038  return 1; // handled
1039  }
1040 
1041  break;
1042 
1043 
1044  default:
1045 
1046  WB_ERROR_PRINT("TEMPORARY - %s - unhandled mousie message\n", __FUNCTION__);
1047  WBDebugDumpEvent((XEvent *)pEvent);
1048 
1049  break;
1050  }
1051 
1052  return 0; // must indicate 'did not handle' if I get here
1053 }
1054 
1055 static int ChildFrameDoCharEvent(XClientMessageEvent *pEvent, Display *pDisplay,
1056  Window wID, WBChildFrame *pC, WBChildFrameUI *pUI)
1057 {
1058 int iKey, iACS, nChar;
1059 char *pBuf;
1060 int iRval = 0;
1061 
1062 
1063  if(wID == None || !pC || !pUI ||
1064  pEvent->type != ClientMessage ||
1065  pEvent->message_type != aWM_CHAR)
1066  {
1067  return 0; // sanity check (temporary?)
1068  }
1069 
1070 //#ifndef NO_DEBUG
1071 // WB_ERROR_PRINT("TEMPORARY: %s - WM_CHAR\n", __FUNCTION__);
1072 // WBDebugDumpEvent((XEvent *)pEvent);
1073 //#endif // NO_DEBUG
1074 
1075  iKey = pEvent->data.l[0]; // result from WBKeyEventProcessKey()
1076  iACS = pEvent->data.l[1];
1077  nChar = pEvent->data.l[2];
1078  pBuf = (char *)&(pEvent->data.l[3]);
1079 
1080 
1081  if(nChar > 0) // normal ASCII characters
1082  {
1084  "%s KEY RELEASE for KEY %d KEYCODE %d MASK=%d (%xH)\n",
1085  __FUNCTION__, iKey, ((XKeyEvent *)pEvent)->keycode,
1086  ((XKeyEvent *)pEvent)->state, ((XKeyEvent *)pEvent)->state);
1087 
1088  if(iKey == 8) // backspace
1089  {
1091  "%s - BACKSPACE key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
1092 
1093  if(pUI->bkspace)
1094  {
1095  pUI->bkspace(pC, iACS);
1096  }
1097  else
1098  {
1099  XBell(pDisplay, -100);
1100  }
1101 
1102  iRval = 1;
1103  }
1104  else if(iKey == 13) // CR
1105  {
1106  if(pUI->enter)
1107  {
1108  pUI->enter(pC, iACS);
1109  }
1110  else if(pUI->do_char)
1111  {
1112  pUI->do_char(pC, pEvent);
1113  }
1114  else
1115  {
1116  XBell(pDisplay, -100);
1117  }
1118 
1119  iRval = 1;
1120  }
1121  else if(iKey == 10) // LF
1122  {
1123  if(pUI->do_char)
1124  {
1125  pUI->do_char(pC, pEvent);
1126  }
1127  else if(pUI->enter) // just in case, allow 'LF' to be 'ENTER' if no char handler
1128  {
1129  pUI->enter(pC, iACS);
1130  }
1131  else
1132  {
1133  XBell(pDisplay, -100);
1134  }
1135 
1136  iRval = 1;
1137  }
1138  else if(iKey == 9) // tab
1139  {
1140  if(pUI->tab)
1141  {
1142  pUI->tab(pC, iACS);
1143  }
1144  else if(pUI->do_char)
1145  {
1146  pUI->do_char(pC, pEvent); // treat tab like normal char
1147  }
1148  else
1149  {
1150  XBell(pDisplay, -100);
1151  }
1152 
1153  iRval = 1;
1154  }
1155  else if(iKey == 1) // CTRL+A
1156  {
1158  "%s - CTRL+A key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
1159 
1160  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
1161  {
1162  if(pUI->select_all)
1163  {
1164  pUI->select_all(pC);
1165  }
1166  else
1167  {
1168  XBell(pDisplay, -100);
1169  }
1170 
1171  iRval = 1;
1172  }
1173  else
1174  {
1175  if(pUI->do_char)
1176  {
1177  pUI->do_char(pC, pEvent); // normal 'A' character
1178 
1179  iRval = 1;
1180  }
1181  }
1182  }
1183  else if(iKey == 3) // CTRL+C
1184  {
1185  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
1186  {
1187  if(pUI->has_selection && pUI->copy_to_cb && pUI->has_selection(pC))
1188  {
1190  "%s - CTRL+C key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
1191 
1192  pUI->copy_to_cb(pC);
1193  }
1194  else
1195  {
1196  XBell(pDisplay, -100);
1197  WB_ERROR_PRINT("TEMPORARY - %s - no selection, can't 'COPY'\n", __FUNCTION__);
1198  }
1199 
1200  iRval = 1;
1201  }
1202  else
1203  {
1204  if(pUI->do_char)
1205  {
1206  pUI->do_char(pC, pEvent); // normal 'C' character
1207 
1208  iRval = 1;
1209  }
1210  }
1211  }
1212  else if(iKey == 22) // CTRL+V
1213  {
1215  "%s - CTRL+V key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
1216 
1217  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
1218  {
1219  // TODO: check for valid clipboard selection - see if there's a clipboard owner maybe?
1220 
1221  if(pUI->paste_from_cb)
1222  {
1223  pUI->paste_from_cb(pC);
1224  }
1225 
1226  iRval = 1;
1227  }
1228  else
1229  {
1230  if(pUI->do_char)
1231  {
1232  pUI->do_char(pC, pEvent); // normal 'V' character
1233 
1234  iRval = 1;
1235  }
1236  }
1237  }
1238  else if(iKey == 24) // CTRL+X
1239  {
1241  "%s - CTRL+X key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
1242 
1243  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
1244  {
1245  if(pUI->has_selection && pUI->cut_to_cb && pUI->has_selection(pC))
1246  {
1247  pUI->cut_to_cb(pC);
1248  }
1249  else
1250  {
1251  XBell(pDisplay, -100);
1252  }
1253 
1254  iRval = 1;
1255  }
1256  else
1257  {
1258  if(pUI->do_char)
1259  {
1260  pUI->do_char(pC, pEvent); // normal 'X' character
1261 
1262  iRval = 1;
1263  }
1264  }
1265  }
1266  else if(iKey == 26) // ctrl+Z
1267  {
1269  "%s - CTRL+Z key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
1270 
1271  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // control key will always be pressed, but no shift
1272  {
1273  if(pUI->can_undo && pUI->undo && pUI->can_undo(pC))
1274  {
1275  pUI->undo(pC);
1276  }
1277  else
1278  {
1279  XBell(pDisplay, -100);
1280  }
1281 
1282  iRval = 1;
1283  }
1284  else if((iACS & WB_KEYEVENT_ACSMASK) == (WB_KEYEVENT_CTRL | WB_KEYEVENT_SHIFT)) // ctrl+shift, no alt
1285  {
1286  if(pUI->can_redo && pUI->redo && pUI->can_redo(pC))
1287  {
1288  pUI->redo(pC);
1289  }
1290  else
1291  {
1292  XBell(pDisplay, -100);
1293  }
1294 
1295  iRval = 1;
1296  }
1297  else
1298  {
1299  if(pUI->do_char)
1300  {
1301  pUI->do_char(pC, pEvent); // normal 'Z' character
1302 
1303  iRval = 1; // "handled"
1304  }
1305 
1306  // ONLY assign 'iRval' if the character was processed
1307  }
1308 
1309  // NOT assigning 'iRval' for all conditions here...
1310  }
1311  else if(iKey == '\x1b') // ESC
1312  {
1314  "%s - ESC key pressed, iACS=%d (%xH)\n", __FUNCTION__, iACS, iACS);
1315 
1316  // cancel mousie things and 'select none'
1317 
1318  if(pUI->mouse_cancel)
1319  {
1320  pUI->mouse_cancel(pC);
1321  }
1322 
1323  if(pUI->select_none)
1324  {
1325  pUI->select_none(pC);
1326  }
1327 
1328  if(!pUI->select_none && !pUI->mouse_cancel)
1329  {
1330  XBell(pDisplay, -100);
1331  }
1332 
1333  iRval = 1;
1334  }
1335  else
1336  {
1337  if(pUI->do_char)
1338  {
1339  pUI->do_char(pC, pEvent);
1340 
1341  iRval = 1; // "handled"
1342  }
1343 
1344  // NOTE: don't call 'XBell' if I don't return "handled", and no 'do_char' means "not handled"
1345  }
1346  }
1347  else // SPECIAL characters.
1348  {
1349  if(iACS & WB_KEYEVENT_KEYSYM)
1350  {
1351  // TODO: international, 'dead' and other KEYSYM key assignments
1352 #define KEYSYM_MATCH_CURSOR_NAME(X) (iKey == XK_##X || iKey == XK_KP_##X)
1353 
1354  if(KEYSYM_MATCH_CURSOR_NAME(Home))
1355  {
1357  "%s - Home key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1358 
1359  if(pUI->home)
1360  {
1361  pUI->home(pC, iACS);
1362  }
1363 
1364  iRval = 1;
1365  }
1366  else if(KEYSYM_MATCH_CURSOR_NAME(End))
1367  {
1369  "%s - End key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1370 
1371  if(pUI->end)
1372  {
1373  pUI->end(pC, iACS);
1374  }
1375 
1376  iRval = 1;
1377  }
1378  else if(KEYSYM_MATCH_CURSOR_NAME(Left))
1379  {
1381  "%s - Left key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1382 
1383  if(pUI->leftarrow)
1384  {
1385  pUI->leftarrow(pC, iACS);
1386  }
1387 
1388  iRval = 1;
1389  }
1390  else if(KEYSYM_MATCH_CURSOR_NAME(Right))
1391  {
1393  "%s - Right key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1394 
1395  if(pUI->rightarrow)
1396  {
1397  pUI->rightarrow(pC, iACS);
1398  }
1399 
1400  iRval = 1;
1401  }
1402  else if(KEYSYM_MATCH_CURSOR_NAME(Up))
1403  {
1405  "%s - Up key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1406 
1407  if(pUI->uparrow)
1408  {
1409  pUI->uparrow(pC, iACS);
1410  }
1411 
1412  iRval = 1;
1413  }
1414  else if(KEYSYM_MATCH_CURSOR_NAME(Down))
1415  {
1417  "%s - Down key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1418 
1419  if(pUI->downarrow)
1420  {
1421  pUI->downarrow(pC, iACS);
1422  }
1423  else
1424  {
1425  XBell(pDisplay, -100);
1426  }
1427 
1428  iRval = 1;
1429  }
1430  else if(KEYSYM_MATCH_CURSOR_NAME(Page_Up))
1431  {
1433  "%s - Page Up key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1434 
1435  if(iACS & WB_KEYEVENT_CTRL) // page left
1436  {
1437  if(pUI->pgleft)
1438  {
1439  pUI->pgleft(pC, iACS /* & ~WB_KEYEVENT_CTRL */); // TODO: turn off 'ctrl' bit?
1440  }
1441  else
1442  {
1443  XBell(pDisplay, -100);
1444  }
1445 
1446  iRval = 1;
1447  }
1448  else
1449  {
1450  if(pUI->pgup)
1451  {
1452  pUI->pgup(pC, iACS);
1453  }
1454  else
1455  {
1456  XBell(pDisplay, -100);
1457  }
1458 
1459  iRval = 1;
1460  }
1461  }
1462  else if(KEYSYM_MATCH_CURSOR_NAME(Page_Down))
1463  {
1465  "%s - Page Down key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1466 
1467  if(iACS & WB_KEYEVENT_CTRL) // page right
1468  {
1469  if(pUI->pgright)
1470  {
1471  pUI->pgright(pC, iACS /* & ~WB_KEYEVENT_CTRL */); // TODO: turn off 'ctrl' bit?
1472  }
1473  else
1474  {
1475  XBell(pDisplay, -100);
1476  }
1477 
1478  iRval = 1;
1479  }
1480  else
1481  {
1482  if(pUI->pgdown)
1483  {
1484  pUI->pgdown(pC, iACS);
1485  }
1486  else
1487  {
1488  XBell(pDisplay, -100);
1489  }
1490 
1491  iRval = 1;
1492  }
1493  }
1494  else if(KEYSYM_MATCH_CURSOR_NAME(Begin)) // beginning of current line
1495  {
1497  "%s - Beginning Of Line key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1498 
1499  // treat this as 'home' key
1500 
1501  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift
1502  {
1503  if(pUI->home)
1504  {
1505  pUI->home(pC, WB_KEYEVENT_SHIFT);
1506  }
1507  else
1508  {
1509  XBell(pDisplay, -100);
1510  }
1511 
1512  iRval = 1;
1513  }
1514  else if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
1515  {
1516  if(pUI->home)
1517  {
1518  pUI->home(pC, iACS);
1519  }
1520  else
1521  {
1522  XBell(pDisplay, -100);
1523  }
1524 
1525  iRval = 1;
1526  }
1527  }
1528  else if(KEYSYM_MATCH_CURSOR_NAME(Insert)) // toggle 'insert' mode, copy, or paste
1529  {
1531  "%s - Insert key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1532 
1533  if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal
1534  {
1535  if(pUI->toggle_ins_mode)
1536  {
1537  pUI->toggle_ins_mode(pC);
1538 
1539  // TODO: update status bar text
1540  }
1541  else
1542  {
1543  XBell(pDisplay, -100);
1544  }
1545 
1546  iRval = 1;
1547  }
1548  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // SHIFT+insert (paste)
1549  {
1550  if(pUI->paste_from_cb)
1551  {
1552  pUI->paste_from_cb(pC);
1553  }
1554  else
1555  {
1556  XBell(pDisplay, -100);
1557  }
1558 
1559  iRval = 1;
1560  }
1561  else if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_CTRL) // CTRL+insert (copy)
1562  {
1563  if(pUI->has_selection && pUI->copy_to_cb && pUI->has_selection(pC))
1564  {
1565  pUI->copy_to_cb(pC);
1566  }
1567  else
1568  {
1569  XBell(pDisplay, -100);
1570  }
1571 
1572  iRval = 1;
1573  }
1574  }
1575  else if(KEYSYM_MATCH_CURSOR_NAME(Delete)) // delete key (keypad may use this)
1576  {
1578  "%s - Delete key pressed iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1579 
1580  if((iACS & WB_KEYEVENT_ACSMASK) == WB_KEYEVENT_SHIFT) // shift+del (cut)
1581  {
1582  if(pUI->has_selection && pUI->cut_to_cb && pUI->has_selection(pC))
1583  {
1584  pUI->cut_to_cb(pC);
1585  }
1586  else
1587  {
1588  XBell(pDisplay, -100);
1589  }
1590 
1591  iRval = 1;
1592  }
1593  else if(iACS & WB_KEYEVENT_CTRL) // ctrl+del (??) alt+del (??) any other combo?
1594  {
1595  WB_ERROR_PRINT("TEMPORARY: %s - Delete key pressed with iACS=%d (%08xH)\n", __FUNCTION__, iACS, iACS);
1596 
1597  if(pUI->del)
1598  {
1599  pUI->del(pC, iACS);
1600  }
1601  else
1602  {
1603  XBell(pDisplay, -100);
1604  }
1605 
1606  iRval = 1; // for now handle it THIS way
1607  }
1608  else // if((iACS & WB_KEYEVENT_ACSMASK) == 0) // normal or "other flags"
1609  {
1610  if(pUI->del)
1611  {
1612  pUI->del(pC, iACS);
1613  }
1614  else
1615  {
1616  XBell(pDisplay, -100);
1617  }
1618 
1619  iRval = 1;
1620  }
1621  }
1622 #undef KEYSYM_MATCH_CURSOR_NAME
1623  else
1624  {
1625  if(pUI->scancode)
1626  {
1627  pUI->scancode(pC, pEvent);
1628 
1629  iRval = 1; // handled
1630  }
1631  else
1632  {
1633  // is it an unknown cursor key? let's find out (dump it)
1635  "%s - CURSOR KEY? %d (%08xH) %d (%08xH)\n",
1636  __FUNCTION__, iKey, iKey, iACS, iACS);
1637 
1638  // 'iRval' left at 0 for "not handled"
1639  }
1640  }
1641  }
1642  }
1643 
1644  return 0; // "not handled"
1645 }
1646 
1647 
1648 
1649 static int ChildFrameEditCutHandler(XClientMessageEvent *pEvent)
1650 {
1651 WBChildFrame *pChildFrame;
1652 
1653  if(!pEvent || pEvent->window == None)
1654  {
1655  return -1; // an error
1656  }
1657 
1658  pChildFrame = FWGetChildFrameStruct(pEvent->window);
1659 
1660  if(!pChildFrame)
1661  {
1662  return -1; // an error
1663  }
1664 
1665  if(pChildFrame->pUI && pChildFrame->pUI->has_selection && pChildFrame->pUI->cut_to_cb)
1666  {
1667  if(pChildFrame->pUI->has_selection(pChildFrame))
1668  {
1669  pChildFrame->pUI->cut_to_cb(pChildFrame);
1670 
1671  return 1; // HANDLED
1672  }
1673  }
1674 
1675  return 0; // NOT handled (but not an error)
1676 }
1677 
1678 static int ChildFrameEditCopyHandler(XClientMessageEvent *pEvent)
1679 {
1680 WBChildFrame *pChildFrame;
1681 
1682  if(!pEvent || pEvent->window == None)
1683  {
1684  return -1; // an error
1685  }
1686 
1687  pChildFrame = FWGetChildFrameStruct(pEvent->window);
1688 
1689  if(!pChildFrame)
1690  {
1691  return -1; // an error
1692  }
1693 
1694  if(pChildFrame->pUI && pChildFrame->pUI->has_selection && pChildFrame->pUI->copy_to_cb)
1695  {
1696  if(pChildFrame->pUI->has_selection(pChildFrame))
1697  {
1698  pChildFrame->pUI->copy_to_cb(pChildFrame);
1699 
1700  return 1; // HANDLED
1701  }
1702  }
1703 
1704  return 0; // NOT handled (but not an error)
1705 }
1706 
1707 static int ChildFrameEditPasteHandler(XClientMessageEvent *pEvent)
1708 {
1709 WBChildFrame *pChildFrame;
1710 
1711  if(!pEvent || pEvent->window == None)
1712  {
1713  return -1; // an error
1714  }
1715 
1716  pChildFrame = FWGetChildFrameStruct(pEvent->window);
1717 
1718  if(!pChildFrame)
1719  {
1720  return -1; // an error
1721  }
1722 
1723  if(pChildFrame->pUI && pChildFrame->pUI->paste_from_cb)
1724  {
1725  // TODO: check for valid clipboard contents first?? or assume 'NULL' is ok?
1726 
1727  pChildFrame->pUI->paste_from_cb(pChildFrame);
1728 
1729  return 1; // HANDLED
1730  }
1731 
1732  return 0; // NOT handled (but not an error)
1733 }
1734 
1735 static int ChildFrameEditDeleteHandler(XClientMessageEvent *pEvent)
1736 {
1737 WBChildFrame *pChildFrame;
1738 
1739  if(!pEvent || pEvent->window == None)
1740  {
1741  return -1; // an error
1742  }
1743 
1744  pChildFrame = FWGetChildFrameStruct(pEvent->window);
1745 
1746  if(!pChildFrame)
1747  {
1748  return -1; // an error
1749  }
1750 
1751  if(pChildFrame->pUI && pChildFrame->pUI->has_selection && pChildFrame->pUI->delete_sel)
1752  {
1753  if(pChildFrame->pUI->has_selection(pChildFrame))
1754  {
1755  pChildFrame->pUI->delete_sel(pChildFrame);
1756 
1757  return 1; // HANDLED
1758  }
1759  }
1760 
1761  return 0; // NOT handled (but not an error)
1762 }
1763 
1764 static int ChildFrameEditSelectAllHandler(XClientMessageEvent *pEvent)
1765 {
1766 WBChildFrame *pChildFrame;
1767 
1768  if(!pEvent || pEvent->window == None)
1769  {
1770  return -1; // an error
1771  }
1772 
1773  pChildFrame = FWGetChildFrameStruct(pEvent->window);
1774  if(!pChildFrame)
1775  {
1776  return -1; // an error
1777  }
1778 
1779  if(pChildFrame->pUI && pChildFrame->pUI->select_all)
1780  {
1781  pChildFrame->pUI->select_all(pChildFrame);
1782 
1783  return 1; // HANDLED
1784  }
1785 
1786  return 0; // NOT handled (but not an error)
1787 }
1788 
1789 static int ChildFrameEditSelectNoneHandler(XClientMessageEvent *pEvent)
1790 {
1791 WBChildFrame *pChildFrame;
1792 
1793  if(!pEvent || pEvent->window == None)
1794  {
1795  return -1; // an error
1796  }
1797 
1798  pChildFrame = FWGetChildFrameStruct(pEvent->window);
1799  if(!pChildFrame)
1800  {
1801  return -1; // an error
1802  }
1803 
1804  if(pChildFrame->pUI && pChildFrame->pUI->select_none)
1805  {
1806  pChildFrame->pUI->select_none(pChildFrame);
1807 
1808  return 1; // HANDLED
1809  }
1810 
1811  return 0; // NOT handled (but not an error)
1812 }
1813 
1814 static int ChildFrameEditCutUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem)
1815 {
1816 Window wID;
1817 WBChildFrame *pChildFrame;
1818 WBFrameWindow *pFrame;
1819 WBMenuPopupWindow *pPopup;
1820 
1821 
1822  // pMenu essentially belongs to the frame window. determine which tab has focus, and whether
1823  // or not there's anything selected. if there is something selected, enable the menu.
1824  //
1825  // NOTE: this is called by the popup menu window itself, and so the pointer will not
1826  // be asynchronously destroyed when I call MBFindMenuPopupWindow(), nor will
1827  // the owning frame window be destroyed, either (unless someone seriously
1828  // violated the way these things are supposed to work).
1829 
1830  pPopup = MBFindMenuPopupWindow(pMenu);
1831 
1832  if(pPopup)
1833  {
1834  wID = pPopup->wOwner;
1835 
1836  if(wID != None)
1837  {
1838  pFrame = FWGetFrameWindowStruct(wID);
1839 
1840  if(pFrame)
1841  {
1842  pChildFrame = FWGetContainedWindowByIndex(pFrame, -1); // current focus window
1843 
1844  if(pChildFrame && pChildFrame->pUI && pChildFrame->pUI->has_selection)
1845  {
1846  if(pChildFrame->pUI->has_selection(pChildFrame))
1847  {
1848  return 1; // select this
1849  }
1850  }
1851  }
1852  }
1853  }
1854 
1855  return -1; // disable this menu
1856 }
1857 
1858 static int ChildFrameEditCopyUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem)
1859 {
1860 Window wID;
1861 WBChildFrame *pChildFrame;
1862 WBFrameWindow *pFrame;
1863 WBMenuPopupWindow *pPopup;
1864 
1865 
1866  // pMenu essentially belongs to the frame window. determine which tab has focus, and whether
1867  // or not there's anything selected. if there is something selected, enable the menu.
1868  //
1869  // NOTE: this is called by the popup menu window itself, and so the pointer will not
1870  // be asynchronously destroyed when I call MBFindMenuPopupWindow(), nor will
1871  // the owning frame window be destroyed, either (unless someone seriously
1872  // violated the way these things are supposed to work).
1873 
1874  pPopup = MBFindMenuPopupWindow(pMenu);
1875 
1876  if(pPopup)
1877  {
1878  wID = pPopup->wOwner;
1879 
1880  if(wID != None)
1881  {
1882  pFrame = FWGetFrameWindowStruct(wID);
1883 
1884  if(pFrame)
1885  {
1886  pChildFrame = FWGetContainedWindowByIndex(pFrame, -1); // current focus window
1887 
1888  if(pChildFrame && pChildFrame->pUI && pChildFrame->pUI->has_selection)
1889  {
1890  if(pChildFrame->pUI->has_selection(pChildFrame))
1891  {
1892  return 1; // select this
1893  }
1894  }
1895  }
1896  }
1897  }
1898 
1899  return -1; // disable this menu
1900 }
1901 
1902 static int ChildFrameEditPasteUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem)
1903 {
1904 Window wID;
1905 WBChildFrame *pChildFrame;
1906 WBFrameWindow *pFrame;
1907 WBMenuPopupWindow *pPopup;
1908 Display *pDisplay;
1909 
1910  // pMenu essentially belongs to the frame window. determine which tab has focus
1911  // THEN, determine if there's a clipboard owner, and enable if so. Disable if there
1912  // are no child frames with the focus or clipboard owners
1913  //
1914  // NOTE: this is called by the popup menu window itself, and so the pointer will not
1915  // be asynchronously destroyed when I call MBFindMenuPopupWindow(), nor will
1916  // the owning frame window be destroyed, either (unless someone seriously
1917  // violated the way these things are supposed to work).
1918 
1919  pPopup = MBFindMenuPopupWindow(pMenu);
1920 
1921  if(pPopup)
1922  {
1923  wID = pPopup->wOwner;
1924 
1925  if(wID != None)
1926  {
1927  pDisplay = WBGetWindowDisplay(wID);
1928  pFrame = FWGetFrameWindowStruct(wID);
1929 
1930  if(pFrame)
1931  {
1932  pChildFrame = FWGetContainedWindowByIndex(pFrame, -1); // current focus window
1933 
1934  if(pChildFrame && pChildFrame->pUI)
1935  {
1936  if(XGetSelectionOwner(pDisplay, aCLIPBOARD) != None ||
1937  XGetSelectionOwner(pDisplay, aPRIMARY) != None)
1938  {
1939  return 1; // there's a clipboard selection out there, waiting to be pasted
1940  }
1941  }
1942  }
1943  }
1944  }
1945 
1946  return -1; // disable this menu
1947 
1948 }
1949 
1950 static int ChildFrameEditDeleteUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem)
1951 {
1952 Window wID;
1953 WBChildFrame *pChildFrame;
1954 WBFrameWindow *pFrame;
1955 WBMenuPopupWindow *pPopup;
1956 
1957 
1958  // pMenu essentially belongs to the frame window. determine which tab has focus, and whether
1959  // or not there's anything selected. if there is something selected, enable the menu.
1960  //
1961  // NOTE: this is called by the popup menu window itself, and so the pointer will not
1962  // be asynchronously destroyed when I call MBFindMenuPopupWindow(), nor will
1963  // the owning frame window be destroyed, either (unless someone seriously
1964  // violated the way these things are supposed to work).
1965 
1966  pPopup = MBFindMenuPopupWindow(pMenu);
1967 
1968  if(pPopup)
1969  {
1970  wID = pPopup->wOwner;
1971 
1972  if(wID != None)
1973  {
1974  pFrame = FWGetFrameWindowStruct(wID);
1975 
1976  if(pFrame)
1977  {
1978  pChildFrame = FWGetContainedWindowByIndex(pFrame, -1); // current focus window
1979 
1980  if(pChildFrame && pChildFrame->pUI && pChildFrame->pUI->has_selection)
1981  {
1982  if(pChildFrame->pUI->has_selection(pChildFrame))
1983  {
1984  return 1; // select this
1985  }
1986  }
1987  }
1988  }
1989  }
1990 
1991  return -1; // disable this menu
1992 }
1993 
1994 static int ChildFrameEditSelectAllUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem)
1995 {
1996 Window wID;
1997 WBChildFrame *pChildFrame;
1998 WBFrameWindow *pFrame;
1999 WBMenuPopupWindow *pPopup;
2000 
2001 
2002  // pMenu essentially belongs to the frame window. determine which tab has focus, and whether
2003  // or not there's anything there. if there is something that CAN be selected, enable the menu.
2004  //
2005  // NOTE: this is called by the popup menu window itself, and so the pointer will not
2006  // be asynchronously destroyed when I call MBFindMenuPopupWindow(), nor will
2007  // the owning frame window be destroyed, either (unless someone seriously
2008  // violated the way these things are supposed to work).
2009 
2010  pPopup = MBFindMenuPopupWindow(pMenu);
2011 
2012  if(pPopup)
2013  {
2014  wID = pPopup->wOwner;
2015 
2016  if(wID != None)
2017  {
2018  pFrame = FWGetFrameWindowStruct(wID);
2019 
2020  if(pFrame)
2021  {
2022  pChildFrame = FWGetContainedWindowByIndex(pFrame, -1); // current focus window
2023 
2024  if(pChildFrame && pChildFrame->pUI)
2025  {
2026  if((pChildFrame->pUI->has_selection && pChildFrame->pUI->has_selection(pChildFrame)) ||
2027  (pChildFrame->pUI->is_empty && !pChildFrame->pUI->is_empty(pChildFrame)))
2028  {
2029  return 1; // select this
2030  }
2031  }
2032  }
2033  }
2034  }
2035 
2036  return -1; // disable this menu
2037 }
2038 
2039 static int ChildFrameEditSelectNoneUIHandler(WBMenu *pMenu, WBMenuItem *pMenuItem)
2040 {
2041 Window wID;
2042 WBChildFrame *pChildFrame;
2043 WBFrameWindow *pFrame;
2044 WBMenuPopupWindow *pPopup;
2045 
2046 
2047  // pMenu essentially belongs to the frame window. determine which tab has focus, and whether
2048  // or not there's anything selected. if there is something selected, enable the menu.
2049  //
2050  // NOTE: this is called by the popup menu window itself, and so the pointer will not
2051  // be asynchronously destroyed when I call MBFindMenuPopupWindow(), nor will
2052  // the owning frame window be destroyed, either (unless someone seriously
2053  // violated the way these things are supposed to work).
2054 
2055  pPopup = MBFindMenuPopupWindow(pMenu);
2056 
2057  if(pPopup)
2058  {
2059  wID = pPopup->wOwner;
2060 
2061  if(wID != None)
2062  {
2063  pFrame = FWGetFrameWindowStruct(wID);
2064 
2065  if(pFrame)
2066  {
2067  pChildFrame = FWGetContainedWindowByIndex(pFrame, -1); // current focus window
2068 
2069  if(pChildFrame && pChildFrame->pUI && pChildFrame->pUI->has_selection)
2070  {
2071  if(pChildFrame->pUI->has_selection(pChildFrame))
2072  {
2073  return 1; // select this
2074  }
2075  }
2076  }
2077  }
2078  }
2079 
2080  return -1; // disable this menu
2081 }
2082