source: trunk/athena/lib/Xj/Window.c @ 20599

Revision 20599, 17.9 KB checked in by ghudson, 20 years ago (diff)
Add a resource to turn off the input windowmanager hint, so that Jets programs can refuse keyboard focus.
Line 
1/*
2 * $Id: Window.c,v 1.4 2004-08-03 01:19:08 ghudson Exp $
3 *
4 * Copyright 1990, 1991 by the Massachusetts Institute of Technology.
5 *
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 *
9 */
10
11#if  (!defined(lint))  &&  (!defined(SABER))
12static char *rcsid =
13"$Id: Window.c,v 1.4 2004-08-03 01:19:08 ghudson Exp $";
14#endif
15
16#include "mit-copyright.h"
17#include <stdio.h>
18#include "Jets.h"
19#include "Window.h"
20#include <X11/Xutil.h>
21#include <X11/Xatom.h>
22
23static Boolean event_handler();
24static void initialize(), prerealize(), realize(),
25  querysize(), move(), resize(), destroy();
26
27static Boolean got_atoms = 0;
28static Atom wm_delete_window;
29static Atom desks_hints, desks_always_global;
30
31extern int DEBUG;
32
33#define offset(field) XjOffset(WindowJet,field)
34
35static XjResource resources[] = {
36  { XjNx, XjCX, XjRInt, sizeof(int),
37     offset(core.x), XjRString, XjDefaultValue },
38  { XjNy, XjCY, XjRInt, sizeof(int),
39     offset(core.y), XjRString, XjDefaultValue },
40  { XjNwidth, XjCWidth, XjRInt, sizeof(int),
41     offset(core.width), XjRString, XjDefaultValue },
42  { XjNheight, XjCHeight, XjRInt, sizeof(int),
43     offset(core.height), XjRString, XjDefaultValue },
44  { XjNbackground, XjCBackground, XjRColor, sizeof(int),
45      offset(window.background), XjRString, XjDefaultBackground },
46  { XjNforeground, XjCForeground, XjRColor, sizeof(int),
47      offset(window.foreground), XjRString, XjDefaultForeground },
48  { XjNreverseVideo, XjCReverseVideo, XjRBoolean, sizeof(Boolean),
49      offset(window.reverseVideo), XjRBoolean, (caddr_t)False },
50  { XjNbackgroundPixmap, XjCBackgroundPixmap, XjRPixmap, sizeof(XjPixmap *),
51      offset(window.pixmap), XjRString, NULL },
52  { XjNborderColor, XjCBorderColor, XjRColor, sizeof(int),
53      offset(window.borderColor), XjRColor, (caddr_t)-1 },
54  { XjNborderWidth, XjCBorderWidth, XjRInt, sizeof(int),
55     offset(window.borderWidth), XjRString, "1" },
56  { XjNtitle, XjCTitle, XjRString, sizeof(char *),
57     offset(window.title), XjRString, "No name" },
58  { XjNgeometry, XjCGeometry, XjRString, sizeof(char *),
59     offset(window.geometry), XjRString, (char *)NULL },
60  { XjNdefGeometry, XjCGeometry, XjRString, sizeof(char *),
61     offset(window.defGeometry), XjRString, (char *) NULL },
62  { XjNminWidth, XjCMinWidth, XjRInt, sizeof(int),
63     offset(window.minWidth), XjRInt, 0 },
64  { XjNminHeight, XjCMinHeight, XjRInt, sizeof(int),
65     offset(window.minHeight), XjRInt, 0 },
66  { XjNoverrideRedirect, XjCOverrideRedirect, XjRBoolean, sizeof(Boolean),
67     offset(window.overrideRedirect), XjRBoolean, (caddr_t)False },
68  { XjNshowCommand, XjCShowCommand, XjRBoolean, sizeof(Boolean),
69     offset(window.showCommand), XjRBoolean, (caddr_t)True },
70  { XjNglobal, XjCGlobal, XjRBoolean, sizeof(Boolean),
71     offset(window.global), XjRBoolean, (caddr_t)False },
72  { XjNrootTransient, XjCRootTransient, XjRBoolean, sizeof(Boolean),
73     offset(window.rootTransient), XjRBoolean, (caddr_t)False },
74  { XjNcursorCode, XjCCursorCode, XjRInt, sizeof(int),
75     offset(window.cursorCode), XjRInt, (caddr_t) 132 /* top_left_arrow */ },
76  { XjNmapped, XjCMapped, XjRBoolean, sizeof(Boolean),
77     offset(window.mapped), XjRBoolean, (caddr_t)True },
78  { XjNiconic, XjCIconic, XjRBoolean, sizeof(Boolean),
79     offset(window.iconic), XjRBoolean, (caddr_t)False },
80  { XjNinput, XjCInput, XjRBoolean, sizeof(Boolean),
81     offset(window.input), XjRBoolean, (caddr_t)True },
82  { XjNforceNWGravity, XjCForceNWGravity, XjRBoolean, sizeof(Boolean),
83      offset(window.forceNWGravity), XjRBoolean, (caddr_t) False },
84  { XjNdeleteProc, XjCDeleteProc, XjRCallback, sizeof(XjCallback *),
85     offset(window.deleteProc), XjRString, NULL },
86  { XjNclientMessageProc, XjCClientMessageProc, XjRCallback,
87     sizeof(XjCallback *), offset(window.clientMessageProc), XjRString, NULL },
88  { XjNmapNotifyProc, XjCMapNotifyProc, XjRCallback, sizeof(XjCallback *),
89     offset(window.mapNotifyProc), XjRString, NULL },
90  { XjNiconWindow, XjCIconWindow, XjRJet, sizeof(Jet),
91     offset(window.iconWindow), XjRJet, NULL }
92};
93
94#undef offset
95
96WindowClassRec windowClassRec = {
97  {
98    /* class name */            "Window",
99    /* jet size   */            sizeof(WindowRec),
100    /* classInitialize */       NULL,
101    /* classInitialized? */     1,
102    /* initialize */            initialize,
103    /* prerealize */            prerealize,
104    /* realize */               realize,
105    /* event */                 event_handler,
106    /* expose */                NULL,
107    /* querySize */             querysize,
108    /* move */                  move,
109    /* resize */                resize,
110    /* destroy */               destroy,
111    /* resources */             resources,
112    /* number of 'em */         XjNumber(resources)
113  }
114};
115
116JetClass windowJetClass = (JetClass)&windowClassRec;
117
118static void querysize(me, size)
119     WindowJet me;
120     XjSize *size;
121{
122  if (DEBUG)
123    printf ("QS(window) '%s'\n", me->core.name);
124
125  if (me->core.child)
126    XjQuerySize(me->core.child, size);
127}
128
129static void move(me, x, y)
130     WindowJet me;
131     int x, y;
132{
133  if (DEBUG)
134    printf ("MV(window) '%s' x=%d,y=%d\n", me->core.name, x, y);
135
136  me->core.x = x;
137  me->core.y = y;
138
139  XMoveWindow(me->core.display, me->core.window, x, y
140              /*me->core.x, me->core.y*/);
141}
142
143static void resize(me, size)
144     WindowJet me;
145     XjSize *size;
146{
147  Jet child;
148
149  if (DEBUG)
150    printf ("RS(window) '%s' w=%d,h=%d\n", me->core.name,
151            size->width, size->height);
152
153  me->core.width = (size->width) ? size->width : 1;
154  me->core.height = (size->height) ? size->height : 1;
155
156  /* child should be informed by getting a ConfigureNotify */
157  XResizeWindow(me->core.display, me->core.window,
158                me->core.width, me->core.height);
159
160  for (child = me->core.child; child != NULL; child = child->core.sibling)
161    XjResize(child, size);
162}
163
164static void initialize(me)
165     WindowJet me;
166{
167  if (!got_atoms)
168    {
169      got_atoms = True;
170      wm_delete_window = XInternAtom(me->core.display,
171                                     "WM_DELETE_WINDOW",
172                                     False);
173
174      desks_hints = XInternAtom(me->core.display,
175                                "_SGI_DESKS_HINTS",
176                                False);
177
178      desks_always_global = XInternAtom(me->core.display,
179                                        "_SGI_DESKS_ALWAYS_GLOBAL",
180                                        False);
181    }
182}
183
184static void prerealize(me)
185     WindowJet me;
186{
187  XjSize size;
188  char defString[30];
189  int mask;
190  int ret_x, ret_y, ret_width, ret_height, ret_gravity;
191
192  /*
193   * Geometry... this is gross, but you've gotta do what you've gotta do...
194   */
195  me->core.borderWidth = me->window.borderWidth;
196
197  if (me->core.x != -1)
198    me->window.sizeHints.x = me->core.x;
199  else
200    me->window.sizeHints.x = 0;
201
202  if (me->core.y != -1)
203    me->window.sizeHints.y = me->core.y;
204  else
205    me->window.sizeHints.y = 0;
206
207  if (me->core.child != NULL)
208    XjQuerySize(me->core.child, &size);
209
210  if (me->core.width != -1)
211    me->window.sizeHints.width = me->core.width;
212  else
213    if (size.width != -1)
214      me->window.sizeHints.width = size.width;
215    else
216      me->window.sizeHints.width = 100;
217
218  if (me->core.height != -1)
219    me->window.sizeHints.height = me->core.height;
220  else
221    if (size.height != -1)
222      me->window.sizeHints.height = size.height;
223    else
224      me->window.sizeHints.height = 100;
225
226  me->window.sizeHints.flags = PPosition | PSize;
227
228#ifdef notdef
229  if (me->window.geometry != NULL  ||  me->window.defGeometry )
230    {
231#endif
232      /* I think this call is screwed - as far as I can tell, it
233         ignores sizeHints.{width,height} */
234      /* so... */
235      if (me->window.defGeometry != NULL  &&
236          strcmp(me->window.defGeometry, ""))
237        mask = XWMGeometry(me->core.display,
238                           DefaultScreen(me->core.display),
239                           me->window.geometry,
240                           me->window.defGeometry,
241                           me->window.borderWidth,
242                           &me->window.sizeHints,
243                           &ret_x, &ret_y,
244                           &ret_width, &ret_height,
245                           &ret_gravity);
246      else
247        {
248          sprintf(defString, "%dx%d+%d+%d",
249                  me->window.sizeHints.width,
250                  me->window.sizeHints.height,
251                  me->window.sizeHints.x,
252                  me->window.sizeHints.y);
253
254          mask = XWMGeometry(me->core.display,
255                             DefaultScreen(me->core.display),
256                             me->window.geometry,
257                             defString,
258                             me->window.borderWidth,
259                             &me->window.sizeHints,
260                             &ret_x, &ret_y,
261                             &ret_width, &ret_height,
262                             &ret_gravity);
263        }
264
265      if (mask & (XValue | YValue))
266        me->window.sizeHints.flags |= USPosition;
267
268      if (mask & (WidthValue | HeightValue))
269        me->window.sizeHints.flags |= USSize;
270
271      me->window.sizeHints.x = ret_x;
272      me->window.sizeHints.y = ret_y;
273
274/*      if (ret_width != 1) *//* this is not the right way, but I can't */
275        me->window.sizeHints.width = ret_width;
276/*      if (ret_height != 1) *//* figure the right way from the docs */
277        me->window.sizeHints.height = ret_height;
278#ifdef notdef
279    }
280#endif
281
282  me->core.x = me->window.sizeHints.x;
283  me->core.y = me->window.sizeHints.y;
284  me->core.width = me->window.sizeHints.width;
285  if(me->core.width <= 0)
286    me->core.width = 32;
287  me->core.height = me->window.sizeHints.height;
288  if (me->core.height <= 0)
289    me->core.height = 32;
290
291  me->window.sizeHints.min_width = me->window.minWidth;
292  me->window.sizeHints.min_height = me->window.minHeight;
293  me->window.sizeHints.win_gravity = (me->window.forceNWGravity
294                                      ? NorthWestGravity
295                                      : ret_gravity);
296  me->window.sizeHints.flags |= PWinGravity | PMinSize;
297}
298
299static void realize(me)
300     WindowJet me;
301{
302  Window parentwindow;
303  Pixmap p = (Pixmap) NULL;
304  unsigned long valuemask;
305  XGCValues values;
306  GC gc;
307/*  int background; */
308  int attribsMask;
309  XTextProperty name;
310  XWMHints wmHints;
311  XClassHint classHints;
312  XSetWindowAttributes attribs;
313  XjSize size;
314  int temp;
315
316/*  background = me->window.background; */
317  parentwindow = me->core.window;
318
319  if (me->window.reverseVideo)
320    {
321      temp = me->window.foreground;
322      me->window.foreground = me->window.background;
323      me->window.background = temp;
324    }
325
326  /*
327   * Title...
328   */
329  name.encoding = XA_STRING;
330  name.format = 8;
331  name.value = (unsigned char *) me->window.title;
332  name.nitems = strlen(me->window.title);
333
334  /*
335   * WM hints
336   */
337  wmHints.flags = InputHint | StateHint;
338  wmHints.input = me->window.input;
339  if (me->window.iconic)
340    wmHints.initial_state = IconicState;
341  else
342    wmHints.initial_state = (me->window.mapped == 1) ?
343      NormalState : WithdrawnState;
344
345  if (me->window.iconWindow != NULL)
346    {
347      wmHints.flags |= IconWindowHint;
348      wmHints.icon_window = me->window.iconWindow->core.window;
349
350      if (((WindowJet)me->window.iconWindow)->
351          window.sizeHints.flags & USPosition)
352        {
353          wmHints.flags |= IconPositionHint;
354          wmHints.icon_x = me->window.iconWindow->core.x;
355          wmHints.icon_y = me->window.iconWindow->core.y;
356        }
357    }
358
359  /*
360   * Class hints
361   */
362  classHints.res_name = programName;
363  classHints.res_class = programClass;
364
365  /*
366   * Attributes
367   */
368  attribsMask = CWOverrideRedirect;
369  attribs.override_redirect = me->window.overrideRedirect;
370
371  attribs.background_pixel = me->window.background;
372  attribsMask |= CWBackPixel;
373
374  attribs.border_pixel = (me->window.borderColor == -1) ?
375    me->window.foreground : me->window.borderColor;
376  attribsMask |= CWBorderPixel;
377
378  if (me->window.pixmap != NULL)
379    { /* this is a mighty annoying pain in the rear */
380      values.function = GXcopy;
381      values.foreground = me->window.foreground;
382      values.background = me->window.background;
383      values.graphics_exposures = False;
384      valuemask = ( GCForeground | GCBackground | GCFunction
385                   | GCGraphicsExposures );
386
387      gc = XjCreateGC(me->core.display,
388                      me->core.window,
389                      valuemask,
390                      &values);
391
392      p = XjCreatePixmap(me->core.display,
393                         parentwindow,
394                         me->window.pixmap->width,
395                         me->window.pixmap->height,
396                         DefaultDepth(me->core.display, /* wrong... sigh. */
397                                      DefaultScreen(me->core.display)));
398
399      XCopyPlane(me->core.display,
400                 me->window.pixmap->pixmap,
401                 p,
402                 gc,
403                 0, 0,
404                 me->window.pixmap->width,
405                 me->window.pixmap->height,
406                 0, 0, 1);
407
408      XjFreeGC(me->core.display, gc);
409
410      attribs.background_pixmap = p;
411      attribsMask |= CWBackPixmap;
412      attribsMask &= ~CWBackPixel;
413    }
414
415  me->core.window = XCreateWindow(me->core.display,
416                                  parentwindow,
417                                  me->core.x, me->core.y,
418                                  me->core.width,
419                                  me->core.height,
420                                  me->window.borderWidth,
421                                  CopyFromParent,
422                                  InputOutput,
423                                  CopyFromParent,
424                                  attribsMask,
425                                  &attribs);
426
427  if (me->window.pixmap != NULL)
428    XjFreePixmap(me->core.display, p);
429
430  XSetWMProperties(me->core.display,
431                   me->core.window,
432                   &name, &name,
433                   me->window.showCommand ? global_argv : NULL, global_argc,
434                   &me->window.sizeHints,
435                   &wmHints,
436                   &classHints);
437
438  if (me->window.rootTransient)
439    XSetTransientForHint(me->core.display,
440                         me->core.window,
441                         DefaultRootWindow(me->core.display));
442 
443  (void)XSetWMProtocols(me->core.display,
444                        me->core.window,
445                        &wm_delete_window,
446                        1);
447
448  if (me->window.global)
449    (void)XChangeProperty(me->core.display, me->core.window,
450                          desks_hints, XA_ATOM, 32, PropModeAppend,
451                          (const unsigned char *)&desks_always_global, 1);
452
453  XjRegisterWindow(me->core.window, (Jet) me);
454  XjSelectInput(me->core.display, me->core.window,
455                ExposureMask | StructureNotifyMask | VisibilityChangeMask);
456  if (me->window.mapped || me->window.iconic) /*trust this to be true?*/
457    XMapWindow(me->core.display, me->core.window);
458
459  if (me->window.cursorCode != -1)
460    {
461      me->window.cursor = XjCreateFontCursor(me->core.display,
462                                             me->window.cursorCode);
463      XDefineCursor(me->core.display, me->core.window, me->window.cursor);
464    }
465  else
466    me->window.cursor = (Cursor) NULL;
467
468  if (me->core.child != NULL)
469    {
470      if (me->core.child->core.x == -1)
471        XjMove(me->core.child, 0, 0);
472
473      size.width = me->core.width;
474      size.height = me->core.height;
475      XjResize(me->core.child, &size);
476    }
477
478  me->window.visibility = VisibilityFullyObscured;
479}
480
481static void destroy(me)
482     WindowJet me;
483{
484  XjUnregisterWindow(me->core.window, (Jet) me);
485  XDestroyWindow(me->core.display, me->core.window);
486
487  if (me->window.cursor != (Cursor) NULL)
488    XjFreeCursor(me->core.display, me->window.cursor);
489}
490
491#define X1  event->xexpose.x
492#define Y1  event->xexpose.y
493#define X2  event->xexpose.x + event->xexpose.width
494#define Y2  event->xexpose.y + event->xexpose.height
495#define X3  child->core.x
496#define Y3  child->core.y
497#define X4  child->core.x + child->core.width
498#define Y4  child->core.y + child->core.height
499#define OVERLAP(x1,y1,x2,y2, x3,y3,x4,y4) \
500  ( (MAX(x1,x3) <= MIN(x2,x4)) && (MAX(y1,y3) <= MIN(y2,y4)) )
501
502static Boolean event_handler(me, event)
503     WindowJet me;
504     XEvent *event;
505{
506  WindowInfo info;
507  Jet child;
508
509  switch(event->type)
510    {
511    case GraphicsExpose:
512    case Expose:
513      for (child = me->core.child; child != (Jet) NULL;
514           child = child->core.sibling)
515        {
516          if (!child->core.need_expose
517              && child->core.classRec->core_class.expose != NULL
518              && OVERLAP(X1,Y1,X2,Y2, X3,Y3,X4,Y4))
519            {
520              child->core.need_expose = True;
521            }
522        }
523
524      if (!event->xexpose.count)
525        {
526          for (child = me->core.child; child != (Jet) NULL;
527               child = child->core.sibling)
528            if (child->core.need_expose)
529              {
530                XjExpose(child, event);
531                child->core.need_expose = False;
532              }
533#ifdef notdefined
534            if (child->core.need_expose
535                && child->core.classRec->core_class.expose != NULL)
536              {
537                child->core.classRec->core_class.expose(child, event);
538                child->core.need_expose = False;
539              }
540#endif
541        }
542      break;
543
544    case MapNotify:
545      me->window.mapped = True;
546      XjCallCallbacks((caddr_t) me,
547                      me->window.mapNotifyProc,
548                      (caddr_t) event);
549      break;
550
551    case UnmapNotify:
552      me->window.mapped = False;
553      break;
554
555    case VisibilityNotify:
556      me->window.visibility = event->xvisibility.state;
557      break;
558
559    case ConfigureNotify:
560      me->core.x = event->xconfigure.x;
561      me->core.y = event->xconfigure.y;
562      if (event->xconfigure.width != me->core.width ||
563          event->xconfigure.height != me->core.height)
564        {
565          XjSize size;
566          Jet child;
567
568          me->core.width = (event->xconfigure.width
569                            ? event->xconfigure.width : 1);
570          me->core.height = (event->xconfigure.height
571                             ? event->xconfigure.height : 1);
572
573          size.width = event->xconfigure.width;
574          size.height = event->xconfigure.height;
575          for (child = me->core.child; child != NULL;
576               child = child->core.sibling)
577            XjResize(child, &size);
578
579          /*XjResize((Jet) me, &size);*/
580        }
581      break;
582
583    case ClientMessage:
584      if (event->xclient.data.l[0] == wm_delete_window)
585        {
586          XjCallCallbacks((caddr_t) me,
587                          me->window.deleteProc,
588                          (caddr_t) event);
589          break;
590        }
591      else
592        {
593          info.window = me;
594          info.event = event;
595          XjCallCallbacks((caddr_t) &info,
596                          me->window.clientMessageProc,
597                          (caddr_t) event);
598        }
599      break;
600
601    default:
602      return False;
603    }
604  return True;
605}
606
607void UnmapWindow(me)
608     WindowJet me;
609{
610  XEvent event;
611
612  XUnmapWindow(me->core.display, me->core.window);
613
614  event.type = UnmapNotify;
615  event.xunmap.event = DefaultRootWindow(me->core.display);
616  event.xunmap.window = me->core.window;
617  event.xunmap.from_configure = False;
618
619  if (!XSendEvent(me->core.display,
620                  DefaultRootWindow(me->core.display),
621                  False,
622                  SubstructureRedirectMask | SubstructureNotifyMask,
623                  &event))
624    XjWarning("window: SendEvent failed");
625}
626
627void MapWindow(me, raise)
628     WindowJet me;
629     Boolean raise;
630{
631  XWMHints wmHints;
632
633  /* check for iconic and don't bother if so */
634  wmHints.flags = InputHint | StateHint;
635  wmHints.input = me->window.input;
636  wmHints.initial_state = NormalState;
637
638  if (me->window.iconWindow != NULL)
639    {
640      wmHints.flags |= IconWindowHint;
641      wmHints.icon_window = me->window.iconWindow->core.window;
642      if (((WindowJet)me->window.iconWindow)->
643          window.sizeHints.flags & USPosition)
644        {
645          wmHints.flags |= IconPositionHint;
646          wmHints.icon_x = me->window.iconWindow->core.x;
647          wmHints.icon_y = me->window.iconWindow->core.y;
648        }
649    }
650
651  XSetWMHints(me->core.display, me->core.window, &wmHints);
652
653  if (!raise)
654    XMapWindow(me->core.display, me->core.window);
655  else
656    XMapRaised(me->core.display, me->core.window);
657}
658
659Boolean WindowMapped(me)
660     WindowJet me;
661{
662  return (Boolean)me->window.mapped;
663}
664
665int WindowVisibility(me)
666     WindowJet me;
667{
668  return me->window.visibility;
669}
Note: See TracBrowser for help on using the repository browser.