2
0

MainWindow.C 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $TOG: MainWindow.C /main/13 1998/04/06 13:22:40 mgreess $ */
  24. /*
  25. *+SNOTICE
  26. *
  27. * $TOG: MainWindow.C /main/13 1998/04/06 13:22:40 mgreess $
  28. *
  29. * RESTRICTED CONFIDENTIAL INFORMATION:
  30. *
  31. * The information in this document is subject to special
  32. * restrictions in a confidential disclosure agreement bertween
  33. * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
  34. * document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
  35. * Sun's specific written approval. This documment and all copies
  36. * and derivative works thereof must be returned or destroyed at
  37. * Sun's request.
  38. *
  39. * Copyright 1993, 1994, 1995 Sun Microsystems, Inc. All rights reserved.
  40. *
  41. *+ENOTICE
  42. */
  43. ///////////////////////////////////////////////////////////////////////////////
  44. //////////////////////////////////////////////////////////////////////////////
  45. // This example code is from the book:
  46. //
  47. // Object-Oriented Programming with C++ and OSF/Motif
  48. // by
  49. // Douglas Young
  50. // Prentice Hall, 1992
  51. // ISBN 0-13-630252-1
  52. //
  53. // Copyright 1991 by Prentice Hall
  54. // All Rights Reserved
  55. //
  56. // Permission to use, copy, modify, and distribute this software for
  57. // any purpose except publication and without fee is hereby granted, provided
  58. // that the above copyright notice appear in all copies of the software.
  59. ///////////////////////////////////////////////////////////////////////////////
  60. //////////////////////////////////////////////////////////////////////////////
  61. ////////////////////////////////////////////////////////////////////
  62. // MainWindow.C: Support a toplevel window
  63. ////////////////////////////////////////////////////////////////////
  64. #include <assert.h>
  65. #include <stdio.h>
  66. #include <stdlib.h>
  67. #include <Xm/Protocols.h>
  68. #include <Xm/AtomMgr.h>
  69. #include <Xm/MainW.h>
  70. #include <Dt/Wsm.h>
  71. #include <Dt/Session.h>
  72. #include <DtMail/IO.hh>
  73. #include <X11/Shell.h>
  74. #include <X11/Xmu/Editres.h>
  75. #include "Application.h"
  76. #include "MainWindow.h"
  77. #include "Help.hh"
  78. // The following headers are private to CDE and should NOT be required
  79. // but unfortunately are.
  80. //
  81. extern "C" {
  82. #include <Dt/HourGlass.h>
  83. }
  84. #include <Dt/Icon.h>
  85. #include <Dt/IconP.h>
  86. #include <Dt/IconFile.h>
  87. // This is a private CDE function that should be public, but is not,
  88. // and does not even have a prototype in a header. Yes, it is required.
  89. //
  90. extern "C" Pixmap _DtGetMask(Screen * screen, char * image_name);
  91. #if 0
  92. static const char * DefaultIcon = "Dtablnk";
  93. #endif
  94. static const unsigned long FLASH_INTERVAL = 250; // milliseconds
  95. MainWindow::MainWindow( char *name, Boolean allowResize ) : UIComponent ( name )
  96. {
  97. _workArea = NULL;
  98. _flashing = 0;
  99. _icon_invert = NULL;
  100. _window_invert = NULL;
  101. _icon = 0;
  102. _allow_resize = allowResize;
  103. _last_state = 0;
  104. _flash_owin = 0;
  105. _flash_iwin = 0;
  106. _main = NULL;
  107. memset(&_window_attributes, 0, sizeof(XWindowAttributes));
  108. assert ( theApplication != NULL ); // Application object must exist
  109. // before any MainWindow object
  110. theApplication->registerWindow ( this );
  111. }
  112. void
  113. MainWindow::initialize( )
  114. {
  115. char *appWorkspaces;
  116. // All toplevel windows in the MotifApp framework are
  117. // implemented as a popup shell off the Application's
  118. // base widget.
  119. //
  120. // XmNdeleteResponse is being set to DO_NOTHING so
  121. // that the user can Cancel their close request.
  122. _w = XtVaCreatePopupShell ( _name,
  123. topLevelShellWidgetClass,
  124. theApplication->baseWidget(),
  125. XmNdeleteResponse, XmDO_NOTHING,
  126. XmNallowShellResize, _allow_resize,
  127. NULL, NULL );
  128. #ifdef USE_EDITRES
  129. XtAddEventHandler(
  130. _w, (EventMask) 0, True,
  131. (XtEventHandler) _XEditResCheckMessages, NULL);
  132. #endif
  133. installDestroyHandler();
  134. // Use a Motif XmMainWindow widget to handle window layout
  135. _main = XtCreateManagedWidget ( "mainWindow",
  136. xmMainWindowWidgetClass,
  137. _w,
  138. NULL, 0 );
  139. printHelpId("_main", _main);
  140. /* install callback */
  141. // XtAddCallback(_main, XmNhelpCallback, HelpCB, helpId);
  142. XtAddCallback(_main, XmNhelpCallback,
  143. HelpCB, (void *)"_HOMETOPIC");
  144. // Called derived class to create the work area
  145. _workArea = createWorkArea ( _main );
  146. assert ( _workArea != NULL );
  147. // Designate the _workArea widget as the XmMainWindow
  148. // widget's XmNworkWindow widget
  149. XtVaSetValues ( _main,
  150. XmNworkWindow, _workArea,
  151. NULL );
  152. Atom WM_DELETE_WINDOW=XmInternAtom( XtDisplay( _w ),
  153. "WM_DELETE_WINDOW",
  154. False );
  155. XmAddWMProtocolCallback( _w,
  156. WM_DELETE_WINDOW,
  157. ( XtCallbackProc ) quitCallback,
  158. this );
  159. #if 0
  160. // Why are we setting the icon to Dtablnk. This is simply going to
  161. // be overriden by some other function setting it to the appropriate
  162. // icon.
  163. setIconName(DefaultIcon);
  164. #endif
  165. _window_invert = NULL;
  166. _last_state = 0;
  167. _flash_owin = (Window) NULL;
  168. _flash_iwin = (Window) NULL;
  169. memset((char*) &(this->_window_attributes), 0, sizeof(XWindowAttributes));
  170. // Manage the work area if the derived class hasn't already.
  171. if ( !XtIsManaged ( _workArea ) )
  172. XtManageChild ( _workArea );
  173. XtRealizeWidget(_w);
  174. appWorkspaces = theApplication->getAppWorkspaceList();
  175. setWorkspacesOccupied(appWorkspaces);
  176. }
  177. MainWindow::~MainWindow( )
  178. {
  179. // Unregister this window with the Application object
  180. if (_w) {
  181. Atom WM_DELETE_WINDOW=XmInternAtom( XtDisplay( _w ),
  182. "WM_DELETE_WINDOW",
  183. False );
  184. XmRemoveWMProtocolCallback( _w,
  185. WM_DELETE_WINDOW,
  186. ( XtCallbackProc ) quitCallback,
  187. NULL );
  188. if (_icon_invert) XFreeGC(XtDisplay(_w), _icon_invert);
  189. if (_window_invert) XFreeGC(XtDisplay(_w), _window_invert);
  190. if (_flash_iwin != (Window) NULL)
  191. XDestroyWindow( XtDisplay(_w), _flash_iwin );
  192. if (_flash_owin != (Window) NULL)
  193. XDestroyWindow( XtDisplay(_w), _flash_owin );
  194. }
  195. theApplication->unregisterWindow ( this );
  196. }
  197. void
  198. MainWindow::enableWorkAreaResize()
  199. {
  200. XtVaSetValues(_workArea, XmNresizePolicy, XmRESIZE_ANY, NULL);
  201. }
  202. void
  203. MainWindow::disableWorkAreaResize()
  204. {
  205. XtVaSetValues(_workArea, XmNresizePolicy, XmRESIZE_NONE, NULL);
  206. }
  207. void
  208. MainWindow::manage()
  209. {
  210. assert ( _w != NULL );
  211. XtPopup ( _w, XtGrabNone );
  212. // Map the window, in case the window is iconified
  213. if ( XtIsRealized ( _w ) )
  214. XMapRaised ( XtDisplay ( _w ), XtWindow ( _w ) );
  215. }
  216. void
  217. MainWindow::unmanage()
  218. {
  219. assert ( _w != NULL );
  220. XtPopdown ( _w );
  221. }
  222. void
  223. MainWindow::iconify()
  224. {
  225. assert ( _w != NULL );
  226. // Set the widget to have an initial iconic state
  227. // in case the base widget has not yet been realized
  228. XtVaSetValues ( _w, XmNiconic, TRUE, NULL );
  229. // If the widget has already been realized,
  230. // iconify the window
  231. if ( XtIsRealized ( _w ) )
  232. XIconifyWindow ( XtDisplay ( _w ), XtWindow ( _w ), 0 );
  233. }
  234. void
  235. MainWindow::setIconTitle(const char * title)
  236. {
  237. XtVaSetValues(_w, XmNiconName, title, NULL);
  238. }
  239. void
  240. MainWindow::setIconName(const char * path)
  241. {
  242. char * icon_filename = XmGetIconFileName(XtScreen(_w),
  243. NULL,
  244. (char *)path, // Bug!
  245. NULL,
  246. DtLARGE);
  247. if (icon_filename == NULL) {
  248. return;
  249. }
  250. Pixel fg = 0, bg = 0;
  251. getIconColors(fg, bg);
  252. _icon = XmGetPixmap(XtScreen(_w),
  253. icon_filename,
  254. fg, bg);
  255. Pixmap icon_mask_map = _DtGetMask(XtScreen(_w), icon_filename);
  256. if (!_icon || !icon_mask_map) {
  257. return;
  258. }
  259. XtVaSetValues(_w,
  260. XmNiconPixmap, _icon,
  261. XmNiconMask, icon_mask_map,
  262. NULL);
  263. // Build the inverted icon mask for flashing.
  264. //
  265. if (_icon_invert) {
  266. XFreeGC(XtDisplay(_w), _icon_invert);
  267. }
  268. XGCValues gc_vals;
  269. gc_vals.foreground = bg;
  270. gc_vals.function = GXxor;
  271. _icon_invert = XCreateGC(XtDisplay(_w), _icon, GCForeground | GCFunction,
  272. &gc_vals);
  273. XtFree(icon_filename);
  274. }
  275. void
  276. MainWindow::busyCursor()
  277. {
  278. // Do nothing if the widget has not been realized
  279. if (XtIsRealized(_w)) {
  280. _DtTurnOnHourGlass(_w);
  281. }
  282. }
  283. void
  284. MainWindow::normalCursor()
  285. {
  286. // Do nothing if the widget has not been realized
  287. if (XtIsRealized ( _w ))
  288. {
  289. _DtTurnOffHourGlass(_w);
  290. }
  291. }
  292. void
  293. MainWindow::setStatus(const char *)
  294. {
  295. // Noop in our case.
  296. }
  297. void
  298. MainWindow::clearStatus(void)
  299. {
  300. // Noop in our case.
  301. }
  302. void
  303. MainWindow::title(const char *text )
  304. {
  305. XtVaSetValues ( _w, XmNtitle, (char *)text, NULL );
  306. }
  307. void
  308. MainWindow::quitCallback( Widget,
  309. XtPointer clientData,
  310. XmAnyCallbackStruct *)
  311. {
  312. MainWindow *window=( MainWindow *) clientData;
  313. window->quit();
  314. }
  315. void
  316. MainWindow::getIconColors(Pixel & fore, Pixel & back)
  317. {
  318. XtVaGetValues (_w,
  319. XmNforeground, &fore,
  320. XmNbackground, &back,
  321. NULL);
  322. }
  323. struct WM_STATE {
  324. int state;
  325. Window icon;
  326. };
  327. static int
  328. getWindowState(Widget w)
  329. {
  330. Atom wmStateAtom, actualType;
  331. int actualFormat;
  332. int retval;
  333. unsigned long nitems, leftover;
  334. WM_STATE *wmState;
  335. /* Getting the WM_STATE property to see if iconified or not */
  336. wmStateAtom = XInternAtom(XtDisplay(w), "WM_STATE", False);
  337. XGetWindowProperty (XtDisplay(w), XtWindow(w),
  338. wmStateAtom, 0L,
  339. (long)BUFSIZ, False, wmStateAtom, &actualType,
  340. &actualFormat, &nitems, &leftover,
  341. (unsigned char **) &wmState);
  342. if (wmState)
  343. retval = wmState->state;
  344. else
  345. retval = 0;
  346. free((void*) wmState);
  347. return retval;
  348. }
  349. void
  350. MainWindow::flash(const int count)
  351. {
  352. XWindowAttributes window_attributes;
  353. if (count == 0) return;
  354. if (_flashing > 0) return;
  355. if (_window_invert == NULL) {
  356. // Create a GC to flash the window.
  357. //
  358. XGCValues gc_vals;
  359. Pixel fg, bg;
  360. getIconColors(fg, bg);
  361. gc_vals.foreground = bg;
  362. gc_vals.function = GXxor;
  363. _window_invert = XCreateGC(XtDisplay(_w), XtWindow(_w),
  364. GCForeground | GCFunction, &gc_vals);
  365. XSetSubwindowMode(XtDisplay(_w), _window_invert, IncludeInferiors);
  366. }
  367. _last_state = getWindowState(_w);
  368. //
  369. // The original method here, to invert the window and timeout
  370. // before inverting back to the original (pixels), breaks when
  371. // the window is left with pixels XOR'd in the flash ON state.
  372. //
  373. // One quick fix, uses a transparent window (or windows) on top
  374. // of the window to be flashed. The temp window(s) are used to
  375. // prevent updates while flash is ON and/or cause a full update
  376. // (expose) after each flash.
  377. //
  378. // First, (this part optional) put an "InputOnly" window on top of
  379. // the window to be flashed and ignore all events to this window.
  380. // This has the effect of preventing user input (events) from
  381. // causing application updates to the window. This temp window
  382. // can be left up (with the wait cursor) until flashing is done.
  383. //
  384. // Next, handle expose events by using a transparent "InputOutput"
  385. // window on top of everything only when flash is ON. This has
  386. // the effect of preventing expose events from causing application
  387. // updates to the real window when flash is ON. It especially,
  388. // ensures other problems (e.g. updates to the window caused by
  389. // other application timeout events and overlapping window pixels
  390. // from an expose event) are cleaned up by an expose event when
  391. // this temp window is unmapped or destroyed (between each flash).
  392. //
  393. XGetWindowAttributes(XtDisplay(_w), XtWindow(_w), &window_attributes);
  394. if ((Window) NULL != _flash_owin &&
  395. (window_attributes.width != _window_attributes.width ||
  396. window_attributes.height != _window_attributes.height ||
  397. window_attributes.border_width != _window_attributes.border_width))
  398. {
  399. XDestroyWindow( XtDisplay(_w), _flash_iwin );
  400. XDestroyWindow( XtDisplay(_w), _flash_owin );
  401. _flash_iwin = (Window) NULL;
  402. _flash_owin = (Window) NULL;
  403. }
  404. if ((Window) NULL == _flash_owin)
  405. {
  406. XSetWindowAttributes sw_attr;
  407. memcpy((char*) &(this->_window_attributes),
  408. (char*) &window_attributes,
  409. sizeof(window_attributes));
  410. sw_attr.event_mask = 0;
  411. _flash_iwin = XCreateWindow(
  412. XtDisplay(_w), XtWindow(_w), 0, 0,
  413. _window_attributes.width, _window_attributes.height,
  414. _window_attributes.border_width, (int) CopyFromParent,
  415. InputOnly, CopyFromParent,
  416. CWEventMask, &sw_attr );
  417. XMapWindow( XtDisplay(_w), _flash_iwin );
  418. _flash_owin = XCreateWindow(
  419. XtDisplay(_w), XtWindow(_w), 0, 0,
  420. _window_attributes.width, _window_attributes.height,
  421. _window_attributes.border_width, (int) CopyFromParent,
  422. InputOutput, CopyFromParent,
  423. CWEventMask, &sw_attr );
  424. }
  425. _flashing = count * 2;
  426. XtAppAddTimeOut(
  427. XtWidgetToApplicationContext(_w),
  428. FLASH_INTERVAL, flashCallback, this);
  429. }
  430. void
  431. MainWindow::flashCallback(XtPointer client_data, XtIntervalId * interval_id)
  432. {
  433. MainWindow * mw = (MainWindow *)client_data;
  434. mw->doFlash(interval_id);
  435. }
  436. void
  437. MainWindow::doFlash(XtIntervalId *)
  438. {
  439. static int busy_cursor = 0;
  440. int state = getWindowState(_w);
  441. // We are going to make things flash an even number of times.
  442. // to do this, we will lie about the state, and leave it at the
  443. // old state for one iteration.
  444. if (state != _last_state && (_flashing % 2) != 0)
  445. state = _last_state;
  446. if (! busy_cursor) {
  447. busyCursor();
  448. busy_cursor = 1;
  449. }
  450. if (state == IconicState) {
  451. Pixmap image = _icon;
  452. XFillRectangle(XtDisplay(_w), image, _icon_invert, 0, 0, 48, 48);
  453. XtVaSetValues(_w, XmNiconPixmap, NULL, NULL);
  454. XtVaSetValues(_w, XmNiconPixmap, image, NULL);
  455. }
  456. else if (state != 0) {
  457. // Map temp window to prevent expose updates and other
  458. // application event updates ... when flash is on.
  459. if ( (_flashing % 2) == 0 )
  460. XMapWindow( XtDisplay(_w), _flash_owin );
  461. XFillRectangle(
  462. XtDisplay(_w), XtWindow(_w),
  463. _window_invert, 0, 0,
  464. _window_attributes.width, _window_attributes.height);
  465. // Remove temp window to update display when flash is off.
  466. if ( (_flashing % 2) != 0 )
  467. XUnmapWindow( XtDisplay(_w), _flash_owin );
  468. }
  469. _flashing -= 1;
  470. if (_flashing > 0) {
  471. XtAppAddTimeOut(
  472. XtWidgetToApplicationContext(_w),
  473. FLASH_INTERVAL, flashCallback, this);
  474. _last_state = state;
  475. }
  476. else {
  477. XUnmapWindow( XtDisplay(_w), _flash_iwin );
  478. XUnmapWindow( XtDisplay(_w), _flash_owin );
  479. normalCursor();
  480. busy_cursor = 0;
  481. }
  482. }
  483. Boolean
  484. MainWindow::isIconified()
  485. {
  486. Atom wmStateAtom, actualType;
  487. int actualFormat;
  488. unsigned long nitems, leftover;
  489. WM_STATE *wmState;
  490. Boolean retval = FALSE;
  491. assert ( _w != NULL );
  492. /* Getting the WM_STATE property to see if iconified or not */
  493. wmStateAtom = XInternAtom(XtDisplay(_w), "WM_STATE", False);
  494. XGetWindowProperty (XtDisplay(_w), XtWindow(_w),
  495. wmStateAtom, 0L,
  496. (long)BUFSIZ, False, wmStateAtom, &actualType,
  497. &actualFormat, &nitems, &leftover,
  498. (unsigned char **) &wmState);
  499. if (wmState && wmState->state == IconicState)
  500. retval = TRUE;
  501. free((void*) wmState);
  502. return retval;
  503. }
  504. /************************************************************************
  505. * MbStrchr -
  506. ************************************************************************/
  507. char *
  508. MainWindow::MbStrchr(char *str, int ch)
  509. {
  510. size_t mbCurMax = MB_CUR_MAX;
  511. wchar_t targetChar, curChar;
  512. char tmpChar;
  513. int i, numBytes, byteLen;
  514. if(mbCurMax <= 1) return strchr(str, ch);
  515. tmpChar = (char)ch;
  516. mbtowc(&targetChar, &tmpChar, mbCurMax);
  517. for(i = 0, numBytes = 0, byteLen = strlen(str); i < byteLen; i += numBytes)
  518. {
  519. numBytes = mbtowc(&curChar, &str[i], mbCurMax);
  520. if(curChar == targetChar) return &str[i];
  521. }
  522. return (char *)NULL;
  523. }
  524. void
  525. MainWindow::setWorkspacesOccupied(char *workspaces)
  526. {
  527. char *ptr;
  528. Atom *workspace_atoms = NULL;
  529. int nworkspaces=0;
  530. if (workspaces)
  531. {
  532. do
  533. {
  534. ptr = MbStrchr (workspaces, ' ');
  535. if (ptr != NULL) *ptr = '\0';
  536. workspace_atoms = (Atom*) XtRealloc(
  537. (char *) workspace_atoms,
  538. sizeof(Atom)*(nworkspaces+1));
  539. workspace_atoms[nworkspaces] = XmInternAtom(
  540. XtDisplay(_w),
  541. workspaces, True);
  542. nworkspaces++;
  543. if (ptr != NULL)
  544. {
  545. *ptr = ' ';
  546. workspaces = ptr + 1;
  547. }
  548. } while (ptr != NULL);
  549. DtWsmSetWorkspacesOccupied(
  550. XtDisplay(_w), XtWindow (_w),
  551. workspace_atoms, nworkspaces);
  552. XtFree ((char *) workspace_atoms);
  553. workspace_atoms = NULL;
  554. }
  555. else
  556. {
  557. Window rootWindow;
  558. Atom pCurrent;
  559. Screen *currentScreen;
  560. int screen;
  561. screen = XDefaultScreen(XtDisplay(_w));
  562. currentScreen = XScreenOfDisplay(XtDisplay(_w), screen);
  563. rootWindow = RootWindowOfScreen(currentScreen);
  564. if (DtWsmGetCurrentWorkspace(
  565. XtDisplay(_w),
  566. rootWindow,
  567. &pCurrent) == Success)
  568. DtWsmSetWorkspacesOccupied(
  569. XtDisplay(_w),
  570. XtWindow(_w),
  571. &pCurrent, 1);
  572. }
  573. }