Update Serbian translation from master branch
[wmaker-crm.git] / WINGs / wwindow.c
blobbf004840d4b7a98863eaff0c379ca54f1e422f38
2 #include <X11/Xmd.h>
4 #include "wconfig.h"
6 #include "WINGsP.h"
8 #include "GNUstep.h"
10 #include <X11/Xatom.h>
12 typedef struct W_Window {
13 W_Class widgetClass;
14 W_View *view;
16 struct W_Window *nextPtr; /* next in the window list */
18 struct W_Window *owner;
20 char *title;
22 WMPixmap *miniImage; /* miniwindow */
23 char *miniTitle;
25 char *wname;
27 WMSize resizeIncrement;
28 WMSize baseSize;
29 WMSize minSize;
30 WMSize maxSize;
31 WMPoint minAspect;
32 WMPoint maxAspect;
34 WMPoint upos;
35 WMPoint ppos;
37 WMAction *closeAction;
38 void *closeData;
40 int level;
42 struct {
43 unsigned style:4;
44 unsigned configured:1;
45 unsigned documentEdited:1;
47 unsigned setUPos:1;
48 unsigned setPPos:1;
49 unsigned setAspect:1;
50 } flags;
51 } _Window;
54 static void willResizeWindow(W_ViewDelegate *, WMView *, unsigned *, unsigned *);
56 struct W_ViewDelegate _WindowViewDelegate = {
57 NULL,
58 NULL,
59 NULL,
60 NULL,
61 willResizeWindow
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 */
76 (void) not;
78 realizeWindow(self);
81 WMWindow *WMCreatePanelWithStyleForWindow(WMWindow * owner, const char *name, int style)
83 WMWindow *win;
85 win = WMCreateWindowWithStyle(owner->view->screen, name, style);
86 win->owner = owner;
88 return win;
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)
115 _Window *win;
117 win = wmalloc(sizeof(_Window));
118 win->widgetClass = WC_Window;
120 win->view = W_CreateTopView(screen);
121 if (!win->view) {
122 wfree(win);
123 return NULL;
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);
149 return win;
152 static void setWindowTitle(WMWindow * win, const char *title)
154 WMScreen *scr = win->view->screen;
155 XTextProperty property;
156 int result;
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);
162 } else {
163 XSetWMName(scr->display, win->view->window, &property);
164 if (property.value)
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;
177 int result;
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);
183 } else {
184 XSetWMIconName(scr->display, win->view->window, &property);
185 if (property.value)
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;
197 unsigned long *data;
198 int x, y;
199 int o;
201 if (!image)
202 return;
204 data = wmalloc((image->width * image->height + 2) * sizeof(long));
206 o = 0;
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++) {
212 unsigned long pixel;
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]);
219 } else {
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;
226 data[o++] = pixel;
230 XChangeProperty(scr->display, win->view->window, scr->netwmIcon,
231 XA_CARDINAL, 32, PropModeReplace,
232 (unsigned char *)data, (image->width * image->height + 2));
234 wfree(data);
237 void WMSetWindowTitle(WMWindow * win, const char *title)
239 wassertr(title != NULL);
241 if (win->title != NULL)
242 wfree(win->title);
244 win->title = wstrdup(title);
246 if (win->view->flags.realized) {
247 setWindowTitle(win, title);
251 void WMSetWindowCloseAction(WMWindow * win, WMAction * action, void *clientData)
253 Atom *atoms = NULL;
254 Atom *newAtoms;
255 int count;
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)) {
261 count = 0;
263 newAtoms = wmalloc((count + 1) * sizeof(Atom));
264 if (count > 0)
265 memcpy(newAtoms, atoms, count * sizeof(Atom));
266 newAtoms[count++] = scr->deleteWindowAtom;
267 XSetWMProtocols(scr->display, win->view->window, newAtoms, count);
268 if (atoms)
269 XFree(atoms);
270 wfree(newAtoms);
271 } else if (!action && win->closeAction) {
272 int i, ncount;
274 if (XGetWMProtocols(scr->display, win->view->window, &atoms, &count) && count > 0) {
275 newAtoms = wmalloc((count - 1) * sizeof(Atom));
276 ncount = 0;
277 for (i = 0; i < count; i++) {
278 if (atoms[i] != scr->deleteWindowAtom) {
279 newAtoms[i] = atoms[i];
280 ncount++;
283 XSetWMProtocols(scr->display, win->view->window, newAtoms, ncount);
284 if (atoms)
285 XFree(atoms);
286 wfree(newAtoms);
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 */
299 (void) self;
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)
318 XSizeHints *hints;
320 hints = XAllocSizeHints();
321 if (!hints) {
322 wwarning("could not allocate memory for window size hints");
323 return;
326 hints->flags = 0;
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;
366 if (hints->flags) {
367 XSetWMNormalHints(win->view->screen->display, win->view->window, hints);
369 XFree(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;
399 if (win->minSize.width == win->maxSize.width && win->minSize.height == win->maxSize.height)
400 win->flags.style &= ~WMResizableWindowMask;
401 attribs.window_style = win->flags.style;
403 attribs.window_level = win->level;
404 if (win->flags.documentEdited)
405 attribs.extra_flags = GSDocumentEditedFlag;
406 else
407 attribs.extra_flags = 0;
409 writeGNUstepWMAttr(scr, win->view->window, &attribs);
412 static void realizeWindow(WMWindow * win)
414 XWMHints *hints;
415 XClassHint *classHint;
416 WMScreen *scr = win->view->screen;
417 Atom atoms[4];
418 int count;
420 classHint = XAllocClassHint();
421 classHint->res_name = win->wname;
422 classHint->res_class = WMGetApplicationName();
423 XSetClassHint(scr->display, win->view->window, classHint);
424 XFree(classHint);
426 hints = XAllocWMHints();
427 hints->flags = 0;
428 if (!scr->aflags.simpleApplication) {
429 hints->flags |= WindowGroupHint;
430 hints->window_group = scr->groupLeader;
432 if (win->miniImage) {
433 hints->flags |= IconPixmapHint;
434 hints->icon_pixmap = WMGetPixmapXID(win->miniImage);
435 hints->icon_mask = WMGetPixmapMaskXID(win->miniImage);
436 if (hints->icon_mask != None) {
437 hints->flags |= IconMaskHint;
440 if (hints->flags != 0)
441 XSetWMHints(scr->display, win->view->window, hints);
442 XFree(hints);
444 count = 0;
445 if (win->closeAction) {
446 atoms[count++] = scr->deleteWindowAtom;
449 if (count > 0)
450 XSetWMProtocols(scr->display, win->view->window, atoms, count);
452 if (win->title || win->miniTitle)
453 XmbSetWMProperties(scr->display, win->view->window, win->title,
454 win->miniTitle, NULL, 0, NULL, NULL, NULL);
456 setWindowMakerHints(win);
458 setSizeHints(win);
460 if (win->owner) {
461 XSetTransientForHint(scr->display, win->view->window, win->owner->view->window);
464 if (win->title)
465 setWindowTitle(win, win->title);
468 void WMSetWindowAspectRatio(WMWindow * win, int minX, int minY, int maxX, int maxY)
470 win->flags.setAspect = 1;
471 win->minAspect.x = minX;
472 win->minAspect.y = minY;
473 win->maxAspect.x = maxX;
474 win->maxAspect.y = maxY;
475 if (win->view->flags.realized)
476 setSizeHints(win);
479 void WMSetWindowInitialPosition(WMWindow * win, int x, int y)
481 win->flags.setPPos = 1;
482 win->ppos.x = x;
483 win->ppos.y = y;
484 if (win->view->flags.realized)
485 setSizeHints(win);
486 WMMoveWidget(win, x, y);
489 void WMSetWindowUserPosition(WMWindow * win, int x, int y)
491 win->flags.setUPos = 1;
492 win->upos.x = x;
493 win->upos.y = y;
494 if (win->view->flags.realized)
495 setSizeHints(win);
496 WMMoveWidget(win, x, y);
499 void WMSetWindowMinSize(WMWindow * win, unsigned width, unsigned height)
501 win->minSize.width = width;
502 win->minSize.height = height;
503 if (win->view->flags.realized)
504 setSizeHints(win);
507 void WMSetWindowMaxSize(WMWindow * win, unsigned width, unsigned height)
509 win->maxSize.width = width;
510 win->maxSize.height = height;
511 if (win->view->flags.realized)
512 setSizeHints(win);
515 void WMSetWindowBaseSize(WMWindow * win, unsigned width, unsigned height)
517 /* TODO: validate sizes */
518 win->baseSize.width = width;
519 win->baseSize.height = height;
520 if (win->view->flags.realized)
521 setSizeHints(win);
524 void WMSetWindowResizeIncrements(WMWindow * win, unsigned wIncr, unsigned hIncr)
526 win->resizeIncrement.width = wIncr;
527 win->resizeIncrement.height = hIncr;
528 if (win->view->flags.realized)
529 setSizeHints(win);
532 void WMSetWindowLevel(WMWindow * win, int level)
534 win->level = level;
535 if (win->view->flags.realized)
536 setWindowMakerHints(win);
539 void WMSetWindowDocumentEdited(WMWindow * win, Bool flag)
541 flag = ((flag == 0) ? 0 : 1);
542 if (win->flags.documentEdited != flag) {
543 win->flags.documentEdited = flag;
544 if (win->view->flags.realized)
545 setWindowMakerHints(win);
549 void WMSetWindowMiniwindowImage(WMWindow * win, RImage * image)
551 if (win->view->flags.realized)
552 setMiniwindow(win, image);
555 void WMSetWindowMiniwindowPixmap(WMWindow * win, WMPixmap * pixmap)
557 if ((win->miniImage && !pixmap) || (!win->miniImage && pixmap)) {
558 if (win->miniImage)
559 WMReleasePixmap(win->miniImage);
561 if (pixmap)
562 win->miniImage = WMRetainPixmap(pixmap);
563 else
564 win->miniImage = NULL;
566 if (win->view->flags.realized) {
567 XWMHints *hints;
569 hints = XGetWMHints(win->view->screen->display, win->view->window);
570 if (!hints) {
571 hints = XAllocWMHints();
572 if (!hints) {
573 wwarning("could not allocate memory for WM hints");
574 return;
576 hints->flags = 0;
578 if (pixmap) {
579 hints->flags |= IconPixmapHint;
580 hints->icon_pixmap = WMGetPixmapXID(pixmap);
581 hints->icon_mask = WMGetPixmapMaskXID(pixmap);
582 if (hints->icon_mask != None) {
583 hints->flags |= IconMaskHint;
586 XSetWMHints(win->view->screen->display, win->view->window, hints);
587 XFree(hints);
592 void WMSetWindowMiniwindowTitle(WMWindow * win, const char *title)
594 if (win && ((win->miniTitle && !title) || (!win->miniTitle && title)
595 || (title && win->miniTitle && strcoll(title, win->miniTitle) != 0))) {
596 if (win->miniTitle)
597 wfree(win->miniTitle);
599 if (title)
600 win->miniTitle = wstrdup(title);
601 else
602 win->miniTitle = NULL;
604 if (win->view->flags.realized) {
605 setMiniwindowTitle(win, title);
610 void WMCloseWindow(WMWindow * win)
612 WMUnmapWidget(win);
613 /* withdraw the window */
614 if (win->view->flags.realized)
615 XWithdrawWindow(win->view->screen->display, win->view->window, win->view->screen->screen);
618 static void handleEvents(XEvent * event, void *clientData)
620 _Window *win = (_Window *) clientData;
621 W_View *view = win->view;
623 switch (event->type) {
624 case ClientMessage:
625 if (event->xclient.message_type == win->view->screen->protocolsAtom
626 && event->xclient.format == 32
627 && event->xclient.data.l[0] == win->view->screen->deleteWindowAtom) {
629 if (win->closeAction) {
630 (*win->closeAction) (win, win->closeData);
633 break;
635 * was causing windows to ignore commands like closeWindow
636 * after the windows is iconized/restored or a workspace change
637 * if this is really needed, put the MapNotify portion too and
638 * fix the restack bug in wmaker
639 case UnmapNotify:
640 WMUnmapWidget(win);
641 break;
643 case MapNotify:
644 WMMapWidget(win);
645 break;
648 case DestroyNotify:
649 destroyWindow(win);
650 break;
652 case ConfigureNotify:
653 if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
655 view->size.width = event->xconfigure.width;
656 view->size.height = event->xconfigure.height;
658 if (view->flags.notifySizeChanged) {
659 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
662 if (event->xconfigure.x != view->pos.x || event->xconfigure.y != view->pos.y) {
664 if (event->xconfigure.send_event) {
665 view->pos.x = event->xconfigure.x;
666 view->pos.y = event->xconfigure.y;
667 } else {
668 Window foo;
670 XTranslateCoordinates(view->screen->display,
671 view->window, view->screen->rootWin,
672 event->xconfigure.x, event->xconfigure.y,
673 &view->pos.x, &view->pos.y, &foo);
676 break;
680 static void destroyWindow(_Window * win)
682 WMScreen *scr = win->view->screen;
684 WMRemoveNotificationObserver(win);
686 if (scr->windowList == win) {
687 scr->windowList = scr->windowList->nextPtr;
688 } else {
689 WMWindow *ptr;
690 ptr = scr->windowList;
692 if (ptr) {
693 while (ptr->nextPtr) {
694 if (ptr->nextPtr == win) {
695 ptr->nextPtr = ptr->nextPtr->nextPtr;
696 break;
698 ptr = ptr->nextPtr;
703 if (win->title) {
704 wfree(win->title);
707 if (win->miniTitle) {
708 wfree(win->miniTitle);
711 if (win->miniImage) {
712 WMReleasePixmap(win->miniImage);
715 if (win->wname)
716 wfree(win->wname);
718 wfree(win);