- Updated WINGs/NEWS with info about hw the API changed how how things
[wmaker-crm.git] / WINGs / wwindow.c
blobfcfb56a9fbd5fd2a0913acce48b0a792f9c14c43
2 #include <X11/Xmd.h>
4 #include "WINGsP.h"
6 #include <X11/Xatom.h>
9 typedef struct W_Window {
10 W_Class widgetClass;
11 W_View *view;
13 struct W_Window *nextPtr; /* next in the window list */
15 struct W_Window *owner;
17 char *title;
19 WMPixmap *miniImage; /* miniwindow */
20 char *miniTitle;
22 char *wname;
24 WMSize resizeIncrement;
25 WMSize baseSize;
26 WMSize minSize;
27 WMSize maxSize;
28 WMPoint minAspect;
29 WMPoint maxAspect;
31 WMPoint upos;
32 WMPoint ppos;
34 WMAction *closeAction;
35 void *closeData;
37 int level;
39 struct {
40 unsigned style:4;
41 unsigned configured:1;
42 unsigned documentEdited:1;
44 unsigned setUPos:1;
45 unsigned setPPos:1;
46 unsigned setAspect:1;
47 } flags;
48 } _Window;
52 typedef struct {
53 CARD32 flags;
54 CARD32 window_style;
55 CARD32 window_level;
56 CARD32 reserved;
57 Pixmap miniaturize_pixmap; /* pixmap for miniaturize button */
58 Pixmap close_pixmap; /* pixmap for close button */
59 Pixmap miniaturize_mask; /* miniaturize pixmap mask */
60 Pixmap close_mask; /* close pixmap mask */
61 CARD32 extra_flags;
62 } GNUstepWMAttributes;
64 #define GSWindowStyleAttr (1<<0)
65 #define GSWindowLevelAttr (1<<1)
66 #define GSMiniaturizePixmapAttr (1<<3)
67 #define GSClosePixmapAttr (1<<4)
68 #define GSMiniaturizeMaskAttr (1<<5)
69 #define GSCloseMaskAttr (1<<6)
70 #define GSExtraFlagsAttr (1<<7)
72 /* extra flags */
73 #define GSDocumentEditedFlag (1<<0)
74 #define GSNoApplicationIconFlag (1<<5)
76 #define WMFHideOtherApplications 10
77 #define WMFHideApplication 12
81 static void willResizeWindow(W_ViewDelegate *, WMView *, unsigned*, unsigned*);
83 struct W_ViewDelegate _WindowViewDelegate = {
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 willResizeWindow
92 #define DEFAULT_WIDTH 400
93 #define DEFAULT_HEIGHT 180
94 #define DEFAULT_TITLE ""
97 static void destroyWindow(_Window *win);
99 static void handleEvents();
101 static void realizeWindow();
103 static void
104 realizeObserver(void *self, WMNotification *not)
106 realizeWindow(self);
110 WMWindow*
111 WMCreatePanelWithStyleForWindow(WMWindow *owner, char *name, int style)
113 WMWindow *win;
115 win = WMCreateWindowWithStyle(owner->view->screen, name, style);
116 win->owner = owner;
118 return win;
123 WMWindow*
124 WMCreatePanelForWindow(WMWindow *owner, char *name)
126 return WMCreatePanelWithStyleForWindow(owner, name,
127 WMTitledWindowMask
128 |WMClosableWindowMask
129 |WMResizableWindowMask);
133 void
134 WMChangePanelOwner(WMWindow *win, WMWindow *newOwner)
136 win->owner = newOwner;
138 if (win->view->flags.realized && newOwner) {
139 XSetTransientForHint(win->view->screen->display, win->view->window,
140 newOwner->view->window);
146 WMWindow*
147 WMCreateWindow(WMScreen *screen, char *name)
149 return WMCreateWindowWithStyle(screen, name, WMTitledWindowMask
150 |WMClosableWindowMask
151 |WMMiniaturizableWindowMask
152 |WMResizableWindowMask);
157 WMWindow*
158 WMCreateWindowWithStyle(WMScreen *screen, char *name, int style)
160 _Window *win;
162 win = wmalloc(sizeof(_Window));
163 memset(win, 0, sizeof(_Window));
165 win->widgetClass = WC_Window;
167 win->view = W_CreateTopView(screen);
168 if (!win->view) {
169 wfree(win);
170 return NULL;
172 win->view->self = win;
174 win->view->delegate = &_WindowViewDelegate;
176 win->wname = wstrdup(name);
178 /* add to the window list of the screen (application) */
179 win->nextPtr = screen->windowList;
180 screen->windowList = win;
182 WMCreateEventHandler(win->view, ExposureMask|StructureNotifyMask
183 |ClientMessageMask|FocusChangeMask,
184 handleEvents, win);
186 W_ResizeView(win->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
188 WMAddNotificationObserver(realizeObserver, win,
189 WMViewRealizedNotification, win->view);
191 win->flags.style = style;
193 win->level = WMNormalWindowLevel;
195 /* kluge. Find a better solution */
196 W_SetFocusOfTopLevel(win->view, win->view);
198 return win;
202 void
203 WMSetWindowTitle(WMWindow *win, char *title)
205 XTextProperty property;
206 int result;
208 if (win->title!=NULL)
209 wfree(win->title);
210 if (title!=NULL)
211 win->title = wstrdup(title);
212 else
213 win->title = NULL;
215 if (win->view->flags.realized) {
216 result = XmbTextListToTextProperty (win->view->screen->display,
217 &title, 1, XStdICCTextStyle,
218 &property);
219 if (result == XNoMemory || result == XLocaleNotSupported) {
220 wwarning("window title conversion error... using STRING encoding");
221 XStoreName(win->view->screen->display, win->view->window, title);
222 } else {
223 XSetWMName(win->view->screen->display, win->view->window, &property);
224 if (property.value)
225 XFree(property.value);
233 void
234 WMSetWindowCloseAction(WMWindow *win, WMAction *action, void *clientData)
236 Atom *atoms = NULL;
237 Atom *newAtoms;
238 int count;
239 WMScreen *scr = win->view->screen;
241 if (win->view->flags.realized) {
242 if (action && !win->closeAction) {
243 if (!XGetWMProtocols(scr->display, win->view->window, &atoms,
244 &count)) {
245 count = 0;
247 newAtoms = wmalloc((count+1)*sizeof(Atom));
248 if (count > 0)
249 memcpy(newAtoms, atoms, count*sizeof(Atom));
250 newAtoms[count++] = scr->deleteWindowAtom;
251 XSetWMProtocols(scr->display, win->view->window, newAtoms, count);
252 if (atoms)
253 XFree(atoms);
254 wfree(newAtoms);
255 } else if (!action && win->closeAction) {
256 int i, ncount;
258 if (XGetWMProtocols(scr->display, win->view->window, &atoms,
259 &count) && count>0) {
260 newAtoms = wmalloc((count-1)*sizeof(Atom));
261 ncount = 0;
262 for (i=0; i < count; i++) {
263 if (atoms[i]!=scr->deleteWindowAtom) {
264 newAtoms[i] = atoms[i];
265 ncount++;
268 XSetWMProtocols(scr->display, win->view->window, newAtoms,
269 ncount);
270 if (atoms)
271 XFree(atoms);
272 wfree(newAtoms);
276 win->closeAction = action;
277 win->closeData = clientData;
282 static void
283 willResizeWindow(W_ViewDelegate *self, WMView *view,
284 unsigned *width, unsigned *height)
286 WMWindow *win = (WMWindow*)view->self;
288 if (win->minSize.width > 0 && win->minSize.height > 0) {
289 if (*width < win->minSize.width)
290 *width = win->minSize.width;
291 if (*height < win->minSize.height)
292 *height = win->minSize.height;
295 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
296 if (*width > win->maxSize.width)
297 *width = win->maxSize.width;
298 if (*height > win->maxSize.height)
299 *height = win->maxSize.height;
304 static void
305 setSizeHints(WMWindow *win)
307 XSizeHints *hints;
309 hints = XAllocSizeHints();
310 if (!hints) {
311 wwarning("could not allocate memory for window size hints");
312 return;
315 hints->flags = 0;
317 if (win->flags.setPPos) {
318 hints->flags |= PPosition;
319 hints->x = win->ppos.x;
320 hints->y = win->ppos.y;
322 if (win->flags.setUPos) {
323 hints->flags |= USPosition;
324 hints->x = win->upos.x;
325 hints->y = win->upos.y;
327 if (win->minSize.width>0 && win->minSize.height>0) {
328 hints->flags |= PMinSize;
329 hints->min_width = win->minSize.width;
330 hints->min_height = win->minSize.height;
332 if (win->maxSize.width>0 && win->maxSize.height>0) {
333 hints->flags |= PMaxSize;
334 hints->max_width = win->maxSize.width;
335 hints->max_height = win->maxSize.height;
337 if (win->baseSize.width>0 && win->baseSize.height>0) {
338 hints->flags |= PBaseSize;
339 hints->base_width = win->baseSize.width;
340 hints->base_height = win->baseSize.height;
342 if (win->resizeIncrement.width>0 && win->resizeIncrement.height>0) {
343 hints->flags |= PResizeInc;
344 hints->width_inc = win->resizeIncrement.width;
345 hints->height_inc = win->resizeIncrement.height;
347 if (win->flags.setAspect) {
348 hints->flags |= PAspect;
349 hints->min_aspect.x = win->minAspect.x;
350 hints->min_aspect.y = win->minAspect.y;
351 hints->max_aspect.x = win->maxAspect.x;
352 hints->max_aspect.y = win->maxAspect.y;
356 if (hints->flags) {
357 XSetWMNormalHints(win->view->screen->display, win->view->window, hints);
359 XFree(hints);
364 static void
365 writeGNUstepWMAttr(WMScreen *scr, Window window, GNUstepWMAttributes *attr)
367 unsigned long data[9];
369 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
370 data[0] = attr->flags;
371 data[1] = attr->window_style;
372 data[2] = attr->window_level;
373 data[3] = 0; /* reserved */
374 /* The X protocol says XIDs are 32bit */
375 data[4] = attr->miniaturize_pixmap;
376 data[5] = attr->close_pixmap;
377 data[6] = attr->miniaturize_mask;
378 data[7] = attr->close_mask;
379 data[8] = attr->extra_flags;
380 XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
381 32, PropModeReplace, (unsigned char *)data, 9);
385 static void
386 setWindowMakerHints(WMWindow *win)
388 GNUstepWMAttributes attribs;
389 WMScreen *scr = WMWidgetScreen(win);
391 memset(&attribs, 0, sizeof(GNUstepWMAttributes));
392 attribs.flags = GSWindowStyleAttr|GSWindowLevelAttr|GSExtraFlagsAttr;
393 attribs.window_style = win->flags.style;
394 attribs.window_level = win->level;
395 if (win->flags.documentEdited)
396 attribs.extra_flags = GSDocumentEditedFlag;
397 else
398 attribs.extra_flags = 0;
400 writeGNUstepWMAttr(scr, win->view->window, &attribs);
404 static void
405 realizeWindow(WMWindow *win)
407 XWMHints *hints;
408 XClassHint *classHint;
409 WMScreen *scr = win->view->screen;
410 Atom atoms[4];
411 int count;
413 classHint = XAllocClassHint();
414 classHint->res_name = win->wname;
415 classHint->res_class = WMGetApplicationName();
416 XSetClassHint(scr->display, win->view->window, classHint);
417 XFree(classHint);
419 hints = XAllocWMHints();
420 hints->flags = 0;
421 if (!scr->aflags.simpleApplication) {
422 hints->flags |= WindowGroupHint;
423 hints->window_group = scr->groupLeader;
425 if (win->miniImage) {
426 hints->flags |= IconPixmapHint;
427 hints->icon_pixmap = WMGetPixmapXID(win->miniImage);
428 hints->icon_mask = WMGetPixmapMaskXID(win->miniImage);
429 if (hints->icon_mask != None) {
430 hints->flags |= IconMaskHint;
433 if (hints->flags != 0)
434 XSetWMHints(scr->display, win->view->window, hints);
435 XFree(hints);
437 count = 0;
438 if (win->closeAction) {
439 atoms[count++] = scr->deleteWindowAtom;
442 if (count>0)
443 XSetWMProtocols(scr->display, win->view->window, atoms, count);
445 if (win->title || win->miniTitle)
446 XmbSetWMProperties(scr->display, win->view->window, win->title,
447 win->miniTitle, NULL, 0, NULL, NULL, NULL);
449 setWindowMakerHints(win);
451 setSizeHints(win);
453 if (win->owner) {
454 XSetTransientForHint(scr->display, win->view->window,
455 win->owner->view->window);
461 void
462 WMSetWindowAspectRatio(WMWindow *win, int minX, int minY,
463 int maxX, int maxY)
465 win->flags.setAspect = 1;
466 win->minAspect.x = minX;
467 win->minAspect.y = minY;
468 win->maxAspect.x = maxX;
469 win->maxAspect.y = maxY;
470 if (win->view->flags.realized)
471 setSizeHints(win);
476 void
477 WMSetWindowInitialPosition(WMWindow *win, int x, int y)
479 win->flags.setPPos = 1;
480 win->ppos.x = x;
481 win->ppos.y = y;
482 if (win->view->flags.realized)
483 setSizeHints(win);
484 WMMoveWidget(win, x, y);
489 void
490 WMSetWindowUserPosition(WMWindow *win, int x, int y)
492 win->flags.setUPos = 1;
493 win->upos.x = x;
494 win->upos.y = y;
495 if (win->view->flags.realized)
496 setSizeHints(win);
497 WMMoveWidget(win, x, y);
503 void
504 WMSetWindowMinSize(WMWindow *win, unsigned width, unsigned height)
506 win->minSize.width = width;
507 win->minSize.height = height;
508 if (win->view->flags.realized)
509 setSizeHints(win);
514 void
515 WMSetWindowMaxSize(WMWindow *win, unsigned width, unsigned height)
517 win->maxSize.width = width;
518 win->maxSize.height = height;
519 if (win->view->flags.realized)
520 setSizeHints(win);
524 void
525 WMSetWindowBaseSize(WMWindow *win, unsigned width, unsigned height)
527 /* TODO: validate sizes */
528 win->baseSize.width = width;
529 win->baseSize.height = height;
530 if (win->view->flags.realized)
531 setSizeHints(win);
535 void
536 WMSetWindowResizeIncrements(WMWindow *win, unsigned wIncr, unsigned hIncr)
538 win->resizeIncrement.width = wIncr;
539 win->resizeIncrement.height = hIncr;
540 if (win->view->flags.realized)
541 setSizeHints(win);
545 void
546 WMSetWindowLevel(WMWindow *win, int level)
548 win->level = level;
549 if (win->view->flags.realized)
550 setWindowMakerHints(win);
554 void
555 WMSetWindowDocumentEdited(WMWindow *win, Bool flag)
557 flag = ((flag==0) ? 0 : 1);
558 if (win->flags.documentEdited != flag) {
559 win->flags.documentEdited = flag;
560 if (win->view->flags.realized)
561 setWindowMakerHints(win);
566 void
567 WMSetWindowMiniwindowPixmap(WMWindow *win, WMPixmap *pixmap)
569 if ((win->miniImage && !pixmap) || (!win->miniImage && pixmap)) {
570 if (win->miniImage)
571 WMReleasePixmap(win->miniImage);
573 if (pixmap)
574 win->miniImage = WMRetainPixmap(pixmap);
575 else
576 win->miniImage = NULL;
578 if (win->view->flags.realized) {
579 XWMHints *hints;
581 hints = XGetWMHints(win->view->screen->display, win->view->window);
582 if (!hints) {
583 hints = XAllocWMHints();
584 if (!hints) {
585 wwarning("could not allocate memory for WM hints");
586 return;
588 hints->flags = 0;
590 if (pixmap) {
591 hints->flags |= IconPixmapHint;
592 hints->icon_pixmap = WMGetPixmapXID(pixmap);
593 hints->icon_mask = WMGetPixmapMaskXID(pixmap);
594 if (hints->icon_mask != None) {
595 hints->flags |= IconMaskHint;
598 XSetWMHints(win->view->screen->display, win->view->window, hints);
599 XFree(hints);
605 void
606 WMSetWindowMiniwindowTitle(WMWindow *win, char *title)
608 XTextProperty property;
609 int result;
611 if ((win->miniTitle && !title) || (!win->miniTitle && title)
612 || (title && win->miniTitle && strcoll(title, win->miniTitle)!=0)) {
613 if (win->miniTitle)
614 wfree(win->miniTitle);
616 if (title)
617 win->miniTitle = wstrdup(title);
618 else
619 win->miniTitle = NULL;
621 if (win->view->flags.realized) {
622 result = XmbTextListToTextProperty (win->view->screen->display,
623 &title, 1, XStdICCTextStyle,
624 &property);
625 if (result == XNoMemory || result == XLocaleNotSupported) {
626 wwarning("icon title conversion error..using STRING encoding");
627 XSetIconName(win->view->screen->display, win->view->window,
628 title);
629 } else {
630 XSetWMIconName(win->view->screen->display, win->view->window,
631 &property);
632 if (property.value)
633 XFree(property.value);
640 void
641 WMCloseWindow(WMWindow *win)
643 WMUnmapWidget(win);
644 /* withdraw the window */
645 if (win->view->flags.realized)
646 XWithdrawWindow(win->view->screen->display, win->view->window,
647 win->view->screen->screen);
651 static void
652 handleEvents(XEvent *event, void *clientData)
654 _Window *win = (_Window*)clientData;
655 W_View *view = win->view;
658 switch (event->type) {
659 case ClientMessage:
660 if (event->xclient.message_type == win->view->screen->protocolsAtom
661 && event->xclient.format == 32
662 && event->xclient.data.l[0]==win->view->screen->deleteWindowAtom) {
664 if (win->closeAction) {
665 (*win->closeAction)(win, win->closeData);
668 break;
670 * was causing windows to ignore commands like closeWindow
671 * after the windows is iconized/restored or a workspace change
672 * if this is really needed, put the MapNotify portion too and
673 * fix the restack bug in wmaker
674 case UnmapNotify:
675 WMUnmapWidget(win);
676 break;
678 case MapNotify:
679 WMMapWidget(win);
680 break;
683 case DestroyNotify:
684 destroyWindow(win);
685 break;
687 case ConfigureNotify:
688 if (event->xconfigure.width != view->size.width
689 || event->xconfigure.height != view->size.height) {
691 view->size.width = event->xconfigure.width;
692 view->size.height = event->xconfigure.height;
694 if (view->flags.notifySizeChanged) {
695 WMPostNotificationName(WMViewSizeDidChangeNotification,
696 view, NULL);
699 if (event->xconfigure.x != view->pos.x
700 || event->xconfigure.y != view->pos.y) {
702 if (event->xconfigure.send_event) {
703 view->pos.x = event->xconfigure.x;
704 view->pos.y = event->xconfigure.y;
705 } else {
706 Window foo;
708 XTranslateCoordinates(view->screen->display,
709 view->window, view->screen->rootWin,
710 event->xconfigure.x, event->xconfigure.y,
711 &view->pos.x, &view->pos.y, &foo);
714 break;
721 static void
722 destroyWindow(_Window *win)
724 WMScreen *scr = win->view->screen;
726 WMRemoveNotificationObserver(win);
728 if (scr->windowList == win) {
729 scr->windowList = scr->windowList->nextPtr;
730 } else {
731 WMWindow *ptr;
732 ptr = scr->windowList;
734 if (ptr) {
735 while (ptr->nextPtr) {
736 if (ptr->nextPtr==win) {
737 ptr->nextPtr = ptr->nextPtr->nextPtr;
738 break;
740 ptr = ptr->nextPtr;
745 if (win->title) {
746 wfree(win->title);
749 if (win->miniTitle) {
750 wfree(win->miniTitle);
753 if (win->miniImage) {
754 WMReleasePixmap(win->miniImage);
757 if (win->wname)
758 wfree(win->wname);
760 wfree(win);