bug fixes, performance enhancement for image rendering
[wmaker-crm.git] / src / framewin.c
blobcbd8b3b22dcf47abec86b77011633ba01f8742fa
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997, 1998 Alfredo K. Kojima
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 * USA.
22 #include "wconfig.h"
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include <wraster.h>
32 #include "WindowMaker.h"
33 #include "GNUstep.h"
34 #include "texture.h"
35 #include "screen.h"
36 #include "wcore.h"
37 #include "framewin.h"
38 #include "stacking.h"
39 #include "funcs.h"
41 #define DBLCLICK_TIME wPreferences.dblclick_time
43 extern WPreferences wPreferences;
45 static void handleExpose(WObjDescriptor *desc, XEvent *event);
46 static void handleButtonExpose(WObjDescriptor *desc, XEvent *event);
48 static void buttonMouseDown(WObjDescriptor *desc, XEvent *event);
49 static void titlebarMouseDown(WObjDescriptor *desc, XEvent *event);
50 static void resizebarMouseDown(WObjDescriptor *desc, XEvent *event);
52 static void checkTitleSize(WFrameWindow *fwin);
55 static void paintButton(WCoreWindow *button, WTexture *texture,
56 unsigned long color, WPixmap *image, int pushed);
58 static void updateTitlebar(WFrameWindow *fwin);
60 static void remakeTexture(WFrameWindow *fwin, int state, int newWidth);
62 static void updateTexture(WFrameWindow *fwin);
65 WFrameWindow*
66 wFrameWindowCreate(WScreen *scr, int wlevel, int x, int y,
67 int width, int height, int flags,
68 WTexture **title_texture, WTexture **resize_texture,
69 unsigned long *color, GC *gc, WFont **font)
71 WFrameWindow *fwin;
73 fwin = wmalloc(sizeof(WFrameWindow));
74 memset(fwin, 0, sizeof(WFrameWindow));
76 fwin->screen_ptr = scr;
78 fwin->flags.single_texture = (flags & WFF_SINGLE_STATE) ? 1 : 0;
80 fwin->title_texture = title_texture;
81 fwin->resizebar_texture = resize_texture;
82 fwin->title_pixel = color;
83 fwin->title_gc = gc;
84 fwin->font = font;
86 fwin->core = wCoreCreateTopLevel(scr, x, y, width, height,
87 FRAME_BORDER_WIDTH);
88 if (wPreferences.use_saveunders) {
89 unsigned long vmask;
90 XSetWindowAttributes attribs;
92 vmask = CWSaveUnder;
93 attribs.save_under = True;
94 XChangeWindowAttributes(dpy, fwin->core->window, vmask, &attribs);
97 /* setup stacking information */
98 fwin->core->stacking = wmalloc(sizeof(WStacking));
99 fwin->core->stacking->above = NULL;
100 fwin->core->stacking->under = NULL;
101 fwin->core->stacking->child_of = NULL;
102 fwin->core->stacking->window_level = wlevel;
104 AddToStackList(fwin->core);
106 wFrameWindowUpdateBorders(fwin, flags);
108 return fwin;
113 void
114 wFrameWindowUpdateBorders(WFrameWindow *fwin, int flags)
116 int theight;
117 int bsize;
118 int width, height;
119 int i;
120 WScreen *scr = fwin->screen_ptr;
122 width = fwin->core->width;
123 if (flags & WFF_IS_SHADED)
124 height = -1;
125 else
126 height = fwin->core->height - fwin->top_width - fwin->bottom_width;
128 if (flags & WFF_TITLEBAR)
129 theight = (*fwin->font)->height + TITLEBAR_EXTRA_HEIGHT;
130 else
131 theight = 0;
133 if (wPreferences.new_style) {
134 bsize = theight;
135 } else {
136 bsize = theight - 7;
139 if (fwin->titlebar) {
140 /* if we had a titlebar and is requesting for one,
141 * check if the size has changed and resize it */
142 if (flags & WFF_TITLEBAR) {
143 fwin->top_width = theight;
145 fwin->flags.need_texture1_remake = 1;
146 fwin->flags.need_texture2_remake = 1;
147 fwin->flags.need_texture3_remake = 1;
149 if (wPreferences.new_style) {
150 if (fwin->left_button) {
151 wCoreConfigure(fwin->left_button, 0, 0, bsize, bsize);
154 if (fwin->right_button) {
155 wCoreConfigure(fwin->right_button, width-bsize+1,
156 0, bsize, bsize);
158 } else { /* !new_style */
159 if (fwin->left_button) {
160 wCoreConfigure(fwin->left_button, 3, (theight-bsize)/2,
161 bsize, bsize);
164 if (fwin->right_button) {
165 wCoreConfigure(fwin->right_button, width-bsize-3,
166 (theight-bsize)/2, bsize, bsize);
169 updateTitlebar(fwin);
170 } else {
171 /* we had a titlebar, but now we don't need it anymore */
172 for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
173 FREE_PIXMAP(fwin->title_back[i]);
174 if (wPreferences.new_style) {
175 FREE_PIXMAP(fwin->lbutton_back[i]);
176 FREE_PIXMAP(fwin->rbutton_back[i]);
179 if (fwin->left_button)
180 wCoreDestroy(fwin->left_button);
181 fwin->left_button = NULL;
183 if (fwin->right_button)
184 wCoreDestroy(fwin->right_button);
185 fwin->right_button = NULL;
187 wCoreDestroy(fwin->titlebar);
188 fwin->titlebar = NULL;
190 fwin->top_width = 0;
192 } else {
193 /* if we didn't have a titlebar and are being requested for
194 * one, create it */
195 if (flags & WFF_TITLEBAR) {
196 fwin->top_width = theight;
198 fwin->flags.titlebar = 1;
199 fwin->titlebar = wCoreCreate(fwin->core, 0, 0, width+1, theight);
201 if (flags & WFF_LEFT_BUTTON) {
202 fwin->flags.left_button = 1;
203 if (wPreferences.new_style) {
204 fwin->left_button = wCoreCreate(fwin->core, 0, 0,
205 bsize, bsize);
206 if (width < theight*4) {
207 fwin->flags.lbutton_dont_fit = 1;
208 } else {
209 XMapRaised(dpy, fwin->left_button->window);
211 } else {
212 fwin->left_button =
213 wCoreCreate(fwin->titlebar, 3, (theight-bsize)/2,
214 bsize, bsize);
216 XSetWindowBackground(dpy, fwin->left_button->window,
217 scr->widget_texture->normal.pixel);
219 if (width < theight*3) {
220 fwin->flags.lbutton_dont_fit = 1;
221 } else {
222 XMapRaised(dpy, fwin->left_button->window);
228 if (flags & WFF_RIGHT_BUTTON) {
229 fwin->flags.right_button = 1;
230 if (wPreferences.new_style) {
231 fwin->right_button =
232 wCoreCreate(fwin->core, width-bsize+1, 0,
233 bsize, bsize);
234 } else {
235 fwin->right_button =
236 wCoreCreate(fwin->titlebar, width-bsize-3,
237 (theight-bsize)/2, bsize, bsize);
238 XSetWindowBackground(dpy, fwin->right_button->window,
239 scr->widget_texture->normal.pixel);
242 if (width < theight*2) {
243 fwin->flags.rbutton_dont_fit = 1;
244 } else {
245 XMapRaised(dpy, fwin->right_button->window);
249 if (wPreferences.new_style)
250 updateTitlebar(fwin);
252 XMapRaised(dpy, fwin->titlebar->window);
254 fwin->flags.need_texture1_remake = 1;
255 fwin->flags.need_texture2_remake = 1;
256 fwin->flags.need_texture3_remake = 1;
259 checkTitleSize(fwin);
261 if (flags & WFF_RESIZEBAR) {
262 fwin->bottom_width = RESIZEBAR_HEIGHT;
263 } else {
264 fwin->bottom_width = 0;
267 if (flags & WFF_RESIZEBAR) {
268 if (!fwin->resizebar) {
269 fwin->flags.resizebar = 1;
270 fwin->resizebar = wCoreCreate(fwin->core, 0,
271 height + fwin->top_width,
272 width, RESIZEBAR_HEIGHT);
273 fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
274 if (width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
275 fwin->resizebar_corner_width = (width - RESIZEBAR_MIN_WIDTH)/2;
276 if (fwin->resizebar_corner_width < 0)
277 fwin->resizebar_corner_width = 0;
280 XMapWindow(dpy, fwin->resizebar->window);
281 XLowerWindow(dpy, fwin->resizebar->window);
283 fwin->flags.need_texture1_remake = 1;
284 fwin->flags.need_texture2_remake = 1;
285 fwin->flags.need_texture3_remake = 1;
286 } else {
287 if (height+fwin->top_width+fwin->bottom_width != fwin->core->height) {
288 wCoreConfigure(fwin->resizebar, 0, height + fwin->top_width,
289 width, RESIZEBAR_HEIGHT);
292 } else {
293 if (fwin->resizebar) {
294 fwin->bottom_width = 0;
295 wCoreDestroy(fwin->resizebar);
296 fwin->resizebar = NULL;
300 if (height + fwin->top_width + fwin->bottom_width != fwin->core->height
301 && !(flags & WFF_IS_SHADED)) {
302 wFrameWindowResize(fwin, width,
303 height + fwin->top_width + fwin->bottom_width);
306 /* setup object descriptors */
308 if (fwin->titlebar) {
309 fwin->titlebar->descriptor.handle_expose = handleExpose;
310 fwin->titlebar->descriptor.parent = fwin;
311 fwin->titlebar->descriptor.parent_type = WCLASS_FRAME;
312 fwin->titlebar->descriptor.handle_mousedown = titlebarMouseDown;
315 if (fwin->resizebar) {
316 fwin->resizebar->descriptor.handle_expose = handleExpose;
317 fwin->resizebar->descriptor.parent = fwin;
318 fwin->resizebar->descriptor.parent_type = WCLASS_FRAME;
319 fwin->resizebar->descriptor.handle_mousedown = resizebarMouseDown;
322 if (fwin->left_button) {
323 fwin->left_button->descriptor.handle_expose = handleButtonExpose;
324 fwin->left_button->descriptor.parent = fwin;
325 fwin->left_button->descriptor.parent_type = WCLASS_FRAME;
326 fwin->left_button->descriptor.handle_mousedown = buttonMouseDown;
329 if (fwin->right_button) {
330 fwin->right_button->descriptor.parent = fwin;
331 fwin->right_button->descriptor.parent_type = WCLASS_FRAME;
332 fwin->right_button->descriptor.handle_expose = handleButtonExpose;
333 fwin->right_button->descriptor.handle_mousedown = buttonMouseDown;
336 checkTitleSize(fwin);
341 void
342 wFrameWindowDestroy(WFrameWindow *fwin)
344 int i;
346 if (fwin->left_button)
347 wCoreDestroy(fwin->left_button);
349 if (fwin->right_button)
350 wCoreDestroy(fwin->right_button);
352 if (fwin->resizebar)
353 wCoreDestroy(fwin->resizebar);
355 if (fwin->titlebar)
356 wCoreDestroy(fwin->titlebar);
358 RemoveFromStackList(fwin->core);
360 wCoreDestroy(fwin->core);
362 if (fwin->title)
363 free(fwin->title);
365 for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
366 FREE_PIXMAP(fwin->title_back[i]);
367 if (wPreferences.new_style) {
368 FREE_PIXMAP(fwin->lbutton_back[i]);
369 FREE_PIXMAP(fwin->rbutton_back[i]);
373 free(fwin);
377 void
378 wFrameWindowChangeState(WFrameWindow *fwin, int state)
380 if (fwin->flags.state==state)
381 return;
383 fwin->flags.state = state;
384 fwin->flags.need_texture_change = 1;
386 wFrameWindowPaint(fwin);
390 static void
391 updateTitlebar(WFrameWindow *fwin)
393 int x, w;
394 int theight;
396 theight = (*fwin->font)->height + TITLEBAR_EXTRA_HEIGHT;
398 x = 0;
399 w = fwin->core->width + 1;
401 if (wPreferences.new_style) {
402 if (fwin->flags.hide_left_button || !fwin->left_button
403 || fwin->flags.lbutton_dont_fit) {
404 x = 0;
405 } else {
406 x = fwin->left_button->width;
407 w -= fwin->left_button->width;
411 if (wPreferences.new_style) {
412 if (!fwin->flags.hide_right_button && fwin->right_button
413 && !fwin->flags.rbutton_dont_fit) {
414 w -= fwin->right_button->width;
418 if (wPreferences.new_style || fwin->titlebar->width!=w) {
419 fwin->flags.need_texture1_remake = 1;
420 fwin->flags.need_texture2_remake = 1;
421 fwin->flags.need_texture3_remake = 1;
424 wCoreConfigure(fwin->titlebar, x, 0, w, theight);
428 void
429 wFrameWindowHideButton(WFrameWindow *fwin, int flags)
431 if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button) {
432 XUnmapWindow(dpy, fwin->right_button->window);
433 fwin->flags.hide_right_button = 1;
436 if ((flags & WFF_LEFT_BUTTON) && fwin->left_button) {
437 XUnmapWindow(dpy, fwin->left_button->window);
438 fwin->flags.hide_left_button = 1;
441 if (fwin->titlebar) {
442 if (wPreferences.new_style) {
443 updateTitlebar(fwin);
444 } else {
445 XClearWindow(dpy, fwin->titlebar->window);
446 wFrameWindowPaint(fwin);
448 checkTitleSize(fwin);
453 void
454 wFrameWindowShowButton(WFrameWindow *fwin, int flags)
456 if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button
457 && fwin->flags.hide_right_button) {
459 if (!fwin->flags.rbutton_dont_fit)
460 XMapWindow(dpy, fwin->right_button->window);
462 fwin->flags.hide_right_button = 0;
465 if ((flags & WFF_LEFT_BUTTON) && fwin->left_button
466 && fwin->flags.hide_left_button) {
468 if (!fwin->flags.lbutton_dont_fit)
469 XMapWindow(dpy, fwin->left_button->window);
471 fwin->flags.hide_left_button = 0;
475 if (fwin->titlebar) {
476 if (wPreferences.new_style) {
477 updateTitlebar(fwin);
478 } else {
479 XClearWindow(dpy, fwin->titlebar->window);
480 wFrameWindowPaint(fwin);
482 checkTitleSize(fwin);
487 static void
488 renderTexture(WScreen *scr, WTexture *texture, int width, int height,
489 int bwidth, int bheight, int left, int right,
490 Pixmap *title, Pixmap *lbutton, Pixmap *rbutton)
492 RImage *img;
493 RImage *limg, *rimg, *mimg;
494 int x, w;
496 *title = None;
497 *lbutton = None;
498 *rbutton = None;
500 img = wTextureRenderImage(texture, width, height, WREL_FLAT);
501 if (!img) {
502 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
503 return;
506 if (wPreferences.new_style) {
507 if (left) {
508 limg = RGetSubImage(img, 0, 0, bwidth, bheight);
509 } else
510 limg = NULL;
512 x = 0;
513 w = img->width;
515 if (limg) {
516 RBevelImage(limg, RBEV_RAISED2);
517 if (!RConvertImage(scr->rcontext, limg, lbutton)) {
518 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
520 x += limg->width;
521 w -= limg->width;
522 RDestroyImage(limg);
525 if (right) {
526 rimg = RGetSubImage(img, width - bwidth, 0, bwidth, bheight);
527 } else
528 rimg = NULL;
530 if (rimg) {
531 RBevelImage(rimg, RBEV_RAISED2);
532 if (!RConvertImage(scr->rcontext, rimg, rbutton)) {
533 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
535 w -= rimg->width;
536 RDestroyImage(rimg);
539 if (w!=width) {
540 mimg = RGetSubImage(img, x, 0, w, img->height);
541 RBevelImage(mimg, RBEV_RAISED2);
543 if (!RConvertImage(scr->rcontext, mimg, title)) {
544 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
546 RDestroyImage(mimg);
547 } else {
548 RBevelImage(img, RBEV_RAISED2);
550 if (!RConvertImage(scr->rcontext, img, title)) {
551 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
554 } else {
555 RBevelImage(img, RBEV_RAISED2);
557 if (!RConvertImage(scr->rcontext, img, title)) {
558 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
562 RDestroyImage(img);
566 static void
567 renderResizebarTexture(WScreen *scr, WTexture *texture, int width, int height,
568 int cwidth, Pixmap *pmap)
570 RImage *img;
571 RColor light;
572 RColor dark;
574 *pmap = None;
576 img = wTextureRenderImage(texture, width, height, WREL_FLAT);
577 if (!img) {
578 wwarning(_("could not render texture: %s"),
579 RMessageForError(RErrorCode));
580 return;
583 light.alpha = 0;
584 light.red = light.green = light.blue = 80;
586 dark.alpha = 0;
587 dark.red = dark.green = dark.blue = 40;
589 ROperateLine(img, RSubtractOperation, 0, 0, width-1, 0, &dark);
590 ROperateLine(img, RAddOperation, 0, 1, width-1, 1, &light);
592 ROperateLine(img, RSubtractOperation, cwidth, 2, cwidth, height-1, &dark);
593 ROperateLine(img, RAddOperation, cwidth+1, 2, cwidth+1, height-1, &light);
595 if (width > 1)
596 ROperateLine(img, RSubtractOperation, width-cwidth-2, 2,
597 width-cwidth-2, height-1, &dark);
598 ROperateLine(img, RAddOperation, width-cwidth-1, 2, width-cwidth-1,
599 height-1, &light);
601 #ifdef SHADOW_RESIZEBAR
602 ROperateLine(img, RAddOperation, 0, 1, 0, height-1, &light);
603 ROperateLine(img, RSubtractOperation, width-1, 1, width-1, height-1,
604 &dark);
605 ROperateLine(img, RSubtractOperation, 0, height-1, width-1, height-1,
606 &dark);
607 #endif /* SHADOW_RESIZEBAR */
610 if (!RConvertImage(scr->rcontext, img, pmap)) {
611 wwarning(_("error rendering image: %s"), RMessageForError(RErrorCode));
614 RDestroyImage(img);
619 static void
620 updateTexture(WFrameWindow *fwin)
622 int i;
623 unsigned long pixel;
625 i = fwin->flags.state;
626 if (fwin->titlebar) {
627 if (fwin->title_texture[i]->any.type!=WTEX_SOLID) {
628 XSetWindowBackgroundPixmap(dpy, fwin->titlebar->window,
629 fwin->title_back[i]);
630 if (wPreferences.new_style) {
631 if (fwin->left_button && fwin->lbutton_back[i])
632 XSetWindowBackgroundPixmap(dpy, fwin->left_button->window,
633 fwin->lbutton_back[i]);
635 if (fwin->right_button && fwin->rbutton_back[i])
636 XSetWindowBackgroundPixmap(dpy, fwin->right_button->window,
637 fwin->rbutton_back[i]);
639 } else {
640 pixel = fwin->title_texture[i]->solid.normal.pixel;
641 XSetWindowBackground(dpy, fwin->titlebar->window, pixel);
642 if (wPreferences.new_style) {
643 if (fwin->left_button)
644 XSetWindowBackground(dpy, fwin->left_button->window,
645 pixel);
646 if (fwin->right_button)
647 XSetWindowBackground(dpy, fwin->right_button->window,
648 pixel);
651 XClearWindow(dpy, fwin->titlebar->window);
653 if (fwin->left_button) {
654 XClearWindow(dpy, fwin->left_button->window);
655 handleButtonExpose(&fwin->left_button->descriptor, NULL);
657 if (fwin->right_button) {
658 XClearWindow(dpy, fwin->right_button->window);
659 handleButtonExpose(&fwin->right_button->descriptor, NULL);
662 XFlush(dpy);
667 static void
668 remakeTexture(WFrameWindow *fwin, int state, int newWidth)
670 Pixmap pmap, lpmap, rpmap;
672 if (fwin->title_texture[state] && fwin->titlebar) {
673 FREE_PIXMAP(fwin->title_back[state]);
674 if (wPreferences.new_style) {
675 FREE_PIXMAP(fwin->lbutton_back[state]);
676 FREE_PIXMAP(fwin->rbutton_back[state]);
679 if (fwin->title_texture[state]->any.type!=WTEX_SOLID) {
680 int left, right;
681 int width;
683 /* eventually surrounded by if new_style */
684 left = fwin->left_button && !fwin->flags.hide_left_button
685 && !fwin->flags.lbutton_dont_fit;
686 right = fwin->right_button && !fwin->flags.hide_right_button
687 && !fwin->flags.rbutton_dont_fit;
689 width = newWidth+1;
691 renderTexture(fwin->screen_ptr, fwin->title_texture[state],
692 width, fwin->titlebar->height,
693 fwin->titlebar->height, fwin->titlebar->height,
694 left, right, &pmap, &lpmap, &rpmap);
696 fwin->title_back[state] = pmap;
697 if (wPreferences.new_style) {
698 fwin->lbutton_back[state] = lpmap;
699 fwin->rbutton_back[state] = rpmap;
703 if (fwin->resizebar_texture && fwin->resizebar_texture[0]
704 && fwin->resizebar && state == fwin->flags.state) {
706 FREE_PIXMAP(fwin->resizebar_back[0]);
708 if (fwin->resizebar_texture[0]->any.type!=WTEX_SOLID) {
710 renderResizebarTexture(fwin->screen_ptr,
711 fwin->resizebar_texture[0],
712 newWidth, fwin->resizebar->height,
713 fwin->resizebar_corner_width,
714 &pmap);
716 fwin->resizebar_back[0] = pmap;
719 /* this part should be in updateTexture() */
720 if (fwin->resizebar_texture[0]->any.type!=WTEX_SOLID) {
721 XSetWindowBackgroundPixmap(dpy, fwin->resizebar->window,
722 fwin->resizebar_back[0]);
723 } else {
724 XSetWindowBackground(dpy, fwin->resizebar->window,
725 fwin->resizebar_texture[0]->solid.normal.pixel);
727 XClearWindow(dpy, fwin->resizebar->window);
732 void
733 wFrameWindowPaint(WFrameWindow *fwin)
735 if (fwin->flags.is_client_window_frame)
736 fwin->flags.justification = wPreferences.title_justification;
738 if (fwin->flags.need_texture1_remake || fwin->flags.need_texture2_remake
739 || fwin->flags.need_texture3_remake) {
741 if (fwin->flags.single_texture) {
743 fwin->flags.need_texture_change = 1;
745 fwin->flags.need_texture1_remake = 0;
746 fwin->flags.need_texture2_remake = 0;
747 fwin->flags.need_texture3_remake = 0;
749 remakeTexture(fwin, 0, fwin->core->width);
751 } else if (fwin->flags.state==0 && fwin->flags.need_texture1_remake) {
753 fwin->flags.need_texture_change = 1;
754 fwin->flags.need_texture1_remake = 0;
755 remakeTexture(fwin, fwin->flags.state, fwin->core->width);
757 } else if (fwin->flags.state==1 && fwin->flags.need_texture2_remake) {
759 fwin->flags.need_texture_change = 1;
760 fwin->flags.need_texture2_remake = 0;
761 remakeTexture(fwin, fwin->flags.state, fwin->core->width);
763 } else if (fwin->flags.state==2 && fwin->flags.need_texture3_remake) {
765 fwin->flags.need_texture_change = 1;
766 fwin->flags.need_texture3_remake = 0;
767 remakeTexture(fwin, fwin->flags.state, fwin->core->width);
771 if (fwin->flags.need_texture_change) {
772 fwin->flags.need_texture_change = 0;
774 updateTexture(fwin);
777 if (fwin->titlebar && !fwin->flags.repaint_only_resizebar
778 && fwin->title_texture[fwin->flags.state]->any.type==WTEX_SOLID) {
779 wDrawBevel(fwin->titlebar->window, fwin->titlebar->width,
780 fwin->titlebar->height,
781 (WTexSolid*)fwin->title_texture[fwin->flags.state],
782 WREL_RAISED);
785 if (fwin->resizebar && !fwin->flags.repaint_only_titlebar
786 && fwin->resizebar_texture[0]->any.type == WTEX_SOLID) {
787 Window win;
788 int w, h;
789 int cw;
790 GC light_gc, dim_gc;
791 WTexSolid *texture = (WTexSolid*)fwin->resizebar_texture[0];
793 w = fwin->resizebar->width;
794 h = fwin->resizebar->height;
795 cw = fwin->resizebar_corner_width;
796 light_gc = texture->light_gc;
797 dim_gc = texture->dim_gc;
798 win = fwin->resizebar->window;
800 XDrawLine(dpy, win, dim_gc, 0, 0, w, 0);
801 XDrawLine(dpy, win, light_gc, 0, 1, w, 1);
803 XDrawLine(dpy, win, dim_gc, cw, 2, cw, h);
804 XDrawLine(dpy, win, light_gc, cw+1, 2, cw+1, h);
806 XDrawLine(dpy, win, dim_gc, w-cw-2, 2, w-cw-2, h);
807 XDrawLine(dpy, win, light_gc, w-cw-1, 2, w-cw-1, h);
809 #ifdef SHADOW_RESIZEBAR
810 XDrawLine(dpy, win, light_gc, 0, 1, 0, h-1);
811 XDrawLine(dpy, win, dim_gc, w-1, 2, w-1, h-1);
812 XDrawLine(dpy, win, dim_gc, 1, h-1, cw, h-1);
813 XDrawLine(dpy, win, dim_gc, cw+2, h-1, w-cw-2, h-1);
814 XDrawLine(dpy, win, dim_gc, w-cw, h-1, w-1, h-1);
815 #endif /* SHADOW_RESIZEBAR */
819 if (fwin->title && fwin->titlebar && !fwin->flags.repaint_only_resizebar) {
820 int x, w;
821 int lofs = 6, rofs = 6;
822 int titlelen;
823 char *title;
824 int allButtons = 1;
827 if (!wPreferences.new_style) {
828 if (fwin->left_button && !fwin->flags.hide_left_button
829 && !fwin->flags.lbutton_dont_fit)
830 lofs += fwin->left_button->width + 3;
831 else
832 allButtons = 0;
834 if (fwin->right_button && !fwin->flags.hide_right_button
835 && !fwin->flags.rbutton_dont_fit)
836 rofs += fwin->right_button->width + 3;
837 else
838 allButtons = 0;
841 #ifdef XKB_TITLE_HINT
842 if(fwin->flags.is_client_window_frame) {
843 char * freebuff;
844 freebuff = (char *)wmalloc((strlen(fwin->title)+6)*sizeof(char));
845 if (fwin->flags.justification == WTJ_RIGHT)
846 sprintf(freebuff,"%s %s",fwin->title,fwin->languagemode?XKB_ON:XKB_OFF);
847 else
848 sprintf(freebuff,"%s %s",fwin->languagemode?XKB_ON:XKB_OFF,fwin->title);
849 title = ShrinkString(*fwin->font, freebuff,
850 fwin->titlebar->width - lofs - rofs);
851 free(freebuff);
853 else title = ShrinkString(*fwin->font, fwin->title,
854 fwin->titlebar->width - lofs - rofs);
855 #else
856 title = ShrinkString(*fwin->font, fwin->title,
857 fwin->titlebar->width - lofs - rofs);
858 #endif /* XKB_TITLE_HINT */
859 titlelen = strlen(title);
860 w = wTextWidth((*fwin->font)->font, title, titlelen);
862 switch (fwin->flags.justification) {
863 case WTJ_LEFT:
864 x = lofs;
865 break;
867 case WTJ_RIGHT:
868 x = fwin->titlebar->width - w - rofs;
869 break;
871 default:
872 if (!allButtons)
873 x = lofs + (fwin->titlebar->width - w - lofs - rofs) / 2;
874 else
875 x = (fwin->titlebar->width - w) / 2;
876 break;
879 #ifdef TITLE_TEXT_SHADOW
880 if(wPreferences.title_shadow) {
881 int shadowx,shadowy;
882 XSetForeground(dpy, *fwin->title_gc,
883 fwin->title_pixel[fwin->flags.state+3]);
884 for(shadowx=0;shadowx<TITLE_TEXT_SHADOW_WIDTH;shadowx++)
885 for(shadowy=0;shadowy<TITLE_TEXT_SHADOW_HEIGHT;shadowy++)
886 wDrawString(fwin->titlebar->window, *fwin->font,
887 *fwin->title_gc,
888 x + shadowx + TITLE_TEXT_SHADOW_X_OFFSET,
889 (*fwin->font)->y + TITLEBAR_EXTRA_HEIGHT/2
890 + shadowy + TITLE_TEXT_SHADOW_Y_OFFSET, title,
891 titlelen);
893 #endif /* TITLE_TEXT_SHADOW */
895 XSetForeground(dpy, *fwin->title_gc,
896 fwin->title_pixel[fwin->flags.state]);
898 wDrawString(fwin->titlebar->window, *fwin->font,
899 *fwin->title_gc, x,
900 (*fwin->font)->y + TITLEBAR_EXTRA_HEIGHT/2, title,
901 titlelen);
903 free(title);
905 if (fwin->left_button)
906 handleButtonExpose(&fwin->left_button->descriptor, NULL);
907 if (fwin->right_button)
908 handleButtonExpose(&fwin->right_button->descriptor, NULL);
913 static void
914 reconfigure(WFrameWindow *fwin, int x, int y, int width, int height,
915 Bool dontMove)
917 int k = (wPreferences.new_style ? 4 : 3);
918 int resizedHorizontally = 0;
920 if (dontMove)
921 XResizeWindow(dpy, fwin->core->window, width, height);
922 else
923 XMoveResizeWindow(dpy, fwin->core->window, x, y, width, height);
926 if (fwin->core->height != height && fwin->resizebar)
927 XMoveWindow(dpy, fwin->resizebar->window, 0,
928 height - fwin->resizebar->height);
930 if (fwin->core->width != width) {
931 resizedHorizontally = 1;
934 fwin->core->width = width;
935 fwin->core->height = height;
937 if (fwin->titlebar && resizedHorizontally) {
938 /* Check if the titlebar is wide enough to hold the buttons.
939 * Temporarily remove them if can't
941 if (fwin->left_button) {
942 if (width < fwin->top_width*k && !fwin->flags.lbutton_dont_fit) {
944 if (!fwin->flags.hide_left_button) {
945 XUnmapWindow(dpy, fwin->left_button->window);
947 fwin->flags.lbutton_dont_fit = 1;
948 } else if (width >= fwin->top_width*k && fwin->flags.lbutton_dont_fit) {
950 if (!fwin->flags.hide_left_button) {
951 XMapWindow(dpy, fwin->left_button->window);
953 fwin->flags.lbutton_dont_fit = 0;
957 if (fwin->right_button) {
958 if (width < fwin->top_width*2 && !fwin->flags.rbutton_dont_fit) {
960 if (!fwin->flags.hide_right_button) {
961 XUnmapWindow(dpy, fwin->right_button->window);
963 fwin->flags.rbutton_dont_fit = 1;
964 } else if (width >= fwin->top_width*2 && fwin->flags.rbutton_dont_fit) {
966 if (!fwin->flags.hide_right_button) {
967 XMapWindow(dpy, fwin->right_button->window);
969 fwin->flags.rbutton_dont_fit = 0;
973 if (wPreferences.new_style) {
974 if (fwin->right_button)
975 XMoveWindow(dpy, fwin->right_button->window,
976 width - fwin->right_button->width + 1, 0);
977 } else {
978 if (fwin->right_button)
979 XMoveWindow(dpy, fwin->right_button->window,
980 width - fwin->right_button->width - 3,
981 (fwin->titlebar->height - fwin->right_button->height)/2);
983 updateTitlebar(fwin);
984 checkTitleSize(fwin);
987 if (fwin->resizebar) {
988 wCoreConfigure(fwin->resizebar, 0,
989 fwin->core->height - fwin->resizebar->height,
990 fwin->core->width, fwin->resizebar->height);
992 fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
993 if (fwin->core->width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
994 fwin->resizebar_corner_width = fwin->core->width/2;
1000 void
1001 wFrameWindowConfigure(WFrameWindow *fwin, int x, int y, int width, int height)
1003 reconfigure(fwin, x, y, width, height, False);
1007 void
1008 wFrameWindowResize(WFrameWindow *fwin, int width, int height)
1010 reconfigure(fwin, 0, 0, width, height, True);
1015 int
1016 wFrameWindowChangeTitle(WFrameWindow *fwin, char *new_title)
1018 /* check if the title is the same as before */
1019 if (fwin->title) {
1020 if (new_title && (strcmp(fwin->title, new_title) == 0)) {
1021 return 0;
1023 } else {
1024 if (!new_title)
1025 return 0;
1028 if (fwin->title)
1029 free(fwin->title);
1031 fwin->title = wstrdup(new_title);
1033 if (fwin->titlebar) {
1034 XClearWindow(dpy, fwin->titlebar->window);
1036 wFrameWindowPaint(fwin);
1038 checkTitleSize(fwin);
1040 return 1;
1044 #ifdef OLWM_HINTS
1045 void
1046 wFrameWindowUpdatePushButton(WFrameWindow *fwin, Bool pushed)
1048 fwin->flags.right_button_pushed_in = pushed;
1050 paintButton(fwin->right_button, fwin->title_texture[fwin->flags.state],
1051 fwin->title_pixel[fwin->flags.state],
1052 fwin->rbutton_image, pushed);
1054 #endif /* OLWM_HINTS */
1058 /*********************************************************************/
1060 static void
1061 handleExpose(WObjDescriptor *desc, XEvent *event)
1063 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
1066 if (fwin->titlebar && fwin->titlebar->window == event->xexpose.window)
1067 fwin->flags.repaint_only_titlebar = 1;
1068 if (fwin->resizebar && fwin->resizebar->window == event->xexpose.window)
1069 fwin->flags.repaint_only_resizebar = 1;
1070 wFrameWindowPaint(fwin);
1071 fwin->flags.repaint_only_titlebar = 0;
1072 fwin->flags.repaint_only_resizebar = 0;
1076 static void
1077 checkTitleSize(WFrameWindow *fwin)
1079 int width;
1081 if (!fwin->title) {
1082 fwin->flags.incomplete_title = 0;
1083 return;
1086 if (!fwin->titlebar) {
1087 fwin->flags.incomplete_title = 1;
1088 return;
1089 } else {
1090 width = fwin->titlebar->width - 6 - 6;
1093 if (!wPreferences.new_style) {
1094 if (fwin->left_button && !fwin->flags.hide_left_button
1095 && !fwin->flags.lbutton_dont_fit)
1096 width -= fwin->left_button->width + 3;
1098 if (fwin->right_button && !fwin->flags.hide_right_button
1099 && !fwin->flags.rbutton_dont_fit)
1100 width -= fwin->right_button->width + 3;
1102 if (wTextWidth((*fwin->font)->font, fwin->title,
1103 strlen(fwin->title)) > width) {
1104 fwin->flags.incomplete_title = 1;
1105 } else {
1106 fwin->flags.incomplete_title = 0;
1111 static void
1112 paintButton(WCoreWindow *button, WTexture *texture, unsigned long color,
1113 WPixmap *image, int pushed)
1115 WScreen *scr = button->screen_ptr;
1116 GC copy_gc = scr->copy_gc;
1117 int x=0, y=0, d=0;
1118 int left=0, width=0;
1120 /* setup stuff according to the state */
1121 if (pushed) {
1122 if (image) {
1123 if (image->width>=image->height*2) {
1124 /* the image contains 2 pictures: the second is for the
1125 * pushed state */
1126 width = image->width/2;
1127 left = image->width/2;
1128 } else {
1129 width = image->width;
1132 XSetClipMask(dpy, copy_gc, None);
1133 XSetForeground(dpy, copy_gc, scr->white_pixel);
1134 d=1;
1135 if (wPreferences.new_style) {
1136 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1137 button->width-1, button->height-1);
1138 XSetForeground(dpy, copy_gc, scr->black_pixel);
1139 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
1140 button->width-1, button->height-1);
1141 } else {
1142 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1143 button->width, button->height);
1144 XSetForeground(dpy, copy_gc, scr->black_pixel);
1145 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
1146 button->width, button->height);
1148 } else {
1149 XClearWindow(dpy, button->window);
1151 if (image) {
1152 if (image->width>=image->height*2)
1153 width = image->width/2;
1154 else
1155 width = image->width;
1157 d=0;
1159 if (wPreferences.new_style) {
1160 if (texture->any.type==WTEX_SOLID || pushed) {
1161 wDrawBevel(button->window, button->width, button->height,
1162 (WTexSolid*)texture, WREL_RAISED);
1164 } else {
1165 wDrawBevel(button->window, button->width, button->height,
1166 scr->widget_texture, WREL_RAISED);
1170 if (image) {
1171 /* display image */
1172 XSetClipMask(dpy, copy_gc, image->mask);
1173 x = (button->width - width)/2 + d;
1174 y = (button->height - image->height)/2 + d;
1175 XSetClipOrigin(dpy, copy_gc, x-left, y);
1176 if (!wPreferences.new_style) {
1177 XSetForeground(dpy, copy_gc, scr->black_pixel);
1178 if (!pushed) {
1179 if (image->depth==1)
1180 XCopyPlane(dpy, image->image, button->window, copy_gc,
1181 left, 0, width, image->height, x, y, 1);
1182 else
1183 XCopyArea(dpy, image->image, button->window, copy_gc,
1184 left, 0, width, image->height, x, y);
1185 } else {
1186 XSetForeground(dpy, copy_gc, scr->dark_pixel);
1187 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1188 button->width, button->height);
1190 } else {
1191 if (pushed) {
1192 XSetForeground(dpy, copy_gc, scr->black_pixel);
1193 } else {
1194 XSetForeground(dpy, copy_gc, color);
1195 XSetBackground(dpy, copy_gc, texture->any.color.pixel);
1197 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1198 button->width, button->height);
1204 static void
1205 handleButtonExpose(WObjDescriptor *desc, XEvent *event)
1207 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
1208 WCoreWindow *button = (WCoreWindow*)desc->self;
1210 if (button == fwin->left_button) {
1211 paintButton(button, fwin->title_texture[fwin->flags.state],
1212 fwin->title_pixel[fwin->flags.state],
1213 fwin->lbutton_image, False);
1214 } else {
1215 Bool pushed = False;
1217 #ifdef OLWM_HINTS
1218 if (fwin->flags.right_button_pushed_in)
1219 pushed = True;
1220 #endif
1221 /* emulate the olwm pushpin in the "out" state */
1222 paintButton(button, fwin->title_texture[fwin->flags.state],
1223 fwin->title_pixel[fwin->flags.state],
1224 fwin->rbutton_image, pushed);
1229 static void
1230 titlebarMouseDown(WObjDescriptor *desc, XEvent *event)
1232 WFrameWindow *fwin = desc->parent;
1233 WCoreWindow *titlebar = desc->self;
1235 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1236 if (fwin->on_dblclick_titlebar)
1237 (*fwin->on_dblclick_titlebar)(titlebar, fwin->child, event);
1238 } else {
1239 if (fwin->on_mousedown_titlebar)
1240 (*fwin->on_mousedown_titlebar)(titlebar, fwin->child, event);
1245 static void
1246 resizebarMouseDown(WObjDescriptor *desc, XEvent *event)
1248 WFrameWindow *fwin = desc->parent;
1249 WCoreWindow *resizebar = desc->self;
1251 if (fwin->on_mousedown_resizebar)
1252 (*fwin->on_mousedown_resizebar)(resizebar, fwin->child, event);
1256 static void
1257 buttonMouseDown(WObjDescriptor *desc, XEvent *event)
1259 WFrameWindow *fwin = desc->parent;
1260 WCoreWindow *button = desc->self;
1261 WPixmap *image;
1262 XEvent ev;
1263 int done=0, execute=1;
1264 WTexture *texture;
1265 unsigned long pixel;
1266 int clickButton = event->xbutton.button;
1268 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1269 if (button == fwin->right_button && fwin->on_dblclick_right) {
1270 (*fwin->on_dblclick_right)(button, fwin->child, event);
1272 return;
1275 if (button == fwin->left_button) {
1276 image = fwin->lbutton_image;
1277 } else {
1278 image = fwin->rbutton_image;
1281 pixel = fwin->title_pixel[fwin->flags.state];
1282 texture = fwin->title_texture[fwin->flags.state];
1283 paintButton(button, texture, pixel, image, True);
1285 while (!done) {
1286 WMMaskEvent(dpy, LeaveWindowMask|EnterWindowMask|ButtonReleaseMask
1287 |ButtonPressMask|ExposureMask, &ev);
1288 switch (ev.type) {
1289 case LeaveNotify:
1290 execute = 0;
1291 paintButton(button, texture, pixel, image, False);
1292 break;
1294 case EnterNotify:
1295 execute = 1;
1296 paintButton(button, texture, pixel, image, True);
1297 break;
1299 case ButtonPress:
1300 break;
1302 case ButtonRelease:
1303 if (ev.xbutton.button == clickButton)
1304 done = 1;
1305 break;
1307 default:
1308 WMHandleEvent(&ev);
1311 paintButton(button, texture, pixel, image, False);
1313 if (execute) {
1314 if (button == fwin->left_button) {
1315 if (fwin->on_click_left)
1316 (*fwin->on_click_left)(button, fwin->child, &ev);
1317 } else if (button == fwin->right_button) {
1318 if (fwin->on_click_right)
1319 (*fwin->on_click_right)(button, fwin->child, &ev);