2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: MainWindow.C /main/13 1998/04/06 13:22:40 mgreess $ */
27 * $TOG: MainWindow.C /main/13 1998/04/06 13:22:40 mgreess $
29 * RESTRICTED CONFIDENTIAL INFORMATION:
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
39 * Copyright 1993, 1994, 1995 Sun Microsystems, Inc. All rights reserved.
44 ///////////////////////////////////////////////////////////////////////////////
45 //////////////////////////////////////////////////////////////////////////////
46 // This example code is from the book:
48 // Object-Oriented Programming with C++ and OSF/Motif
51 // Prentice Hall, 1992
54 // Copyright 1991 by Prentice Hall
55 // All Rights Reserved
57 // Permission to use, copy, modify, and distribute this software for
58 // any purpose except publication and without fee is hereby granted, provided
59 // that the above copyright notice appear in all copies of the software.
60 ///////////////////////////////////////////////////////////////////////////////
61 //////////////////////////////////////////////////////////////////////////////
64 ////////////////////////////////////////////////////////////////////
65 // MainWindow.C: Support a toplevel window
66 ////////////////////////////////////////////////////////////////////
70 #include <Xm/Protocols.h>
71 #include <Xm/AtomMgr.h>
74 #include <Dt/Session.h>
75 #include <DtMail/IO.hh>
76 #include <X11/Shell.h>
77 #include <X11/Xmu/Editres.h>
78 #include "Application.h"
79 #include "MainWindow.h"
82 // The following headers are private to CDE and should NOT be required
83 // but unfortunately are.
86 #include <Dt/HourGlass.h>
90 #include <Dt/IconFile.h>
92 // This is a private CDE function that should be public, but is not,
93 // and does not even have a prototype in a header. Yes, it is required.
95 extern "C" Pixmap _DtGetMask(Screen * screen, char * image_name);
98 static const char * DefaultIcon = "Dtablnk";
100 static const unsigned long FLASH_INTERVAL = 250; // milliseconds
102 MainWindow::MainWindow( char *name, Boolean allowResize ) : UIComponent ( name )
107 _window_invert = NULL;
109 _allow_resize = allowResize;
114 memset(&_window_attributes, 0, sizeof(XWindowAttributes));
116 assert ( theApplication != NULL ); // Application object must exist
117 // before any MainWindow object
118 theApplication->registerWindow ( this );
122 MainWindow::initialize( )
126 // All toplevel windows in the MotifApp framework are
127 // implemented as a popup shell off the Application's
130 // XmNdeleteResponse is being set to DO_NOTHING so
131 // that the user can Cancel their close request.
133 _w = XtVaCreatePopupShell ( _name,
134 topLevelShellWidgetClass,
135 theApplication->baseWidget(),
136 XmNdeleteResponse, XmDO_NOTHING,
137 XmNallowShellResize, _allow_resize,
142 _w, (EventMask) 0, True,
143 (XtEventHandler) _XEditResCheckMessages, NULL);
146 installDestroyHandler();
148 // Use a Motif XmMainWindow widget to handle window layout
150 _main = XtCreateManagedWidget ( "mainWindow",
151 xmMainWindowWidgetClass,
154 printHelpId("_main", _main);
155 /* install callback */
156 // XtAddCallback(_main, XmNhelpCallback, HelpCB, helpId);
157 XtAddCallback(_main, XmNhelpCallback,
158 HelpCB, (void *)"_HOMETOPIC");
160 // Called derived class to create the work area
162 _workArea = createWorkArea ( _main );
163 assert ( _workArea != NULL );
165 // Designate the _workArea widget as the XmMainWindow
166 // widget's XmNworkWindow widget
168 XtVaSetValues ( _main,
169 XmNworkWindow, _workArea,
172 Atom WM_DELETE_WINDOW=XmInternAtom( XtDisplay( _w ),
176 XmAddWMProtocolCallback( _w,
178 ( XtCallbackProc ) quitCallback,
182 // Why are we setting the icon to Dtablnk. This is simply going to
183 // be overriden by some other function setting it to the appropriate
185 setIconName(DefaultIcon);
188 _window_invert = NULL;
190 _flash_owin = (Window) NULL;
191 _flash_iwin = (Window) NULL;
192 memset((char*) &(this->_window_attributes), 0, sizeof(XWindowAttributes));
194 // Manage the work area if the derived class hasn't already.
196 if ( !XtIsManaged ( _workArea ) )
197 XtManageChild ( _workArea );
200 appWorkspaces = theApplication->getAppWorkspaceList();
201 setWorkspacesOccupied(appWorkspaces);
204 MainWindow::~MainWindow( )
206 // Unregister this window with the Application object
209 Atom WM_DELETE_WINDOW=XmInternAtom( XtDisplay( _w ),
212 XmRemoveWMProtocolCallback( _w,
214 ( XtCallbackProc ) quitCallback,
217 if (_icon_invert) XFreeGC(XtDisplay(_w), _icon_invert);
218 if (_window_invert) XFreeGC(XtDisplay(_w), _window_invert);
219 if (_flash_iwin != (Window) NULL)
220 XDestroyWindow( XtDisplay(_w), _flash_iwin );
221 if (_flash_owin != (Window) NULL)
222 XDestroyWindow( XtDisplay(_w), _flash_owin );
225 theApplication->unregisterWindow ( this );
229 MainWindow::enableWorkAreaResize()
231 XtVaSetValues(_workArea, XmNresizePolicy, XmRESIZE_ANY, NULL);
235 MainWindow::disableWorkAreaResize()
237 XtVaSetValues(_workArea, XmNresizePolicy, XmRESIZE_NONE, NULL);
243 assert ( _w != NULL );
244 XtPopup ( _w, XtGrabNone );
246 // Map the window, in case the window is iconified
248 if ( XtIsRealized ( _w ) )
249 XMapRaised ( XtDisplay ( _w ), XtWindow ( _w ) );
253 MainWindow::unmanage()
255 assert ( _w != NULL );
260 MainWindow::iconify()
262 assert ( _w != NULL );
264 // Set the widget to have an initial iconic state
265 // in case the base widget has not yet been realized
267 XtVaSetValues ( _w, XmNiconic, TRUE, NULL );
269 // If the widget has already been realized,
270 // iconify the window
272 if ( XtIsRealized ( _w ) )
273 XIconifyWindow ( XtDisplay ( _w ), XtWindow ( _w ), 0 );
277 MainWindow::setIconTitle(const char * title)
279 XtVaSetValues(_w, XmNiconName, title, NULL);
283 MainWindow::setIconName(const char * path)
285 char * icon_filename = XmGetIconFileName(XtScreen(_w),
287 (char *)path, // Bug!
291 if (icon_filename == NULL) {
295 Pixel fg = 0, bg = 0;
297 getIconColors(fg, bg);
299 _icon = XmGetPixmap(XtScreen(_w),
303 Pixmap icon_mask_map = _DtGetMask(XtScreen(_w), icon_filename);
305 if (!_icon || !icon_mask_map) {
310 XmNiconPixmap, _icon,
311 XmNiconMask, icon_mask_map,
314 // Build the inverted icon mask for flashing.
317 XFreeGC(XtDisplay(_w), _icon_invert);
322 gc_vals.foreground = bg;
323 gc_vals.function = GXxor;
324 _icon_invert = XCreateGC(XtDisplay(_w), _icon, GCForeground | GCFunction,
327 XtFree(icon_filename);
331 MainWindow::busyCursor()
333 // Do nothing if the widget has not been realized
335 if (XtIsRealized(_w)) {
336 _DtTurnOnHourGlass(_w);
341 MainWindow::normalCursor()
343 // Do nothing if the widget has not been realized
345 if (XtIsRealized ( _w ))
347 _DtTurnOffHourGlass(_w);
352 MainWindow::setStatus(const char *)
358 MainWindow::clearStatus(void)
364 MainWindow::title(const char *text )
366 XtVaSetValues ( _w, XmNtitle, (char *)text, NULL );
370 MainWindow::quitCallback( Widget,
371 XtPointer clientData,
372 XmAnyCallbackStruct *)
374 MainWindow *window=( MainWindow *) clientData;
379 MainWindow::getIconColors(Pixel & fore, Pixel & back)
382 XmNforeground, &fore,
383 XmNbackground, &back,
393 getWindowState(Widget w)
395 Atom wmStateAtom, actualType;
398 unsigned long nitems, leftover;
401 /* Getting the WM_STATE property to see if iconified or not */
402 wmStateAtom = XInternAtom(XtDisplay(w), "WM_STATE", False);
404 XGetWindowProperty (XtDisplay(w), XtWindow(w),
406 (long)BUFSIZ, False, wmStateAtom, &actualType,
407 &actualFormat, &nitems, &leftover,
408 (unsigned char **) &wmState);
411 retval = wmState->state;
415 free((void*) wmState);
420 MainWindow::flash(const int count)
422 XWindowAttributes window_attributes;
424 if (count == 0) return;
425 if (_flashing > 0) return;
427 if (_window_invert == NULL) {
428 // Create a GC to flash the window.
432 getIconColors(fg, bg);
434 gc_vals.foreground = bg;
435 gc_vals.function = GXxor;
436 _window_invert = XCreateGC(XtDisplay(_w), XtWindow(_w),
437 GCForeground | GCFunction, &gc_vals);
438 XSetSubwindowMode(XtDisplay(_w), _window_invert, IncludeInferiors);
441 _last_state = getWindowState(_w);
444 // The original method here, to invert the window and timeout
445 // before inverting back to the original (pixels), breaks when
446 // the window is left with pixels XOR'd in the flash ON state.
448 // One quick fix, uses a transparent window (or windows) on top
449 // of the window to be flashed. The temp window(s) are used to
450 // prevent updates while flash is ON and/or cause a full update
451 // (expose) after each flash.
453 // First, (this part optional) put an "InputOnly" window on top of
454 // the window to be flashed and ignore all events to this window.
455 // This has the effect of preventing user input (events) from
456 // causing application updates to the window. This temp window
457 // can be left up (with the wait cursor) until flashing is done.
459 // Next, handle expose events by using a transparent "InputOutput"
460 // window on top of everything only when flash is ON. This has
461 // the effect of preventing expose events from causing application
462 // updates to the real window when flash is ON. It especially,
463 // ensures other problems (e.g. updates to the window caused by
464 // other application timeout events and overlapping window pixels
465 // from an expose event) are cleaned up by an expose event when
466 // this temp window is unmapped or destroyed (between each flash).
469 XGetWindowAttributes(XtDisplay(_w), XtWindow(_w), &window_attributes);
471 if ((Window) NULL != _flash_owin &&
472 (window_attributes.width != _window_attributes.width ||
473 window_attributes.height != _window_attributes.height ||
474 window_attributes.border_width != _window_attributes.border_width))
476 XDestroyWindow( XtDisplay(_w), _flash_iwin );
477 XDestroyWindow( XtDisplay(_w), _flash_owin );
478 _flash_iwin = (Window) NULL;
479 _flash_owin = (Window) NULL;
482 if ((Window) NULL == _flash_owin)
484 XSetWindowAttributes sw_attr;
486 memcpy((char*) &(this->_window_attributes),
487 (char*) &window_attributes,
488 sizeof(window_attributes));
490 sw_attr.event_mask = 0;
491 _flash_iwin = XCreateWindow(
492 XtDisplay(_w), XtWindow(_w), 0, 0,
493 _window_attributes.width, _window_attributes.height,
494 _window_attributes.border_width, (int) CopyFromParent,
495 InputOnly, CopyFromParent,
496 CWEventMask, &sw_attr );
497 XMapWindow( XtDisplay(_w), _flash_iwin );
498 _flash_owin = XCreateWindow(
499 XtDisplay(_w), XtWindow(_w), 0, 0,
500 _window_attributes.width, _window_attributes.height,
501 _window_attributes.border_width, (int) CopyFromParent,
502 InputOutput, CopyFromParent,
503 CWEventMask, &sw_attr );
506 _flashing = count * 2;
508 XtWidgetToApplicationContext(_w),
509 FLASH_INTERVAL, flashCallback, this);
513 MainWindow::flashCallback(XtPointer client_data, XtIntervalId * interval_id)
515 MainWindow * mw = (MainWindow *)client_data;
517 mw->doFlash(interval_id);
521 MainWindow::doFlash(XtIntervalId *)
523 static int busy_cursor = 0;
524 int state = getWindowState(_w);
526 // We are going to make things flash an even number of times.
527 // to do this, we will lie about the state, and leave it at the
528 // old state for one iteration.
529 if (state != _last_state && (_flashing % 2) != 0)
537 if (state == IconicState) {
538 Pixmap image = _icon;
540 XFillRectangle(XtDisplay(_w), image, _icon_invert, 0, 0, 48, 48);
541 XtVaSetValues(_w, XmNiconPixmap, NULL, NULL);
542 XtVaSetValues(_w, XmNiconPixmap, image, NULL);
544 else if (state != 0) {
546 // Map temp window to prevent expose updates and other
547 // application event updates ... when flash is on.
548 if ( (_flashing % 2) == 0 )
549 XMapWindow( XtDisplay(_w), _flash_owin );
552 XtDisplay(_w), XtWindow(_w),
553 _window_invert, 0, 0,
554 _window_attributes.width, _window_attributes.height);
556 // Remove temp window to update display when flash is off.
557 if ( (_flashing % 2) != 0 )
558 XUnmapWindow( XtDisplay(_w), _flash_owin );
565 XtWidgetToApplicationContext(_w),
566 FLASH_INTERVAL, flashCallback, this);
570 XUnmapWindow( XtDisplay(_w), _flash_iwin );
571 XUnmapWindow( XtDisplay(_w), _flash_owin );
578 MainWindow::isIconified()
581 Atom wmStateAtom, actualType;
583 unsigned long nitems, leftover;
585 Boolean retval = FALSE;
587 assert ( _w != NULL );
589 /* Getting the WM_STATE property to see if iconified or not */
590 wmStateAtom = XInternAtom(XtDisplay(_w), "WM_STATE", False);
592 XGetWindowProperty (XtDisplay(_w), XtWindow(_w),
594 (long)BUFSIZ, False, wmStateAtom, &actualType,
595 &actualFormat, &nitems, &leftover,
596 (unsigned char **) &wmState);
599 if (wmState && wmState->state == IconicState)
602 free((void*) wmState);
606 /************************************************************************
608 ************************************************************************/
610 MainWindow::MbStrchr(char *str, int ch)
612 size_t mbCurMax = MB_CUR_MAX;
613 wchar_t targetChar, curChar;
615 int i, numBytes, byteLen;
617 if(mbCurMax <= 1) return strchr(str, ch);
620 mbtowc(&targetChar, &tmpChar, mbCurMax);
621 for(i = 0, numBytes = 0, byteLen = strlen(str); i < byteLen; i += numBytes)
623 numBytes = mbtowc(&curChar, &str[i], mbCurMax);
624 if(curChar == targetChar) return &str[i];
630 MainWindow::setWorkspacesOccupied(char *workspaces)
633 Atom *workspace_atoms = NULL;
640 ptr = MbStrchr (workspaces, ' ');
642 if (ptr != NULL) *ptr = '\0';
644 workspace_atoms = (Atom*) XtRealloc(
645 (char *) workspace_atoms,
646 sizeof(Atom)*(nworkspaces+1));
647 workspace_atoms[nworkspaces] = XmInternAtom(
655 workspaces = ptr + 1;
657 } while (ptr != NULL);
659 DtWsmSetWorkspacesOccupied(
660 XtDisplay(_w), XtWindow (_w),
661 workspace_atoms, nworkspaces);
663 XtFree ((char *) workspace_atoms);
664 workspace_atoms = NULL;
670 Screen *currentScreen;
673 screen = XDefaultScreen(XtDisplay(_w));
674 currentScreen = XScreenOfDisplay(XtDisplay(_w), screen);
675 rootWindow = RootWindowOfScreen(currentScreen);
677 if (DtWsmGetCurrentWorkspace(
680 &pCurrent) == Success)
681 DtWsmSetWorkspacesOccupied(