10 #include <X11/Xatom.h>
12 typedef struct W_Window
{
16 struct W_Window
*nextPtr
; /* next in the window list */
18 struct W_Window
*owner
;
22 WMPixmap
*miniImage
; /* miniwindow */
27 WMSize resizeIncrement
;
37 WMAction
*closeAction
;
44 unsigned configured
:1;
45 unsigned documentEdited
:1;
54 static void willResizeWindow(W_ViewDelegate
*, WMView
*, unsigned *, unsigned *);
56 struct W_ViewDelegate _WindowViewDelegate
= {
64 #define DEFAULT_WIDTH 400
65 #define DEFAULT_HEIGHT 180
67 static void destroyWindow(_Window
* win
);
69 static void handleEvents(XEvent
* event
, void *clientData
);
71 static void realizeWindow(WMWindow
* win
);
73 static void realizeObserver(void *self
, WMNotification
* not)
75 /* Parameter not used, but tell the compiler that it is ok */
81 WMWindow
*WMCreatePanelWithStyleForWindow(WMWindow
* owner
, const char *name
, int style
)
85 win
= WMCreateWindowWithStyle(owner
->view
->screen
, name
, style
);
91 WMWindow
*WMCreatePanelForWindow(WMWindow
* owner
, const char *name
)
93 return WMCreatePanelWithStyleForWindow(owner
, name
,
94 WMTitledWindowMask
| WMClosableWindowMask
| WMResizableWindowMask
);
97 void WMChangePanelOwner(WMWindow
* win
, WMWindow
* newOwner
)
99 win
->owner
= newOwner
;
101 if (win
->view
->flags
.realized
&& newOwner
) {
102 XSetTransientForHint(win
->view
->screen
->display
, win
->view
->window
, newOwner
->view
->window
);
106 WMWindow
*WMCreateWindow(WMScreen
* screen
, const char *name
)
108 return WMCreateWindowWithStyle(screen
, name
, WMTitledWindowMask
109 | WMClosableWindowMask
110 | WMMiniaturizableWindowMask
| WMResizableWindowMask
);
113 WMWindow
*WMCreateWindowWithStyle(WMScreen
* screen
, const char *name
, int style
)
117 win
= wmalloc(sizeof(_Window
));
118 win
->widgetClass
= WC_Window
;
120 win
->view
= W_CreateTopView(screen
);
125 win
->view
->self
= win
;
127 win
->view
->delegate
= &_WindowViewDelegate
;
129 win
->wname
= wstrdup(name
);
131 /* add to the window list of the screen (application) */
132 win
->nextPtr
= screen
->windowList
;
133 screen
->windowList
= win
;
135 WMCreateEventHandler(win
->view
, ExposureMask
| StructureNotifyMask
136 | ClientMessageMask
| FocusChangeMask
, handleEvents
, win
);
138 W_ResizeView(win
->view
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
140 WMAddNotificationObserver(realizeObserver
, win
, WMViewRealizedNotification
, win
->view
);
142 win
->flags
.style
= style
;
144 win
->level
= WMNormalWindowLevel
;
146 /* kluge. Find a better solution */
147 W_SetFocusOfTopLevel(win
->view
, win
->view
);
152 static void setWindowTitle(WMWindow
* win
, const char *title
)
154 WMScreen
*scr
= win
->view
->screen
;
155 XTextProperty property
;
158 result
= XmbTextListToTextProperty(scr
->display
, (char **)&title
, 1, XStdICCTextStyle
, &property
);
159 if (result
== XNoMemory
|| result
== XLocaleNotSupported
) {
160 wwarning(_("window title conversion error... using STRING encoding"));
161 XStoreName(scr
->display
, win
->view
->window
, title
);
163 XSetWMName(scr
->display
, win
->view
->window
, &property
);
165 XFree(property
.value
);
168 XChangeProperty(scr
->display
, win
->view
->window
,
169 scr
->netwmName
, scr
->utf8String
, 8,
170 PropModeReplace
, (unsigned char *)title
, strlen(title
));
173 static void setMiniwindowTitle(WMWindow
* win
, const char *title
)
175 WMScreen
*scr
= win
->view
->screen
;
176 XTextProperty property
;
179 result
= XmbTextListToTextProperty(scr
->display
, (char **)&title
, 1, XStdICCTextStyle
, &property
);
180 if (result
== XNoMemory
|| result
== XLocaleNotSupported
) {
181 wwarning(_("icon title conversion error... using STRING encoding"));
182 XSetIconName(scr
->display
, win
->view
->window
, title
);
184 XSetWMIconName(scr
->display
, win
->view
->window
, &property
);
186 XFree(property
.value
);
189 XChangeProperty(scr
->display
, win
->view
->window
,
190 scr
->netwmIconName
, scr
->utf8String
, 8,
191 PropModeReplace
, (unsigned char *)title
, strlen(title
));
194 static void setMiniwindow(WMWindow
*win
, RImage
*image
)
196 WMScreen
*scr
= win
->view
->screen
;
204 data
= wmalloc((image
->width
* image
->height
+ 2) * sizeof(long));
207 data
[o
++] = image
->width
;
208 data
[o
++] = image
->height
;
210 for (y
= 0; y
< image
->height
; y
++) {
211 for (x
= 0; x
< image
->width
; x
++) {
213 int offs
= (x
+ y
* image
->width
);
215 if (image
->format
== RRGBFormat
) {
216 pixel
= ((unsigned long) image
->data
[offs
* 3 ]) << 16;
217 pixel
|= ((unsigned long) image
->data
[offs
* 3 + 1]) << 8;
218 pixel
|= ((unsigned long) image
->data
[offs
* 3 + 2]);
220 pixel
= ((unsigned long) image
->data
[offs
* 4 ]) << 16;
221 pixel
|= ((unsigned long) image
->data
[offs
* 4 + 1]) << 8;
222 pixel
|= ((unsigned long) image
->data
[offs
* 4 + 2]);
223 pixel
|= ((unsigned long) image
->data
[offs
* 4 + 3]) << 24;
230 XChangeProperty(scr
->display
, win
->view
->window
, scr
->netwmIcon
,
231 XA_CARDINAL
, 32, PropModeReplace
,
232 (unsigned char *)data
, (image
->width
* image
->height
+ 2));
237 void WMSetWindowTitle(WMWindow
* win
, const char *title
)
239 wassertr(title
!= NULL
);
241 if (win
->title
!= NULL
)
244 win
->title
= wstrdup(title
);
246 if (win
->view
->flags
.realized
) {
247 setWindowTitle(win
, title
);
251 void WMSetWindowCloseAction(WMWindow
* win
, WMAction
* action
, void *clientData
)
256 WMScreen
*scr
= win
->view
->screen
;
258 if (win
->view
->flags
.realized
) {
259 if (action
&& !win
->closeAction
) {
260 if (!XGetWMProtocols(scr
->display
, win
->view
->window
, &atoms
, &count
)) {
263 newAtoms
= wmalloc((count
+ 1) * sizeof(Atom
));
265 memcpy(newAtoms
, atoms
, count
* sizeof(Atom
));
266 newAtoms
[count
++] = scr
->deleteWindowAtom
;
267 XSetWMProtocols(scr
->display
, win
->view
->window
, newAtoms
, count
);
271 } else if (!action
&& win
->closeAction
) {
274 if (XGetWMProtocols(scr
->display
, win
->view
->window
, &atoms
, &count
) && count
> 0) {
275 newAtoms
= wmalloc((count
- 1) * sizeof(Atom
));
277 for (i
= 0; i
< count
; i
++) {
278 if (atoms
[i
] != scr
->deleteWindowAtom
) {
279 newAtoms
[i
] = atoms
[i
];
283 XSetWMProtocols(scr
->display
, win
->view
->window
, newAtoms
, ncount
);
290 win
->closeAction
= action
;
291 win
->closeData
= clientData
;
294 static void willResizeWindow(W_ViewDelegate
* self
, WMView
* view
, unsigned *width
, unsigned *height
)
296 WMWindow
*win
= (WMWindow
*) view
->self
;
298 /* Parameter not used, but tell the compiler that it is ok */
301 if (win
->minSize
.width
> 0 && win
->minSize
.height
> 0) {
302 if (*width
< win
->minSize
.width
)
303 *width
= win
->minSize
.width
;
304 if (*height
< win
->minSize
.height
)
305 *height
= win
->minSize
.height
;
308 if (win
->maxSize
.width
> 0 && win
->maxSize
.height
> 0) {
309 if (*width
> win
->maxSize
.width
)
310 *width
= win
->maxSize
.width
;
311 if (*height
> win
->maxSize
.height
)
312 *height
= win
->maxSize
.height
;
316 static void setSizeHints(WMWindow
* win
)
320 hints
= XAllocSizeHints();
322 wwarning("could not allocate memory for window size hints");
328 if (win
->flags
.setPPos
) {
329 hints
->flags
|= PPosition
;
330 hints
->x
= win
->ppos
.x
;
331 hints
->y
= win
->ppos
.y
;
333 if (win
->flags
.setUPos
) {
334 hints
->flags
|= USPosition
;
335 hints
->x
= win
->upos
.x
;
336 hints
->y
= win
->upos
.y
;
338 if (win
->minSize
.width
> 0 && win
->minSize
.height
> 0) {
339 hints
->flags
|= PMinSize
;
340 hints
->min_width
= win
->minSize
.width
;
341 hints
->min_height
= win
->minSize
.height
;
343 if (win
->maxSize
.width
> 0 && win
->maxSize
.height
> 0) {
344 hints
->flags
|= PMaxSize
;
345 hints
->max_width
= win
->maxSize
.width
;
346 hints
->max_height
= win
->maxSize
.height
;
348 if (win
->baseSize
.width
> 0 && win
->baseSize
.height
> 0) {
349 hints
->flags
|= PBaseSize
;
350 hints
->base_width
= win
->baseSize
.width
;
351 hints
->base_height
= win
->baseSize
.height
;
353 if (win
->resizeIncrement
.width
> 0 && win
->resizeIncrement
.height
> 0) {
354 hints
->flags
|= PResizeInc
;
355 hints
->width_inc
= win
->resizeIncrement
.width
;
356 hints
->height_inc
= win
->resizeIncrement
.height
;
358 if (win
->flags
.setAspect
) {
359 hints
->flags
|= PAspect
;
360 hints
->min_aspect
.x
= win
->minAspect
.x
;
361 hints
->min_aspect
.y
= win
->minAspect
.y
;
362 hints
->max_aspect
.x
= win
->maxAspect
.x
;
363 hints
->max_aspect
.y
= win
->maxAspect
.y
;
367 XSetWMNormalHints(win
->view
->screen
->display
, win
->view
->window
, hints
);
372 static void writeGNUstepWMAttr(WMScreen
* scr
, Window window
, GNUstepWMAttributes
* attr
)
374 unsigned long data
[9];
376 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
377 data
[0] = attr
->flags
;
378 data
[1] = attr
->window_style
;
379 data
[2] = attr
->window_level
;
380 data
[3] = 0; /* reserved */
381 /* The X protocol says XIDs are 32bit */
382 data
[4] = attr
->miniaturize_pixmap
;
383 data
[5] = attr
->close_pixmap
;
384 data
[6] = attr
->miniaturize_mask
;
385 data
[7] = attr
->close_mask
;
386 data
[8] = attr
->extra_flags
;
387 XChangeProperty(scr
->display
, window
, scr
->attribsAtom
, scr
->attribsAtom
,
388 32, PropModeReplace
, (unsigned char *)data
, 9);
391 static void setWindowMakerHints(WMWindow
* win
)
393 GNUstepWMAttributes attribs
;
394 WMScreen
*scr
= WMWidgetScreen(win
);
396 memset(&attribs
, 0, sizeof(GNUstepWMAttributes
));
397 attribs
.flags
= GSWindowStyleAttr
| GSWindowLevelAttr
| GSExtraFlagsAttr
;
398 attribs
.window_style
= win
->flags
.style
;
399 attribs
.window_level
= win
->level
;
400 if (win
->flags
.documentEdited
)
401 attribs
.extra_flags
= GSDocumentEditedFlag
;
403 attribs
.extra_flags
= 0;
405 writeGNUstepWMAttr(scr
, win
->view
->window
, &attribs
);
408 static void realizeWindow(WMWindow
* win
)
411 XClassHint
*classHint
;
412 WMScreen
*scr
= win
->view
->screen
;
416 classHint
= XAllocClassHint();
417 classHint
->res_name
= win
->wname
;
418 classHint
->res_class
= WMGetApplicationName();
419 XSetClassHint(scr
->display
, win
->view
->window
, classHint
);
422 hints
= XAllocWMHints();
424 if (!scr
->aflags
.simpleApplication
) {
425 hints
->flags
|= WindowGroupHint
;
426 hints
->window_group
= scr
->groupLeader
;
428 if (win
->miniImage
) {
429 hints
->flags
|= IconPixmapHint
;
430 hints
->icon_pixmap
= WMGetPixmapXID(win
->miniImage
);
431 hints
->icon_mask
= WMGetPixmapMaskXID(win
->miniImage
);
432 if (hints
->icon_mask
!= None
) {
433 hints
->flags
|= IconMaskHint
;
436 if (hints
->flags
!= 0)
437 XSetWMHints(scr
->display
, win
->view
->window
, hints
);
441 if (win
->closeAction
) {
442 atoms
[count
++] = scr
->deleteWindowAtom
;
446 XSetWMProtocols(scr
->display
, win
->view
->window
, atoms
, count
);
448 if (win
->title
|| win
->miniTitle
)
449 XmbSetWMProperties(scr
->display
, win
->view
->window
, win
->title
,
450 win
->miniTitle
, NULL
, 0, NULL
, NULL
, NULL
);
452 setWindowMakerHints(win
);
457 XSetTransientForHint(scr
->display
, win
->view
->window
, win
->owner
->view
->window
);
461 setWindowTitle(win
, win
->title
);
464 void WMSetWindowAspectRatio(WMWindow
* win
, int minX
, int minY
, int maxX
, int maxY
)
466 win
->flags
.setAspect
= 1;
467 win
->minAspect
.x
= minX
;
468 win
->minAspect
.y
= minY
;
469 win
->maxAspect
.x
= maxX
;
470 win
->maxAspect
.y
= maxY
;
471 if (win
->view
->flags
.realized
)
475 void WMSetWindowInitialPosition(WMWindow
* win
, int x
, int y
)
477 win
->flags
.setPPos
= 1;
480 if (win
->view
->flags
.realized
)
482 WMMoveWidget(win
, x
, y
);
485 void WMSetWindowUserPosition(WMWindow
* win
, int x
, int y
)
487 win
->flags
.setUPos
= 1;
490 if (win
->view
->flags
.realized
)
492 WMMoveWidget(win
, x
, y
);
495 void WMSetWindowMinSize(WMWindow
* win
, unsigned width
, unsigned height
)
497 win
->minSize
.width
= width
;
498 win
->minSize
.height
= height
;
499 if (win
->view
->flags
.realized
)
503 void WMSetWindowMaxSize(WMWindow
* win
, unsigned width
, unsigned height
)
505 win
->maxSize
.width
= width
;
506 win
->maxSize
.height
= height
;
507 if (win
->view
->flags
.realized
)
511 void WMSetWindowBaseSize(WMWindow
* win
, unsigned width
, unsigned height
)
513 /* TODO: validate sizes */
514 win
->baseSize
.width
= width
;
515 win
->baseSize
.height
= height
;
516 if (win
->view
->flags
.realized
)
520 void WMSetWindowResizeIncrements(WMWindow
* win
, unsigned wIncr
, unsigned hIncr
)
522 win
->resizeIncrement
.width
= wIncr
;
523 win
->resizeIncrement
.height
= hIncr
;
524 if (win
->view
->flags
.realized
)
528 void WMSetWindowLevel(WMWindow
* win
, int level
)
531 if (win
->view
->flags
.realized
)
532 setWindowMakerHints(win
);
535 void WMSetWindowDocumentEdited(WMWindow
* win
, Bool flag
)
537 flag
= ((flag
== 0) ? 0 : 1);
538 if (win
->flags
.documentEdited
!= flag
) {
539 win
->flags
.documentEdited
= flag
;
540 if (win
->view
->flags
.realized
)
541 setWindowMakerHints(win
);
545 void WMSetWindowMiniwindowImage(WMWindow
* win
, RImage
* image
)
547 if (win
->view
->flags
.realized
)
548 setMiniwindow(win
, image
);
551 void WMSetWindowMiniwindowPixmap(WMWindow
* win
, WMPixmap
* pixmap
)
553 if ((win
->miniImage
&& !pixmap
) || (!win
->miniImage
&& pixmap
)) {
555 WMReleasePixmap(win
->miniImage
);
558 win
->miniImage
= WMRetainPixmap(pixmap
);
560 win
->miniImage
= NULL
;
562 if (win
->view
->flags
.realized
) {
565 hints
= XGetWMHints(win
->view
->screen
->display
, win
->view
->window
);
567 hints
= XAllocWMHints();
569 wwarning("could not allocate memory for WM hints");
575 hints
->flags
|= IconPixmapHint
;
576 hints
->icon_pixmap
= WMGetPixmapXID(pixmap
);
577 hints
->icon_mask
= WMGetPixmapMaskXID(pixmap
);
578 if (hints
->icon_mask
!= None
) {
579 hints
->flags
|= IconMaskHint
;
582 XSetWMHints(win
->view
->screen
->display
, win
->view
->window
, hints
);
588 void WMSetWindowMiniwindowTitle(WMWindow
* win
, const char *title
)
590 if (win
&& ((win
->miniTitle
&& !title
) || (!win
->miniTitle
&& title
)
591 || (title
&& win
->miniTitle
&& strcoll(title
, win
->miniTitle
) != 0))) {
593 wfree(win
->miniTitle
);
596 win
->miniTitle
= wstrdup(title
);
598 win
->miniTitle
= NULL
;
600 if (win
->view
->flags
.realized
) {
601 setMiniwindowTitle(win
, title
);
606 void WMCloseWindow(WMWindow
* win
)
609 /* withdraw the window */
610 if (win
->view
->flags
.realized
)
611 XWithdrawWindow(win
->view
->screen
->display
, win
->view
->window
, win
->view
->screen
->screen
);
614 static void handleEvents(XEvent
* event
, void *clientData
)
616 _Window
*win
= (_Window
*) clientData
;
617 W_View
*view
= win
->view
;
619 switch (event
->type
) {
621 if (event
->xclient
.message_type
== win
->view
->screen
->protocolsAtom
622 && event
->xclient
.format
== 32
623 && event
->xclient
.data
.l
[0] == win
->view
->screen
->deleteWindowAtom
) {
625 if (win
->closeAction
) {
626 (*win
->closeAction
) (win
, win
->closeData
);
631 * was causing windows to ignore commands like closeWindow
632 * after the windows is iconized/restored or a workspace change
633 * if this is really needed, put the MapNotify portion too and
634 * fix the restack bug in wmaker
648 case ConfigureNotify
:
649 if (event
->xconfigure
.width
!= view
->size
.width
|| event
->xconfigure
.height
!= view
->size
.height
) {
651 view
->size
.width
= event
->xconfigure
.width
;
652 view
->size
.height
= event
->xconfigure
.height
;
654 if (view
->flags
.notifySizeChanged
) {
655 WMPostNotificationName(WMViewSizeDidChangeNotification
, view
, NULL
);
658 if (event
->xconfigure
.x
!= view
->pos
.x
|| event
->xconfigure
.y
!= view
->pos
.y
) {
660 if (event
->xconfigure
.send_event
) {
661 view
->pos
.x
= event
->xconfigure
.x
;
662 view
->pos
.y
= event
->xconfigure
.y
;
666 XTranslateCoordinates(view
->screen
->display
,
667 view
->window
, view
->screen
->rootWin
,
668 event
->xconfigure
.x
, event
->xconfigure
.y
,
669 &view
->pos
.x
, &view
->pos
.y
, &foo
);
676 static void destroyWindow(_Window
* win
)
678 WMScreen
*scr
= win
->view
->screen
;
680 WMRemoveNotificationObserver(win
);
682 if (scr
->windowList
== win
) {
683 scr
->windowList
= scr
->windowList
->nextPtr
;
686 ptr
= scr
->windowList
;
689 while (ptr
->nextPtr
) {
690 if (ptr
->nextPtr
== win
) {
691 ptr
->nextPtr
= ptr
->nextPtr
->nextPtr
;
703 if (win
->miniTitle
) {
704 wfree(win
->miniTitle
);
707 if (win
->miniImage
) {
708 WMReleasePixmap(win
->miniImage
);