Small fix for wmaker nightly build script
[wmaker-crm.git] / WINGs / wwindow.c
blob565b3924bba5cdcbfd497a0d110dcb20c3f31451
2 #include <X11/Xmd.h>
4 #include "WINGsP.h"
6 #include <X11/Xatom.h>
8 typedef struct W_Window {
9 W_Class widgetClass;
10 W_View *view;
12 struct W_Window *nextPtr; /* next in the window list */
14 struct W_Window *owner;
16 char *title;
18 WMPixmap *miniImage; /* miniwindow */
19 char *miniTitle;
21 char *wname;
23 WMSize resizeIncrement;
24 WMSize baseSize;
25 WMSize minSize;
26 WMSize maxSize;
27 WMPoint minAspect;
28 WMPoint maxAspect;
30 WMPoint upos;
31 WMPoint ppos;
33 WMAction *closeAction;
34 void *closeData;
36 int level;
38 struct {
39 unsigned style:4;
40 unsigned configured:1;
41 unsigned documentEdited:1;
43 unsigned setUPos:1;
44 unsigned setPPos:1;
45 unsigned setAspect:1;
46 } flags;
47 } _Window;
49 typedef struct {
50 CARD32 flags;
51 CARD32 window_style;
52 CARD32 window_level;
53 CARD32 reserved;
54 Pixmap miniaturize_pixmap; /* pixmap for miniaturize button */
55 Pixmap close_pixmap; /* pixmap for close button */
56 Pixmap miniaturize_mask; /* miniaturize pixmap mask */
57 Pixmap close_mask; /* close pixmap mask */
58 CARD32 extra_flags;
59 } GNUstepWMAttributes;
61 #define GSWindowStyleAttr (1<<0)
62 #define GSWindowLevelAttr (1<<1)
63 #define GSMiniaturizePixmapAttr (1<<3)
64 #define GSClosePixmapAttr (1<<4)
65 #define GSMiniaturizeMaskAttr (1<<5)
66 #define GSCloseMaskAttr (1<<6)
67 #define GSExtraFlagsAttr (1<<7)
69 /* extra flags */
70 #define GSDocumentEditedFlag (1<<0)
71 #define GSNoApplicationIconFlag (1<<5)
73 #define WMFHideOtherApplications 10
74 #define WMFHideApplication 12
76 static void willResizeWindow(W_ViewDelegate *, WMView *, unsigned *, unsigned *);
78 struct W_ViewDelegate _WindowViewDelegate = {
79 NULL,
80 NULL,
81 NULL,
82 NULL,
83 willResizeWindow
86 #define DEFAULT_WIDTH 400
87 #define DEFAULT_HEIGHT 180
88 #define DEFAULT_TITLE ""
90 static void destroyWindow(_Window * win);
92 static void handleEvents();
94 static void realizeWindow();
96 static void realizeObserver(void *self, WMNotification * not)
98 realizeWindow(self);
101 WMWindow *WMCreatePanelWithStyleForWindow(WMWindow * owner, char *name, int style)
103 WMWindow *win;
105 win = WMCreateWindowWithStyle(owner->view->screen, name, style);
106 win->owner = owner;
108 return win;
111 WMWindow *WMCreatePanelForWindow(WMWindow * owner, char *name)
113 return WMCreatePanelWithStyleForWindow(owner, name,
114 WMTitledWindowMask | WMClosableWindowMask | WMResizableWindowMask);
117 void WMChangePanelOwner(WMWindow * win, WMWindow * newOwner)
119 win->owner = newOwner;
121 if (win->view->flags.realized && newOwner) {
122 XSetTransientForHint(win->view->screen->display, win->view->window, newOwner->view->window);
126 WMWindow *WMCreateWindow(WMScreen * screen, char *name)
128 return WMCreateWindowWithStyle(screen, name, WMTitledWindowMask
129 | WMClosableWindowMask
130 | WMMiniaturizableWindowMask | WMResizableWindowMask);
133 WMWindow *WMCreateWindowWithStyle(WMScreen * screen, char *name, int style)
135 _Window *win;
137 win = wmalloc(sizeof(_Window));
138 memset(win, 0, sizeof(_Window));
140 win->widgetClass = WC_Window;
142 win->view = W_CreateTopView(screen);
143 if (!win->view) {
144 wfree(win);
145 return NULL;
147 win->view->self = win;
149 win->view->delegate = &_WindowViewDelegate;
151 win->wname = wstrdup(name);
153 /* add to the window list of the screen (application) */
154 win->nextPtr = screen->windowList;
155 screen->windowList = win;
157 WMCreateEventHandler(win->view, ExposureMask | StructureNotifyMask
158 | ClientMessageMask | FocusChangeMask, handleEvents, win);
160 W_ResizeView(win->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
162 WMAddNotificationObserver(realizeObserver, win, WMViewRealizedNotification, win->view);
164 win->flags.style = style;
166 win->level = WMNormalWindowLevel;
168 /* kluge. Find a better solution */
169 W_SetFocusOfTopLevel(win->view, win->view);
171 return win;
174 static void setWindowTitle(WMWindow * win, const char *title)
176 WMScreen *scr = win->view->screen;
177 XTextProperty property;
178 int result;
180 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
181 if (result == XNoMemory || result == XLocaleNotSupported) {
182 wwarning("window title conversion error... using STRING encoding");
183 XStoreName(scr->display, win->view->window, title);
184 } else {
185 XSetWMName(scr->display, win->view->window, &property);
186 if (property.value)
187 XFree(property.value);
190 XChangeProperty(scr->display, win->view->window,
191 scr->netwmName, scr->utf8String, 8,
192 PropModeReplace, (unsigned char *)title, strlen(title));
195 static void setMiniwindowTitle(WMWindow * win, const char *title)
197 WMScreen *scr = win->view->screen;
198 XTextProperty property;
199 int result;
201 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
202 if (result == XNoMemory || result == XLocaleNotSupported) {
203 wwarning("icon title conversion error..using STRING encoding");
204 XSetIconName(scr->display, win->view->window, title);
205 } else {
206 XSetWMIconName(scr->display, win->view->window, &property);
207 if (property.value)
208 XFree(property.value);
211 XChangeProperty(scr->display, win->view->window,
212 scr->netwmIconName, scr->utf8String, 8,
213 PropModeReplace, (unsigned char *)title, strlen(title));
216 static void setMiniwindow(WMWindow *win, RImage *image)
218 WMScreen *scr = win->view->screen;
219 long *data;
220 int x, y;
221 int o;
223 if (!image)
224 return;
226 data = wmalloc((image->width * image->height + 2) * sizeof(long));
228 o = 0;
229 data[o++] = image->width;
230 data[o++] = image->height;
232 for (y = 0; y < image->height; y++) {
233 for (x = 0; x < image->width; x++) {
234 long pixel;
235 int offs = (x + y * image->width);
237 if (image->format == RRGBFormat)
238 pixel = image->data[offs * 3] << 16 | image->data[offs * 3 + 1] << 8
239 | image->data[offs * 3 + 2];
240 else
241 pixel = image->data[offs * 4] << 16 | image->data[offs * 4 + 1] << 8
242 | image->data[offs * 4 + 2] | image->data[offs * 4 + 3] << 24;
244 data[o++] = pixel;
248 XChangeProperty(scr->display, win->view->window, scr->netwmIcon,
249 XA_CARDINAL, 32, PropModeReplace,
250 (unsigned char *)data, (image->width * image->height + 2));
252 wfree(data);
255 void WMSetWindowTitle(WMWindow * win, char *title)
257 if (win->title != NULL)
258 wfree(win->title);
259 if (title != NULL)
260 win->title = wstrdup(title);
261 else
262 win->title = NULL;
264 if (win->view->flags.realized) {
265 setWindowTitle(win, title);
269 void WMSetWindowCloseAction(WMWindow * win, WMAction * action, void *clientData)
271 Atom *atoms = NULL;
272 Atom *newAtoms;
273 int count;
274 WMScreen *scr = win->view->screen;
276 if (win->view->flags.realized) {
277 if (action && !win->closeAction) {
278 if (!XGetWMProtocols(scr->display, win->view->window, &atoms, &count)) {
279 count = 0;
281 newAtoms = wmalloc((count + 1) * sizeof(Atom));
282 if (count > 0)
283 memcpy(newAtoms, atoms, count * sizeof(Atom));
284 newAtoms[count++] = scr->deleteWindowAtom;
285 XSetWMProtocols(scr->display, win->view->window, newAtoms, count);
286 if (atoms)
287 XFree(atoms);
288 wfree(newAtoms);
289 } else if (!action && win->closeAction) {
290 int i, ncount;
292 if (XGetWMProtocols(scr->display, win->view->window, &atoms, &count) && count > 0) {
293 newAtoms = wmalloc((count - 1) * sizeof(Atom));
294 ncount = 0;
295 for (i = 0; i < count; i++) {
296 if (atoms[i] != scr->deleteWindowAtom) {
297 newAtoms[i] = atoms[i];
298 ncount++;
301 XSetWMProtocols(scr->display, win->view->window, newAtoms, ncount);
302 if (atoms)
303 XFree(atoms);
304 wfree(newAtoms);
308 win->closeAction = action;
309 win->closeData = clientData;
312 static void willResizeWindow(W_ViewDelegate * self, WMView * view, unsigned *width, unsigned *height)
314 WMWindow *win = (WMWindow *) view->self;
316 if (win->minSize.width > 0 && win->minSize.height > 0) {
317 if (*width < win->minSize.width)
318 *width = win->minSize.width;
319 if (*height < win->minSize.height)
320 *height = win->minSize.height;
323 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
324 if (*width > win->maxSize.width)
325 *width = win->maxSize.width;
326 if (*height > win->maxSize.height)
327 *height = win->maxSize.height;
331 static void setSizeHints(WMWindow * win)
333 XSizeHints *hints;
335 hints = XAllocSizeHints();
336 if (!hints) {
337 wwarning("could not allocate memory for window size hints");
338 return;
341 hints->flags = 0;
343 if (win->flags.setPPos) {
344 hints->flags |= PPosition;
345 hints->x = win->ppos.x;
346 hints->y = win->ppos.y;
348 if (win->flags.setUPos) {
349 hints->flags |= USPosition;
350 hints->x = win->upos.x;
351 hints->y = win->upos.y;
353 if (win->minSize.width > 0 && win->minSize.height > 0) {
354 hints->flags |= PMinSize;
355 hints->min_width = win->minSize.width;
356 hints->min_height = win->minSize.height;
358 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
359 hints->flags |= PMaxSize;
360 hints->max_width = win->maxSize.width;
361 hints->max_height = win->maxSize.height;
363 if (win->baseSize.width > 0 && win->baseSize.height > 0) {
364 hints->flags |= PBaseSize;
365 hints->base_width = win->baseSize.width;
366 hints->base_height = win->baseSize.height;
368 if (win->resizeIncrement.width > 0 && win->resizeIncrement.height > 0) {
369 hints->flags |= PResizeInc;
370 hints->width_inc = win->resizeIncrement.width;
371 hints->height_inc = win->resizeIncrement.height;
373 if (win->flags.setAspect) {
374 hints->flags |= PAspect;
375 hints->min_aspect.x = win->minAspect.x;
376 hints->min_aspect.y = win->minAspect.y;
377 hints->max_aspect.x = win->maxAspect.x;
378 hints->max_aspect.y = win->maxAspect.y;
381 if (hints->flags) {
382 XSetWMNormalHints(win->view->screen->display, win->view->window, hints);
384 XFree(hints);
387 static void writeGNUstepWMAttr(WMScreen * scr, Window window, GNUstepWMAttributes * attr)
389 unsigned long data[9];
391 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
392 data[0] = attr->flags;
393 data[1] = attr->window_style;
394 data[2] = attr->window_level;
395 data[3] = 0; /* reserved */
396 /* The X protocol says XIDs are 32bit */
397 data[4] = attr->miniaturize_pixmap;
398 data[5] = attr->close_pixmap;
399 data[6] = attr->miniaturize_mask;
400 data[7] = attr->close_mask;
401 data[8] = attr->extra_flags;
402 XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
403 32, PropModeReplace, (unsigned char *)data, 9);
406 static void setWindowMakerHints(WMWindow * win)
408 GNUstepWMAttributes attribs;
409 WMScreen *scr = WMWidgetScreen(win);
411 memset(&attribs, 0, sizeof(GNUstepWMAttributes));
412 attribs.flags = GSWindowStyleAttr | GSWindowLevelAttr | GSExtraFlagsAttr;
413 attribs.window_style = win->flags.style;
414 attribs.window_level = win->level;
415 if (win->flags.documentEdited)
416 attribs.extra_flags = GSDocumentEditedFlag;
417 else
418 attribs.extra_flags = 0;
420 writeGNUstepWMAttr(scr, win->view->window, &attribs);
423 static void realizeWindow(WMWindow * win)
425 XWMHints *hints;
426 XClassHint *classHint;
427 WMScreen *scr = win->view->screen;
428 Atom atoms[4];
429 int count;
431 classHint = XAllocClassHint();
432 classHint->res_name = win->wname;
433 classHint->res_class = WMGetApplicationName();
434 XSetClassHint(scr->display, win->view->window, classHint);
435 XFree(classHint);
437 hints = XAllocWMHints();
438 hints->flags = 0;
439 if (!scr->aflags.simpleApplication) {
440 hints->flags |= WindowGroupHint;
441 hints->window_group = scr->groupLeader;
443 if (win->miniImage) {
444 hints->flags |= IconPixmapHint;
445 hints->icon_pixmap = WMGetPixmapXID(win->miniImage);
446 hints->icon_mask = WMGetPixmapMaskXID(win->miniImage);
447 if (hints->icon_mask != None) {
448 hints->flags |= IconMaskHint;
451 if (hints->flags != 0)
452 XSetWMHints(scr->display, win->view->window, hints);
453 XFree(hints);
455 count = 0;
456 if (win->closeAction) {
457 atoms[count++] = scr->deleteWindowAtom;
460 if (count > 0)
461 XSetWMProtocols(scr->display, win->view->window, atoms, count);
463 if (win->title || win->miniTitle)
464 XmbSetWMProperties(scr->display, win->view->window, win->title,
465 win->miniTitle, NULL, 0, NULL, NULL, NULL);
467 setWindowMakerHints(win);
469 setSizeHints(win);
471 if (win->owner) {
472 XSetTransientForHint(scr->display, win->view->window, win->owner->view->window);
475 if (win->title)
476 setWindowTitle(win, win->title);
479 void WMSetWindowAspectRatio(WMWindow * win, int minX, int minY, int maxX, int maxY)
481 win->flags.setAspect = 1;
482 win->minAspect.x = minX;
483 win->minAspect.y = minY;
484 win->maxAspect.x = maxX;
485 win->maxAspect.y = maxY;
486 if (win->view->flags.realized)
487 setSizeHints(win);
490 void WMSetWindowInitialPosition(WMWindow * win, int x, int y)
492 win->flags.setPPos = 1;
493 win->ppos.x = x;
494 win->ppos.y = y;
495 if (win->view->flags.realized)
496 setSizeHints(win);
497 WMMoveWidget(win, x, y);
500 void WMSetWindowUserPosition(WMWindow * win, int x, int y)
502 win->flags.setUPos = 1;
503 win->upos.x = x;
504 win->upos.y = y;
505 if (win->view->flags.realized)
506 setSizeHints(win);
507 WMMoveWidget(win, x, y);
510 void WMSetWindowMinSize(WMWindow * win, unsigned width, unsigned height)
512 win->minSize.width = width;
513 win->minSize.height = height;
514 if (win->view->flags.realized)
515 setSizeHints(win);
518 void WMSetWindowMaxSize(WMWindow * win, unsigned width, unsigned height)
520 win->maxSize.width = width;
521 win->maxSize.height = height;
522 if (win->view->flags.realized)
523 setSizeHints(win);
526 void WMSetWindowBaseSize(WMWindow * win, unsigned width, unsigned height)
528 /* TODO: validate sizes */
529 win->baseSize.width = width;
530 win->baseSize.height = height;
531 if (win->view->flags.realized)
532 setSizeHints(win);
535 void WMSetWindowResizeIncrements(WMWindow * win, unsigned wIncr, unsigned hIncr)
537 win->resizeIncrement.width = wIncr;
538 win->resizeIncrement.height = hIncr;
539 if (win->view->flags.realized)
540 setSizeHints(win);
543 void WMSetWindowLevel(WMWindow * win, int level)
545 win->level = level;
546 if (win->view->flags.realized)
547 setWindowMakerHints(win);
550 void WMSetWindowDocumentEdited(WMWindow * win, Bool flag)
552 flag = ((flag == 0) ? 0 : 1);
553 if (win->flags.documentEdited != flag) {
554 win->flags.documentEdited = flag;
555 if (win->view->flags.realized)
556 setWindowMakerHints(win);
560 void WMSetWindowMiniwindowImage(WMWindow * win, RImage * image)
562 if (win->view->flags.realized)
563 setMiniwindow(win, image);
566 void WMSetWindowMiniwindowPixmap(WMWindow * win, WMPixmap * pixmap)
568 if ((win->miniImage && !pixmap) || (!win->miniImage && pixmap)) {
569 if (win->miniImage)
570 WMReleasePixmap(win->miniImage);
572 if (pixmap)
573 win->miniImage = WMRetainPixmap(pixmap);
574 else
575 win->miniImage = NULL;
577 if (win->view->flags.realized) {
578 XWMHints *hints;
580 hints = XGetWMHints(win->view->screen->display, win->view->window);
581 if (!hints) {
582 hints = XAllocWMHints();
583 if (!hints) {
584 wwarning("could not allocate memory for WM hints");
585 return;
587 hints->flags = 0;
589 if (pixmap) {
590 hints->flags |= IconPixmapHint;
591 hints->icon_pixmap = WMGetPixmapXID(pixmap);
592 hints->icon_mask = WMGetPixmapMaskXID(pixmap);
593 if (hints->icon_mask != None) {
594 hints->flags |= IconMaskHint;
597 XSetWMHints(win->view->screen->display, win->view->window, hints);
598 XFree(hints);
603 void WMSetWindowMiniwindowTitle(WMWindow * win, char *title)
605 if ((win->miniTitle && !title) || (!win->miniTitle && title)
606 || (title && win->miniTitle && strcoll(title, win->miniTitle) != 0)) {
607 if (win->miniTitle)
608 wfree(win->miniTitle);
610 if (title)
611 win->miniTitle = wstrdup(title);
612 else
613 win->miniTitle = NULL;
615 if (win->view->flags.realized) {
616 setMiniwindowTitle(win, title);
621 void WMCloseWindow(WMWindow * win)
623 WMUnmapWidget(win);
624 /* withdraw the window */
625 if (win->view->flags.realized)
626 XWithdrawWindow(win->view->screen->display, win->view->window, win->view->screen->screen);
629 static void handleEvents(XEvent * event, void *clientData)
631 _Window *win = (_Window *) clientData;
632 W_View *view = win->view;
634 switch (event->type) {
635 case ClientMessage:
636 if (event->xclient.message_type == win->view->screen->protocolsAtom
637 && event->xclient.format == 32
638 && event->xclient.data.l[0] == win->view->screen->deleteWindowAtom) {
640 if (win->closeAction) {
641 (*win->closeAction) (win, win->closeData);
644 break;
646 * was causing windows to ignore commands like closeWindow
647 * after the windows is iconized/restored or a workspace change
648 * if this is really needed, put the MapNotify portion too and
649 * fix the restack bug in wmaker
650 case UnmapNotify:
651 WMUnmapWidget(win);
652 break;
654 case MapNotify:
655 WMMapWidget(win);
656 break;
659 case DestroyNotify:
660 destroyWindow(win);
661 break;
663 case ConfigureNotify:
664 if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
666 view->size.width = event->xconfigure.width;
667 view->size.height = event->xconfigure.height;
669 if (view->flags.notifySizeChanged) {
670 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
673 if (event->xconfigure.x != view->pos.x || event->xconfigure.y != view->pos.y) {
675 if (event->xconfigure.send_event) {
676 view->pos.x = event->xconfigure.x;
677 view->pos.y = event->xconfigure.y;
678 } else {
679 Window foo;
681 XTranslateCoordinates(view->screen->display,
682 view->window, view->screen->rootWin,
683 event->xconfigure.x, event->xconfigure.y,
684 &view->pos.x, &view->pos.y, &foo);
687 break;
691 static void destroyWindow(_Window * win)
693 WMScreen *scr = win->view->screen;
695 WMRemoveNotificationObserver(win);
697 if (scr->windowList == win) {
698 scr->windowList = scr->windowList->nextPtr;
699 } else {
700 WMWindow *ptr;
701 ptr = scr->windowList;
703 if (ptr) {
704 while (ptr->nextPtr) {
705 if (ptr->nextPtr == win) {
706 ptr->nextPtr = ptr->nextPtr->nextPtr;
707 break;
709 ptr = ptr->nextPtr;
714 if (win->title) {
715 wfree(win->title);
718 if (win->miniTitle) {
719 wfree(win->miniTitle);
722 if (win->miniImage) {
723 WMReleasePixmap(win->miniImage);
726 if (win->wname)
727 wfree(win->wname);
729 wfree(win);