fixed cosmetic bug in geom. dpy window for 8bpp
[wmaker-crm.git] / src / framewin.c
blob2ed11437c812919a5f43137f458d15602858814c
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);
61 WFrameWindow*
62 wFrameWindowCreate(WScreen *scr, int wlevel, int x, int y,
63 int width, int height, int flags,
64 WTexture **title_texture, WTexture **resize_texture,
65 unsigned long *color, GC *gc, WMFont **font)
67 WFrameWindow *fwin;
69 fwin = wmalloc(sizeof(WFrameWindow));
70 memset(fwin, 0, sizeof(WFrameWindow));
72 fwin->screen_ptr = scr;
74 fwin->flags.single_texture = (flags & WFF_SINGLE_STATE) ? 1 : 0;
76 fwin->title_texture = title_texture;
77 fwin->resizebar_texture = resize_texture;
78 fwin->title_pixel = color;
79 fwin->title_gc = gc;
80 fwin->font = font;
82 fwin->core = wCoreCreateTopLevel(scr, x, y, width, height,
83 FRAME_BORDER_WIDTH);
84 if (wPreferences.use_saveunders) {
85 unsigned long vmask;
86 XSetWindowAttributes attribs;
88 vmask = CWSaveUnder;
89 attribs.save_under = True;
90 XChangeWindowAttributes(dpy, fwin->core->window, vmask, &attribs);
93 /* setup stacking information */
94 fwin->core->stacking = wmalloc(sizeof(WStacking));
95 fwin->core->stacking->above = NULL;
96 fwin->core->stacking->under = NULL;
97 fwin->core->stacking->child_of = NULL;
98 fwin->core->stacking->window_level = wlevel;
100 AddToStackList(fwin->core);
102 wFrameWindowUpdateBorders(fwin, flags);
104 return fwin;
109 void
110 wFrameWindowUpdateBorders(WFrameWindow *fwin, int flags)
112 int theight;
113 int bsize;
114 int width, height;
115 int i;
116 WScreen *scr = fwin->screen_ptr;
118 width = fwin->core->width;
119 if (flags & WFF_IS_SHADED)
120 height = -1;
121 else
122 height = fwin->core->height - fwin->top_width - fwin->bottom_width;
124 if (flags & WFF_TITLEBAR)
125 theight = WMFontHeight(*fwin->font) + TITLEBAR_EXTRA_HEIGHT;
126 else
127 theight = 0;
129 if (wPreferences.new_style) {
130 bsize = theight;
131 } else {
132 bsize = theight - 7;
135 if (fwin->titlebar) {
136 /* if we had a titlebar and is requesting for one,
137 * check if the size has changed and resize it */
138 if (flags & WFF_TITLEBAR) {
139 fwin->top_width = theight;
141 fwin->flags.need_texture_remake = 1;
143 if (wPreferences.new_style) {
144 if (fwin->left_button) {
145 wCoreConfigure(fwin->left_button, 0, 0, bsize, bsize);
148 if (fwin->right_button) {
149 wCoreConfigure(fwin->right_button, width-bsize+1,
150 0, bsize, bsize);
152 } else { /* !new_style */
153 if (fwin->left_button) {
154 wCoreConfigure(fwin->left_button, 3, (theight-bsize)/2,
155 bsize, bsize);
158 if (fwin->right_button) {
159 wCoreConfigure(fwin->right_button, width-bsize-3,
160 (theight-bsize)/2, bsize, bsize);
163 updateTitlebar(fwin);
164 } else {
165 /* we had a titlebar, but now we don't need it anymore */
166 for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
167 FREE_PIXMAP(fwin->title_back[i]);
168 if (wPreferences.new_style) {
169 FREE_PIXMAP(fwin->lbutton_back[i]);
170 FREE_PIXMAP(fwin->rbutton_back[i]);
173 if (fwin->left_button)
174 wCoreDestroy(fwin->left_button);
175 fwin->left_button = NULL;
177 if (fwin->right_button)
178 wCoreDestroy(fwin->right_button);
179 fwin->right_button = NULL;
181 wCoreDestroy(fwin->titlebar);
182 fwin->titlebar = NULL;
184 fwin->top_width = 0;
186 } else {
187 /* if we didn't have a titlebar and are being requested for
188 * one, create it */
189 if (flags & WFF_TITLEBAR) {
190 fwin->top_width = theight;
192 fwin->flags.titlebar = 1;
193 fwin->titlebar = wCoreCreate(fwin->core, 0, 0, width+1, theight);
195 if (flags & WFF_LEFT_BUTTON) {
196 fwin->flags.left_button = 1;
197 if (wPreferences.new_style) {
198 fwin->left_button = wCoreCreate(fwin->core, 0, 0,
199 bsize, bsize);
200 if (width < theight*4) {
201 fwin->flags.lbutton_dont_fit = 1;
202 } else {
203 XMapRaised(dpy, fwin->left_button->window);
205 } else {
206 fwin->left_button =
207 wCoreCreate(fwin->titlebar, 3, (theight-bsize)/2,
208 bsize, bsize);
210 XSetWindowBackground(dpy, fwin->left_button->window,
211 scr->widget_texture->normal.pixel);
213 if (width < theight*3) {
214 fwin->flags.lbutton_dont_fit = 1;
215 } else {
216 XMapRaised(dpy, fwin->left_button->window);
222 if (flags & WFF_RIGHT_BUTTON) {
223 fwin->flags.right_button = 1;
224 if (wPreferences.new_style) {
225 fwin->right_button =
226 wCoreCreate(fwin->core, width-bsize+1, 0,
227 bsize, bsize);
228 } else {
229 fwin->right_button =
230 wCoreCreate(fwin->titlebar, width-bsize-3,
231 (theight-bsize)/2, bsize, bsize);
232 XSetWindowBackground(dpy, fwin->right_button->window,
233 scr->widget_texture->normal.pixel);
236 if (width < theight*2) {
237 fwin->flags.rbutton_dont_fit = 1;
238 } else {
239 XMapRaised(dpy, fwin->right_button->window);
243 if (wPreferences.new_style)
244 updateTitlebar(fwin);
246 XMapRaised(dpy, fwin->titlebar->window);
248 fwin->flags.need_texture_remake = 1;
251 checkTitleSize(fwin);
253 if (flags & WFF_RESIZEBAR) {
254 fwin->bottom_width = RESIZEBAR_HEIGHT;
255 } else {
256 fwin->bottom_width = 0;
259 if (flags & WFF_RESIZEBAR) {
260 if (!fwin->resizebar) {
261 fwin->flags.resizebar = 1;
262 fwin->resizebar = wCoreCreate(fwin->core, 0,
263 height + fwin->top_width,
264 width, RESIZEBAR_HEIGHT);
265 fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
266 if (width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
267 fwin->resizebar_corner_width = (width - RESIZEBAR_MIN_WIDTH)/2;
268 if (fwin->resizebar_corner_width < 0)
269 fwin->resizebar_corner_width = 0;
272 XMapWindow(dpy, fwin->resizebar->window);
273 XLowerWindow(dpy, fwin->resizebar->window);
275 fwin->flags.need_texture_remake = 1;
276 } else {
277 if (height+fwin->top_width+fwin->bottom_width != fwin->core->height) {
278 wCoreConfigure(fwin->resizebar, 0, height + fwin->top_width,
279 width, RESIZEBAR_HEIGHT);
282 } else {
283 if (fwin->resizebar) {
284 fwin->bottom_width = 0;
285 wCoreDestroy(fwin->resizebar);
286 fwin->resizebar = NULL;
290 if (height + fwin->top_width + fwin->bottom_width != fwin->core->height
291 && !(flags & WFF_IS_SHADED)) {
292 wFrameWindowResize(fwin, width,
293 height + fwin->top_width + fwin->bottom_width);
296 /* setup object descriptors */
298 if (fwin->titlebar) {
299 fwin->titlebar->descriptor.handle_expose = handleExpose;
300 fwin->titlebar->descriptor.parent = fwin;
301 fwin->titlebar->descriptor.parent_type = WCLASS_FRAME;
302 fwin->titlebar->descriptor.handle_mousedown = titlebarMouseDown;
305 if (fwin->resizebar) {
306 fwin->resizebar->descriptor.handle_expose = handleExpose;
307 fwin->resizebar->descriptor.parent = fwin;
308 fwin->resizebar->descriptor.parent_type = WCLASS_FRAME;
309 fwin->resizebar->descriptor.handle_mousedown = resizebarMouseDown;
312 if (fwin->left_button) {
313 fwin->left_button->descriptor.handle_expose = handleButtonExpose;
314 fwin->left_button->descriptor.parent = fwin;
315 fwin->left_button->descriptor.parent_type = WCLASS_FRAME;
316 fwin->left_button->descriptor.handle_mousedown = buttonMouseDown;
319 if (fwin->right_button) {
320 fwin->right_button->descriptor.parent = fwin;
321 fwin->right_button->descriptor.parent_type = WCLASS_FRAME;
322 fwin->right_button->descriptor.handle_expose = handleButtonExpose;
323 fwin->right_button->descriptor.handle_mousedown = buttonMouseDown;
326 checkTitleSize(fwin);
331 void
332 wFrameWindowDestroy(WFrameWindow *fwin)
334 int i;
336 if (fwin->left_button)
337 wCoreDestroy(fwin->left_button);
339 if (fwin->right_button)
340 wCoreDestroy(fwin->right_button);
342 if (fwin->resizebar)
343 wCoreDestroy(fwin->resizebar);
345 if (fwin->titlebar)
346 wCoreDestroy(fwin->titlebar);
348 RemoveFromStackList(fwin->core);
350 wCoreDestroy(fwin->core);
352 if (fwin->title)
353 free(fwin->title);
355 for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
356 FREE_PIXMAP(fwin->title_back[i]);
357 if (wPreferences.new_style) {
358 FREE_PIXMAP(fwin->lbutton_back[i]);
359 FREE_PIXMAP(fwin->rbutton_back[i]);
363 free(fwin);
367 void
368 wFrameWindowChangeState(WFrameWindow *fwin, int state)
370 if (fwin->flags.state==state)
371 return;
373 fwin->flags.state = state;
374 fwin->flags.need_texture_change = 1;
376 wFrameWindowPaint(fwin);
380 static void
381 updateTitlebar(WFrameWindow *fwin)
383 int x, w;
384 int theight;
386 theight = WMFontHeight(*fwin->font) + TITLEBAR_EXTRA_HEIGHT;
388 x = 0;
389 w = fwin->core->width + 1;
391 if (wPreferences.new_style) {
392 if (fwin->flags.hide_left_button || !fwin->left_button
393 || fwin->flags.lbutton_dont_fit) {
394 x = 0;
395 } else {
396 x = fwin->left_button->width;
397 w -= fwin->left_button->width;
401 if (wPreferences.new_style) {
402 if (!fwin->flags.hide_right_button && fwin->right_button
403 && !fwin->flags.rbutton_dont_fit) {
404 w -= fwin->right_button->width;
408 if (wPreferences.new_style || fwin->titlebar->width!=w)
409 fwin->flags.need_texture_remake = 1;
411 wCoreConfigure(fwin->titlebar, x, 0, w, theight);
415 void
416 wFrameWindowHideButton(WFrameWindow *fwin, int flags)
418 if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button) {
419 XUnmapWindow(dpy, fwin->right_button->window);
420 fwin->flags.hide_right_button = 1;
423 if ((flags & WFF_LEFT_BUTTON) && fwin->left_button) {
424 XUnmapWindow(dpy, fwin->left_button->window);
425 fwin->flags.hide_left_button = 1;
428 if (fwin->titlebar) {
429 if (wPreferences.new_style) {
430 updateTitlebar(fwin);
431 } else {
432 XClearWindow(dpy, fwin->titlebar->window);
433 wFrameWindowPaint(fwin);
435 checkTitleSize(fwin);
440 void
441 wFrameWindowShowButton(WFrameWindow *fwin, int flags)
443 if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button
444 && fwin->flags.hide_right_button) {
446 if (!fwin->flags.rbutton_dont_fit)
447 XMapWindow(dpy, fwin->right_button->window);
449 fwin->flags.hide_right_button = 0;
452 if ((flags & WFF_LEFT_BUTTON) && fwin->left_button
453 && fwin->flags.hide_left_button) {
455 if (!fwin->flags.lbutton_dont_fit)
456 XMapWindow(dpy, fwin->left_button->window);
458 fwin->flags.hide_left_button = 0;
462 if (fwin->titlebar) {
463 if (wPreferences.new_style) {
464 updateTitlebar(fwin);
465 } else {
466 XClearWindow(dpy, fwin->titlebar->window);
467 wFrameWindowPaint(fwin);
469 checkTitleSize(fwin);
474 static void
475 renderTexture(WScreen *scr, WTexture *texture, int width, int height,
476 int bwidth, int bheight, int left, int right,
477 Pixmap *title, Pixmap *lbutton, Pixmap *rbutton)
479 RImage *img;
480 RImage *limg, *rimg, *mimg;
481 int x, w;
483 *title = None;
484 *lbutton = None;
485 *rbutton = None;
487 img = wTextureRenderImage(texture, width, height, WREL_FLAT);
488 if (!img) {
489 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
490 return;
493 if (wPreferences.new_style) {
494 if (left) {
495 limg = RGetSubImage(img, 0, 0, bwidth, bheight);
496 } else
497 limg = NULL;
499 x = 0;
500 w = img->width;
502 if (limg) {
503 RBevelImage(limg, RBEV_RAISED2);
504 if (!RConvertImage(scr->rcontext, limg, lbutton)) {
505 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
507 x += limg->width;
508 w -= limg->width;
509 RDestroyImage(limg);
512 if (right) {
513 rimg = RGetSubImage(img, width - bwidth, 0, bwidth, bheight);
514 } else
515 rimg = NULL;
517 if (rimg) {
518 RBevelImage(rimg, RBEV_RAISED2);
519 if (!RConvertImage(scr->rcontext, rimg, rbutton)) {
520 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
522 w -= rimg->width;
523 RDestroyImage(rimg);
526 if (w!=width) {
527 mimg = RGetSubImage(img, x, 0, w, img->height);
528 RBevelImage(mimg, RBEV_RAISED2);
530 if (!RConvertImage(scr->rcontext, mimg, title)) {
531 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
533 RDestroyImage(mimg);
534 } else {
535 RBevelImage(img, RBEV_RAISED2);
537 if (!RConvertImage(scr->rcontext, img, title)) {
538 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
541 } else {
542 RBevelImage(img, RBEV_RAISED2);
544 if (!RConvertImage(scr->rcontext, img, title)) {
545 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
549 RDestroyImage(img);
553 static void
554 renderResizebarTexture(WScreen *scr, WTexture *texture, int width, int height,
555 int cwidth, Pixmap *pmap)
557 RImage *img;
558 RColor light;
559 RColor dark;
561 *pmap = None;
563 img = wTextureRenderImage(texture, width, height, WREL_FLAT);
564 if (!img) {
565 wwarning(_("could not render texture: %s"),
566 RMessageForError(RErrorCode));
567 return;
570 light.alpha = 0;
571 light.red = light.green = light.blue = 80;
573 dark.alpha = 0;
574 dark.red = dark.green = dark.blue = 40;
576 ROperateLine(img, RSubtractOperation, 0, 0, width-1, 0, &dark);
577 ROperateLine(img, RAddOperation, 0, 1, width-1, 1, &light);
579 ROperateLine(img, RSubtractOperation, cwidth, 2, cwidth, height-1, &dark);
580 ROperateLine(img, RAddOperation, cwidth+1, 2, cwidth+1, height-1, &light);
582 if (width > 1)
583 ROperateLine(img, RSubtractOperation, width-cwidth-2, 2,
584 width-cwidth-2, height-1, &dark);
585 ROperateLine(img, RAddOperation, width-cwidth-1, 2, width-cwidth-1,
586 height-1, &light);
588 #ifdef SHADOW_RESIZEBAR
589 ROperateLine(img, RAddOperation, 0, 1, 0, height-1, &light);
590 ROperateLine(img, RSubtractOperation, width-1, 1, width-1, height-1,
591 &dark);
592 ROperateLine(img, RSubtractOperation, 0, height-1, width-1, height-1,
593 &dark);
594 #endif /* SHADOW_RESIZEBAR */
597 if (!RConvertImage(scr->rcontext, img, pmap)) {
598 wwarning(_("error rendering image: %s"), RMessageForError(RErrorCode));
601 RDestroyImage(img);
606 static void
607 updateTexture(WFrameWindow *fwin)
609 int i;
610 unsigned long pixel;
612 i = fwin->flags.state;
613 if (fwin->titlebar) {
614 if (fwin->title_texture[i]->any.type!=WTEX_SOLID) {
615 XSetWindowBackgroundPixmap(dpy, fwin->titlebar->window,
616 fwin->title_back[i]);
617 if (wPreferences.new_style) {
618 if (fwin->left_button && fwin->lbutton_back[i])
619 XSetWindowBackgroundPixmap(dpy, fwin->left_button->window,
620 fwin->lbutton_back[i]);
622 if (fwin->right_button && fwin->rbutton_back[i])
623 XSetWindowBackgroundPixmap(dpy, fwin->right_button->window,
624 fwin->rbutton_back[i]);
626 } else {
627 pixel = fwin->title_texture[i]->solid.normal.pixel;
628 XSetWindowBackground(dpy, fwin->titlebar->window, pixel);
629 if (wPreferences.new_style) {
630 if (fwin->left_button)
631 XSetWindowBackground(dpy, fwin->left_button->window,
632 pixel);
633 if (fwin->right_button)
634 XSetWindowBackground(dpy, fwin->right_button->window,
635 pixel);
638 XClearWindow(dpy, fwin->titlebar->window);
640 if (fwin->left_button) {
641 XClearWindow(dpy, fwin->left_button->window);
642 handleButtonExpose(&fwin->left_button->descriptor, NULL);
644 if (fwin->right_button) {
645 XClearWindow(dpy, fwin->right_button->window);
646 handleButtonExpose(&fwin->right_button->descriptor, NULL);
653 static void
654 remakeTexture(WFrameWindow *fwin, int state)
656 Pixmap pmap, lpmap, rpmap;
658 if (fwin->title_texture[state] && fwin->titlebar) {
659 FREE_PIXMAP(fwin->title_back[state]);
660 if (wPreferences.new_style) {
661 FREE_PIXMAP(fwin->lbutton_back[state]);
662 FREE_PIXMAP(fwin->rbutton_back[state]);
665 if (fwin->title_texture[state]->any.type!=WTEX_SOLID) {
666 int left, right;
667 int width;
669 /* eventually surrounded by if new_style */
670 left = fwin->left_button && !fwin->flags.hide_left_button
671 && !fwin->flags.lbutton_dont_fit;
672 right = fwin->right_button && !fwin->flags.hide_right_button
673 && !fwin->flags.rbutton_dont_fit;
675 width = fwin->core->width+1;
677 renderTexture(fwin->screen_ptr, fwin->title_texture[state],
678 width, fwin->titlebar->height,
679 fwin->titlebar->height, fwin->titlebar->height,
680 left, right, &pmap, &lpmap, &rpmap);
682 fwin->title_back[state] = pmap;
683 if (wPreferences.new_style) {
684 fwin->lbutton_back[state] = lpmap;
685 fwin->rbutton_back[state] = rpmap;
689 if (fwin->resizebar_texture && fwin->resizebar_texture[0]
690 && fwin->resizebar && state == 0) {
692 FREE_PIXMAP(fwin->resizebar_back[0]);
694 if (fwin->resizebar_texture[0]->any.type!=WTEX_SOLID) {
696 renderResizebarTexture(fwin->screen_ptr,
697 fwin->resizebar_texture[0],
698 fwin->resizebar->width,
699 fwin->resizebar->height,
700 fwin->resizebar_corner_width,
701 &pmap);
703 fwin->resizebar_back[0] = pmap;
706 /* this part should be in updateTexture() */
707 if (fwin->resizebar_texture[0]->any.type!=WTEX_SOLID) {
708 XSetWindowBackgroundPixmap(dpy, fwin->resizebar->window,
709 fwin->resizebar_back[0]);
710 } else {
711 XSetWindowBackground(dpy, fwin->resizebar->window,
712 fwin->resizebar_texture[0]->solid.normal.pixel);
714 XClearWindow(dpy, fwin->resizebar->window);
719 void
720 wFrameWindowPaint(WFrameWindow *fwin)
722 if (fwin->flags.is_client_window_frame)
723 fwin->flags.justification = wPreferences.title_justification;
725 if (fwin->flags.need_texture_remake) {
726 int i;
728 fwin->flags.need_texture_remake = 0;
729 fwin->flags.need_texture_change = 0;
731 if (fwin->flags.single_texture) {
732 remakeTexture(fwin, 0);
733 updateTexture(fwin);
734 } else {
735 /* first render the texture for the current state... */
736 remakeTexture(fwin, fwin->flags.state);
737 /* ... and paint it */
738 updateTexture(fwin);
740 for (i=0; i < 3; i++) {
741 if (i!=fwin->flags.state)
742 remakeTexture(fwin, i);
747 if (fwin->flags.need_texture_change) {
748 fwin->flags.need_texture_change = 0;
750 updateTexture(fwin);
753 if (fwin->titlebar && !fwin->flags.repaint_only_resizebar
754 && fwin->title_texture[fwin->flags.state]->any.type==WTEX_SOLID) {
755 wDrawBevel(fwin->titlebar->window, fwin->titlebar->width,
756 fwin->titlebar->height,
757 (WTexSolid*)fwin->title_texture[fwin->flags.state],
758 WREL_RAISED);
761 if (fwin->resizebar && !fwin->flags.repaint_only_titlebar
762 && fwin->resizebar_texture[0]->any.type == WTEX_SOLID) {
763 Window win;
764 int w, h;
765 int cw;
766 GC light_gc, dim_gc;
767 WTexSolid *texture = (WTexSolid*)fwin->resizebar_texture[0];
769 w = fwin->resizebar->width;
770 h = fwin->resizebar->height;
771 cw = fwin->resizebar_corner_width;
772 light_gc = texture->light_gc;
773 dim_gc = texture->dim_gc;
774 win = fwin->resizebar->window;
776 XDrawLine(dpy, win, dim_gc, 0, 0, w, 0);
777 XDrawLine(dpy, win, light_gc, 0, 1, w, 1);
779 XDrawLine(dpy, win, dim_gc, cw, 2, cw, h);
780 XDrawLine(dpy, win, light_gc, cw+1, 2, cw+1, h);
782 XDrawLine(dpy, win, dim_gc, w-cw-2, 2, w-cw-2, h);
783 XDrawLine(dpy, win, light_gc, w-cw-1, 2, w-cw-1, h);
785 #ifdef SHADOW_RESIZEBAR
786 XDrawLine(dpy, win, light_gc, 0, 1, 0, h-1);
787 XDrawLine(dpy, win, dim_gc, w-1, 2, w-1, h-1);
788 XDrawLine(dpy, win, dim_gc, 1, h-1, cw, h-1);
789 XDrawLine(dpy, win, dim_gc, cw+2, h-1, w-cw-2, h-1);
790 XDrawLine(dpy, win, dim_gc, w-cw, h-1, w-1, h-1);
791 #endif /* SHADOW_RESIZEBAR */
795 if (fwin->title && fwin->titlebar && !fwin->flags.repaint_only_resizebar) {
796 int x, w;
797 int lofs = 6, rofs = 6;
798 int titlelen;
799 char *title;
800 int allButtons = 1;
801 WScreen *scr = fwin->screen_ptr;
804 if (!wPreferences.new_style) {
805 if (fwin->left_button && !fwin->flags.hide_left_button
806 && !fwin->flags.lbutton_dont_fit)
807 lofs += fwin->left_button->width + 3;
808 else
809 allButtons = 0;
811 if (fwin->right_button && !fwin->flags.hide_right_button
812 && !fwin->flags.rbutton_dont_fit)
813 rofs += fwin->right_button->width + 3;
814 else
815 allButtons = 0;
818 #ifdef XKB_TITLE_HINT
819 if(fwin->flags.is_client_window_frame) {
820 char * freebuff;
821 freebuff = (char *)wmalloc((strlen(fwin->title)+6)*sizeof(char));
822 if (fwin->flags.justification == WTJ_RIGHT)
823 sprintf(freebuff,"%s %s",fwin->title,fwin->languagemode?XKB_ON:XKB_OFF);
824 else
825 sprintf(freebuff,"%s %s",fwin->languagemode?XKB_ON:XKB_OFF,fwin->title);
826 title = ShrinkString(*fwin->font, freebuff,
827 fwin->titlebar->width - lofs - rofs);
828 free(freebuff);
830 else title = ShrinkString(*fwin->font, fwin->title,
831 fwin->titlebar->width - lofs - rofs);
832 #else
833 title = ShrinkString(*fwin->font, fwin->title,
834 fwin->titlebar->width - lofs - rofs);
835 #endif /* XKB_TITLE_HINT */
836 titlelen = strlen(title);
837 w = WMWidthOfString(*fwin->font, title, titlelen);
839 switch (fwin->flags.justification) {
840 case WTJ_LEFT:
841 x = lofs;
842 break;
844 case WTJ_RIGHT:
845 x = fwin->titlebar->width - w - rofs;
846 break;
848 default:
849 if (!allButtons)
850 x = lofs + (fwin->titlebar->width - w - lofs - rofs) / 2;
851 else
852 x = (fwin->titlebar->width - w) / 2;
853 break;
856 #ifdef TITLE_TEXT_SHADOW
857 if(wPreferences.title_shadow){
858 int shadowx,shadowy;
859 XSetForeground(dpy, *fwin->title_gc,
860 fwin->title_pixel[fwin->flags.state+3]);
861 for(shadowx=0;shadowx<TITLE_TEXT_SHADOW_WIDTH;shadowx++)
862 for(shadowy=0;shadowy<TITLE_TEXT_SHADOW_HEIGHT;shadowy++)
863 WMDrawString(scr->wmscreen, fwin->titlebar->window,
864 *fwin->title_gc, *fwin->font,
865 x + shadowx + TITLE_TEXT_SHADOW_X_OFFSET,
866 TITLEBAR_EXTRA_HEIGHT/2
867 + shadowy + TITLE_TEXT_SHADOW_Y_OFFSET, title,
868 titlelen);
870 #endif /* TITLE_TEXT_SHADOW */
872 XSetForeground(dpy, *fwin->title_gc,
873 fwin->title_pixel[fwin->flags.state]);
875 WMDrawString(scr->wmscreen, fwin->titlebar->window, *fwin->title_gc,
876 *fwin->font, x, TITLEBAR_EXTRA_HEIGHT/2, title, titlelen);
878 free(title);
880 if (fwin->left_button)
881 handleButtonExpose(&fwin->left_button->descriptor, NULL);
882 if (fwin->right_button)
883 handleButtonExpose(&fwin->right_button->descriptor, NULL);
888 static void
889 reconfigure(WFrameWindow *fwin, int x, int y, int width, int height,
890 Bool dontMove)
892 int k = (wPreferences.new_style ? 4 : 3);
893 int resizedHorizontally = 0;
895 if (dontMove)
896 XResizeWindow(dpy, fwin->core->window, width, height);
897 else
898 XMoveResizeWindow(dpy, fwin->core->window, x, y, width, height);
901 if (fwin->core->height != height && fwin->resizebar)
902 XMoveWindow(dpy, fwin->resizebar->window, 0,
903 height - fwin->resizebar->height);
905 if (fwin->core->width != width) {
906 fwin->flags.need_texture_remake = 1;
907 resizedHorizontally = 1;
910 fwin->core->width = width;
911 fwin->core->height = height;
913 if (fwin->titlebar && resizedHorizontally) {
914 /* Check if the titlebar is wide enough to hold the buttons.
915 * Temporarily remove them if can't
917 if (fwin->left_button) {
918 if (width < fwin->top_width*k && !fwin->flags.lbutton_dont_fit) {
920 if (!fwin->flags.hide_left_button) {
921 XUnmapWindow(dpy, fwin->left_button->window);
923 fwin->flags.lbutton_dont_fit = 1;
924 } else if (width >= fwin->top_width*k && fwin->flags.lbutton_dont_fit) {
926 if (!fwin->flags.hide_left_button) {
927 XMapWindow(dpy, fwin->left_button->window);
929 fwin->flags.lbutton_dont_fit = 0;
933 if (fwin->right_button) {
934 if (width < fwin->top_width*2 && !fwin->flags.rbutton_dont_fit) {
936 if (!fwin->flags.hide_right_button) {
937 XUnmapWindow(dpy, fwin->right_button->window);
939 fwin->flags.rbutton_dont_fit = 1;
940 } else if (width >= fwin->top_width*2 && fwin->flags.rbutton_dont_fit) {
942 if (!fwin->flags.hide_right_button) {
943 XMapWindow(dpy, fwin->right_button->window);
945 fwin->flags.rbutton_dont_fit = 0;
949 if (wPreferences.new_style) {
950 if (fwin->right_button)
951 XMoveWindow(dpy, fwin->right_button->window,
952 width - fwin->right_button->width + 1, 0);
953 } else {
954 if (fwin->right_button)
955 XMoveWindow(dpy, fwin->right_button->window,
956 width - fwin->right_button->width - 3,
957 (fwin->titlebar->height - fwin->right_button->height)/2);
959 updateTitlebar(fwin);
960 checkTitleSize(fwin);
963 if (fwin->resizebar) {
964 wCoreConfigure(fwin->resizebar, 0,
965 fwin->core->height - fwin->resizebar->height,
966 fwin->core->width, fwin->resizebar->height);
968 fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
969 if (fwin->core->width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
970 fwin->resizebar_corner_width = fwin->core->width/2;
975 void
976 wFrameWindowConfigure(WFrameWindow *fwin, int x, int y, int width, int height)
978 reconfigure(fwin, x, y, width, height, False);
981 void
982 wFrameWindowResize(WFrameWindow *fwin, int width, int height)
984 reconfigure(fwin, 0, 0, width, height, True);
989 int
990 wFrameWindowChangeTitle(WFrameWindow *fwin, char *new_title)
992 /* check if the title is the same as before */
993 if (fwin->title) {
994 if (new_title && (strcmp(fwin->title, new_title) == 0)) {
995 return 0;
997 } else {
998 if (!new_title)
999 return 0;
1002 if (fwin->title)
1003 free(fwin->title);
1005 fwin->title = wstrdup(new_title);
1007 if (fwin->titlebar) {
1008 XClearWindow(dpy, fwin->titlebar->window);
1010 wFrameWindowPaint(fwin);
1012 checkTitleSize(fwin);
1014 return 1;
1018 #ifdef OLWM_HINTS
1019 void
1020 wFrameWindowUpdatePushButton(WFrameWindow *fwin, Bool pushed)
1022 fwin->flags.right_button_pushed_in = pushed;
1024 paintButton(fwin->right_button, fwin->title_texture[fwin->flags.state],
1025 fwin->title_pixel[fwin->flags.state],
1026 fwin->rbutton_image, pushed);
1028 #endif /* OLWM_HINTS */
1032 /*********************************************************************/
1034 static void
1035 handleExpose(WObjDescriptor *desc, XEvent *event)
1037 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
1040 if (fwin->titlebar && fwin->titlebar->window == event->xexpose.window)
1041 fwin->flags.repaint_only_titlebar = 1;
1042 if (fwin->resizebar && fwin->resizebar->window == event->xexpose.window)
1043 fwin->flags.repaint_only_resizebar = 1;
1044 wFrameWindowPaint(fwin);
1045 fwin->flags.repaint_only_titlebar = 0;
1046 fwin->flags.repaint_only_resizebar = 0;
1050 static void
1051 checkTitleSize(WFrameWindow *fwin)
1053 int width;
1055 if (!fwin->title) {
1056 fwin->flags.incomplete_title = 0;
1057 return;
1060 if (!fwin->titlebar) {
1061 fwin->flags.incomplete_title = 1;
1062 return;
1063 } else {
1064 width = fwin->titlebar->width - 6 - 6;
1067 if (!wPreferences.new_style) {
1068 if (fwin->left_button && !fwin->flags.hide_left_button
1069 && !fwin->flags.lbutton_dont_fit)
1070 width -= fwin->left_button->width + 3;
1072 if (fwin->right_button && !fwin->flags.hide_right_button
1073 && !fwin->flags.rbutton_dont_fit)
1074 width -= fwin->right_button->width + 3;
1076 if (WMWidthOfString(*fwin->font, fwin->title, strlen(fwin->title)) > width) {
1077 fwin->flags.incomplete_title = 1;
1078 } else {
1079 fwin->flags.incomplete_title = 0;
1084 static void
1085 paintButton(WCoreWindow *button, WTexture *texture, unsigned long color,
1086 WPixmap *image, int pushed)
1088 WScreen *scr = button->screen_ptr;
1089 GC copy_gc = scr->copy_gc;
1090 int x=0, y=0, d=0;
1091 int left=0, width=0;
1093 /* setup stuff according to the state */
1094 if (pushed) {
1095 if (image) {
1096 if (image->width>=image->height*2) {
1097 /* the image contains 2 pictures: the second is for the
1098 * pushed state */
1099 width = image->width/2;
1100 left = image->width/2;
1101 } else {
1102 width = image->width;
1105 XSetClipMask(dpy, copy_gc, None);
1106 XSetForeground(dpy, copy_gc, scr->white_pixel);
1107 d=1;
1108 if (wPreferences.new_style) {
1109 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1110 button->width-1, button->height-1);
1111 XSetForeground(dpy, copy_gc, scr->black_pixel);
1112 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
1113 button->width-1, button->height-1);
1114 } else {
1115 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1116 button->width, button->height);
1117 XSetForeground(dpy, copy_gc, scr->black_pixel);
1118 XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
1119 button->width, button->height);
1121 } else {
1122 XClearWindow(dpy, button->window);
1124 if (image) {
1125 if (image->width>=image->height*2)
1126 width = image->width/2;
1127 else
1128 width = image->width;
1130 d=0;
1132 if (wPreferences.new_style) {
1133 if (texture->any.type==WTEX_SOLID || pushed) {
1134 wDrawBevel(button->window, button->width, button->height,
1135 (WTexSolid*)texture, WREL_RAISED);
1137 } else {
1138 wDrawBevel(button->window, button->width, button->height,
1139 scr->widget_texture, WREL_RAISED);
1143 if (image) {
1144 /* display image */
1145 XSetClipMask(dpy, copy_gc, image->mask);
1146 x = (button->width - width)/2 + d;
1147 y = (button->height - image->height)/2 + d;
1148 XSetClipOrigin(dpy, copy_gc, x-left, y);
1149 if (!wPreferences.new_style) {
1150 XSetForeground(dpy, copy_gc, scr->black_pixel);
1151 if (!pushed) {
1152 if (image->depth==1)
1153 XCopyPlane(dpy, image->image, button->window, copy_gc,
1154 left, 0, width, image->height, x, y, 1);
1155 else
1156 XCopyArea(dpy, image->image, button->window, copy_gc,
1157 left, 0, width, image->height, x, y);
1158 } else {
1159 XSetForeground(dpy, copy_gc, scr->dark_pixel);
1160 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1161 button->width, button->height);
1163 } else {
1164 if (pushed) {
1165 XSetForeground(dpy, copy_gc, scr->black_pixel);
1166 } else {
1167 XSetForeground(dpy, copy_gc, color);
1168 XSetBackground(dpy, copy_gc, texture->any.color.pixel);
1170 XFillRectangle(dpy, button->window, copy_gc, 0, 0,
1171 button->width, button->height);
1177 static void
1178 handleButtonExpose(WObjDescriptor *desc, XEvent *event)
1180 WFrameWindow *fwin = (WFrameWindow*)desc->parent;
1181 WCoreWindow *button = (WCoreWindow*)desc->self;
1183 if (button == fwin->left_button) {
1184 paintButton(button, fwin->title_texture[fwin->flags.state],
1185 fwin->title_pixel[fwin->flags.state],
1186 fwin->lbutton_image, False);
1187 } else {
1188 Bool pushed = False;
1190 #ifdef OLWM_HINTS
1191 if (fwin->flags.right_button_pushed_in)
1192 pushed = True;
1193 #endif
1194 /* emulate the olwm pushpin in the "out" state */
1195 paintButton(button, fwin->title_texture[fwin->flags.state],
1196 fwin->title_pixel[fwin->flags.state],
1197 fwin->rbutton_image, pushed);
1202 static void
1203 titlebarMouseDown(WObjDescriptor *desc, XEvent *event)
1205 WFrameWindow *fwin = desc->parent;
1206 WCoreWindow *titlebar = desc->self;
1208 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1209 if (fwin->on_dblclick_titlebar)
1210 (*fwin->on_dblclick_titlebar)(titlebar, fwin->child, event);
1211 } else {
1212 if (fwin->on_mousedown_titlebar)
1213 (*fwin->on_mousedown_titlebar)(titlebar, fwin->child, event);
1218 static void
1219 resizebarMouseDown(WObjDescriptor *desc, XEvent *event)
1221 WFrameWindow *fwin = desc->parent;
1222 WCoreWindow *resizebar = desc->self;
1224 if (fwin->on_mousedown_resizebar)
1225 (*fwin->on_mousedown_resizebar)(resizebar, fwin->child, event);
1229 static void
1230 buttonMouseDown(WObjDescriptor *desc, XEvent *event)
1232 WFrameWindow *fwin = desc->parent;
1233 WCoreWindow *button = desc->self;
1234 WPixmap *image;
1235 XEvent ev;
1236 int done=0, execute=1;
1237 WTexture *texture;
1238 unsigned long pixel;
1239 int clickButton = event->xbutton.button;
1241 if (IsDoubleClick(fwin->core->screen_ptr, event)) {
1242 if (button == fwin->right_button && fwin->on_dblclick_right) {
1243 (*fwin->on_dblclick_right)(button, fwin->child, event);
1245 return;
1248 if (button == fwin->left_button) {
1249 image = fwin->lbutton_image;
1250 } else {
1251 image = fwin->rbutton_image;
1254 pixel = fwin->title_pixel[fwin->flags.state];
1255 texture = fwin->title_texture[fwin->flags.state];
1256 paintButton(button, texture, pixel, image, True);
1258 while (!done) {
1259 WMMaskEvent(dpy, LeaveWindowMask|EnterWindowMask|ButtonReleaseMask
1260 |ButtonPressMask|ExposureMask, &ev);
1261 switch (ev.type) {
1262 case LeaveNotify:
1263 execute = 0;
1264 paintButton(button, texture, pixel, image, False);
1265 break;
1267 case EnterNotify:
1268 execute = 1;
1269 paintButton(button, texture, pixel, image, True);
1270 break;
1272 case ButtonPress:
1273 break;
1275 case ButtonRelease:
1276 if (ev.xbutton.button == clickButton)
1277 done = 1;
1278 break;
1280 default:
1281 WMHandleEvent(&ev);
1284 paintButton(button, texture, pixel, image, False);
1286 if (execute) {
1287 if (button == fwin->left_button) {
1288 if (fwin->on_click_left)
1289 (*fwin->on_click_left)(button, fwin->child, &ev);
1290 } else if (button == fwin->right_button) {
1291 if (fwin->on_click_right)
1292 (*fwin->on_click_right)(button, fwin->child, &ev);