1
0
mirror of https://github.com/gryf/wmaker.git synced 2026-04-26 02:21:27 +02:00
Files
wmaker/src/framewin.c
T
dan 36e46831e0 For libwraster:
---------------

- Added retain/release mechanism to RImage by adding RRetainImage() and
  RReleaseImage(). RDestroyImage() is an alias to RReleaseImage() now, but
  will be removed in a future release because it no longer fits with the
  semantics. Will be kept for a while to allow a smoother transition.
  More about in wrlib/NEWS


For WINGs:
----------

- Small API change:
  1. Renamed WMSetApplicationIconImage(), WMGetApplicationIconImage() and
     WMSetWindowMiniwindowImage() to respectively WMSetApplicationIconPixmap(),
     WMGetApplicationIconPixmap() and WMSetWindowMiniwindowPixmap()
     They operate on a WMPixmap which is practically an X Pixmap with no alpha
     channel information and the new name is more suggestive and also leaves
     room for the new functions added for operating on images with alpha info.
  2. Added WMSetApplicationIconImage() and WMGetApplicationIconImage() which
     operate on an RImage and store alpha information too.
  3. Added WMGetApplicationIconBlendedPixmap() which will take the image with
     alpha set by WMSetApplicationIconImage() and will blend it with a color.
     If color is NULL it will blend using the default panel color (#aeaaae)
  All these changes will allow WINGs to handle images with alpha blending
  correctly in panels and wherever else needed. More about in WINGs/NEWS.
- updated panels to use the newly available RImages if present and fallback
  to old WMPixmaps if not, to properly show alpha blended images.
- replaced some still left malloc's with wmalloc's.


For Window Maker:
-----------------
- Fixed wrong mapping position of the "Docked Applications Panel" for some
  icons.
- Smoother animation for the smiley =)
- Made images with alpha blending be shown correctly in the panels and the
  icon chooser.
- The icon image set to be shown in panels ("Logo.WMPanel") will be
  automatically updated if its entry in WMWindowAttributes changes (without
  a need to restart as until now).


*** Note!!! ***

If you are developing applications with one of libwraster or libWINGs
then you should look to wrlib/NEWS and WINGs/NEWS to see what changed
and how should you update your code.
2001-04-21 07:12:21 +00:00

1563 lines
41 KiB
C

/*
* Window Maker window manager
*
* Copyright (c) 1997, 1998 Alfredo K. Kojima
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include "wconfig.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef KEEP_XKB_LOCK_STATUS
#include <X11/XKBlib.h>
#endif /* KEEP_XKB_LOCK_STATUS */
#include <stdlib.h>
#include <string.h>
#include <wraster.h>
#include "WindowMaker.h"
#include "GNUstep.h"
#include "texture.h"
#include "screen.h"
#include "wcore.h"
#include "framewin.h"
#include "stacking.h"
#include "funcs.h"
#define DBLCLICK_TIME wPreferences.dblclick_time
extern WPreferences wPreferences;
static void handleExpose(WObjDescriptor *desc, XEvent *event);
static void handleButtonExpose(WObjDescriptor *desc, XEvent *event);
static void buttonMouseDown(WObjDescriptor *desc, XEvent *event);
static void titlebarMouseDown(WObjDescriptor *desc, XEvent *event);
static void resizebarMouseDown(WObjDescriptor *desc, XEvent *event);
static void checkTitleSize(WFrameWindow *fwin);
static void paintButton(WCoreWindow *button, WTexture *texture,
unsigned long color, WPixmap *image, int pushed);
static void updateTitlebar(WFrameWindow *fwin);
WFrameWindow*
wFrameWindowCreate(WScreen *scr, int wlevel, int x, int y,
int width, int height, int *clearance, int flags,
WTexture **title_texture, WTexture **resize_texture,
unsigned long *color,
GC *gc, WMFont **font)
{
WFrameWindow *fwin;
fwin = wmalloc(sizeof(WFrameWindow));
memset(fwin, 0, sizeof(WFrameWindow));
fwin->screen_ptr = scr;
fwin->flags.single_texture = (flags & WFF_SINGLE_STATE) ? 1 : 0;
fwin->title_texture = title_texture;
fwin->resizebar_texture = resize_texture;
fwin->title_pixel = color;
fwin->title_clearance = clearance;
fwin->title_gc = gc;
fwin->font = font;
#ifdef KEEP_XKB_LOCK_STATUS
fwin->languagemode = XkbGroup1Index;
fwin->last_languagemode = XkbGroup2Index;
#endif
fwin->core = wCoreCreateTopLevel(scr, x, y, width, height,
(flags & WFF_BORDER)
? FRAME_BORDER_WIDTH : 0);
if (wPreferences.use_saveunders) {
unsigned long vmask;
XSetWindowAttributes attribs;
vmask = CWSaveUnder;
attribs.save_under = True;
XChangeWindowAttributes(dpy, fwin->core->window, vmask, &attribs);
}
/* setup stacking information */
fwin->core->stacking = wmalloc(sizeof(WStacking));
fwin->core->stacking->above = NULL;
fwin->core->stacking->under = NULL;
fwin->core->stacking->child_of = NULL;
fwin->core->stacking->window_level = wlevel;
AddToStackList(fwin->core);
wFrameWindowUpdateBorders(fwin, flags);
return fwin;
}
void
wFrameWindowUpdateBorders(WFrameWindow *fwin, int flags)
{
int theight;
int bsize;
int width, height;
int i;
WScreen *scr = fwin->screen_ptr;
width = fwin->core->width;
if (flags & WFF_IS_SHADED)
height = -1;
else
height = fwin->core->height - fwin->top_width - fwin->bottom_width;
if (flags & WFF_TITLEBAR)
theight = WMFontHeight(*fwin->font) + (*fwin->title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
else
theight = 0;
if (wPreferences.new_style) {
bsize = theight;
} else {
bsize = theight - 7;
}
if (fwin->titlebar) {
/* if we had a titlebar and is requesting for one,
* check if the size has changed and resize it */
if (flags & WFF_TITLEBAR) {
fwin->top_width = theight;
fwin->flags.need_texture_remake = 1;
if (wPreferences.new_style) {
if (fwin->left_button) {
wCoreConfigure(fwin->left_button, 0, 0, bsize, bsize);
}
#ifdef XKB_BUTTON_HINT
if (fwin->language_button)
if (fwin->flags.hide_left_button || !fwin->left_button
|| fwin->flags.lbutton_dont_fit) {
wCoreConfigure(fwin->language_button, 0, 0, bsize, bsize);
} else {
wCoreConfigure(fwin->language_button, bsize, 0, bsize, bsize);
}
#endif
if (fwin->right_button) {
wCoreConfigure(fwin->right_button, width-bsize+1,
0, bsize, bsize);
}
} else { /* !new_style */
if (fwin->left_button) {
wCoreConfigure(fwin->left_button, 3, (theight-bsize)/2,
bsize, bsize);
}
#ifdef XKB_BUTTON_HINT
if (fwin->language_button) {
wCoreConfigure(fwin->language_button, 6 + bsize, (theight-bsize)/2,
bsize, bsize);
}
#endif
if (fwin->right_button) {
wCoreConfigure(fwin->right_button, width-bsize-3,
(theight-bsize)/2, bsize, bsize);
}
}
updateTitlebar(fwin);
} else {
/* we had a titlebar, but now we don't need it anymore */
for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
FREE_PIXMAP(fwin->title_back[i]);
if (wPreferences.new_style) {
FREE_PIXMAP(fwin->lbutton_back[i]);
FREE_PIXMAP(fwin->rbutton_back[i]);
#ifdef XKB_BUTTON_HINT
FREE_PIXMAP(fwin->languagebutton_back[i]);
#endif
}
}
if (fwin->left_button)
wCoreDestroy(fwin->left_button);
fwin->left_button = NULL;
#ifdef XKB_BUTTON_HINT
if (fwin->language_button)
wCoreDestroy(fwin->language_button);
fwin->language_button = NULL;
#endif
if (fwin->right_button)
wCoreDestroy(fwin->right_button);
fwin->right_button = NULL;
wCoreDestroy(fwin->titlebar);
fwin->titlebar = NULL;
fwin->top_width = 0;
}
} else {
/* if we didn't have a titlebar and are being requested for
* one, create it */
if (flags & WFF_TITLEBAR) {
fwin->top_width = theight;
fwin->flags.titlebar = 1;
fwin->titlebar = wCoreCreate(fwin->core, 0, 0, width+1, theight);
if (flags & WFF_LEFT_BUTTON) {
fwin->flags.left_button = 1;
if (wPreferences.new_style) {
fwin->left_button = wCoreCreate(fwin->core, 0, 0,
bsize, bsize);
if (width < theight*4) {
fwin->flags.lbutton_dont_fit = 1;
} else {
XMapRaised(dpy, fwin->left_button->window);
}
} else {
fwin->left_button =
wCoreCreate(fwin->titlebar, 3, (theight-bsize)/2,
bsize, bsize);
XSetWindowBackground(dpy, fwin->left_button->window,
scr->widget_texture->normal.pixel);
if (width < theight*3) {
fwin->flags.lbutton_dont_fit = 1;
} else {
XMapRaised(dpy, fwin->left_button->window);
}
}
}
#ifdef XKB_BUTTON_HINT
if (flags & WFF_LANGUAGE_BUTTON) {
fwin->flags.language_button = 1;
if (wPreferences.new_style) {
fwin->language_button = wCoreCreate(fwin->core,
bsize, 0, bsize, bsize);
if (width < theight*4) {
fwin->flags.languagebutton_dont_fit = 1;
} else {
XMapRaised(dpy, fwin->language_button->window);
}
} else {
fwin->language_button =
wCoreCreate(fwin->titlebar, bsize + 6, (theight-bsize)/2,
bsize, bsize);
XSetWindowBackground(dpy, fwin->language_button->window,
scr->widget_texture->normal.pixel);
if (width < theight*3) {
fwin->flags.languagebutton_dont_fit = 1;
} else {
XMapRaised(dpy, fwin->language_button->window);
}
}
}
#endif
if (flags & WFF_RIGHT_BUTTON) {
fwin->flags.right_button = 1;
if (wPreferences.new_style) {
fwin->right_button =
wCoreCreate(fwin->core, width-bsize+1, 0,
bsize, bsize);
} else {
fwin->right_button =
wCoreCreate(fwin->titlebar, width-bsize-3,
(theight-bsize)/2, bsize, bsize);
XSetWindowBackground(dpy, fwin->right_button->window,
scr->widget_texture->normal.pixel);
}
if (width < theight*2) {
fwin->flags.rbutton_dont_fit = 1;
} else {
XMapRaised(dpy, fwin->right_button->window);
}
}
if (wPreferences.new_style)
updateTitlebar(fwin);
XMapRaised(dpy, fwin->titlebar->window);
fwin->flags.need_texture_remake = 1;
}
}
checkTitleSize(fwin);
if (flags & WFF_RESIZEBAR) {
fwin->bottom_width = RESIZEBAR_HEIGHT;
if (!fwin->resizebar) {
fwin->flags.resizebar = 1;
fwin->resizebar = wCoreCreate(fwin->core, 0,
height + fwin->top_width,
width, RESIZEBAR_HEIGHT);
fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
if (width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
fwin->resizebar_corner_width = (width - RESIZEBAR_MIN_WIDTH)/2;
if (fwin->resizebar_corner_width < 0)
fwin->resizebar_corner_width = 0;
}
XMapWindow(dpy, fwin->resizebar->window);
XLowerWindow(dpy, fwin->resizebar->window);
fwin->flags.need_texture_remake = 1;
} else {
if (height+fwin->top_width+fwin->bottom_width != fwin->core->height) {
wCoreConfigure(fwin->resizebar, 0, height + fwin->top_width,
width, RESIZEBAR_HEIGHT);
}
}
} else {
fwin->bottom_width = 0;
if (fwin->resizebar) {
fwin->bottom_width = 0;
wCoreDestroy(fwin->resizebar);
fwin->resizebar = NULL;
}
}
if (height + fwin->top_width + fwin->bottom_width != fwin->core->height
&& !(flags & WFF_IS_SHADED)) {
wFrameWindowResize(fwin, width,
height + fwin->top_width + fwin->bottom_width);
}
if (flags & WFF_BORDER) {
XSetWindowBorderWidth(dpy, fwin->core->window, FRAME_BORDER_WIDTH);
} else {
XSetWindowBorderWidth(dpy, fwin->core->window, 0);
}
/* setup object descriptors */
if (fwin->titlebar) {
fwin->titlebar->descriptor.handle_expose = handleExpose;
fwin->titlebar->descriptor.parent = fwin;
fwin->titlebar->descriptor.parent_type = WCLASS_FRAME;
fwin->titlebar->descriptor.handle_mousedown = titlebarMouseDown;
}
if (fwin->resizebar) {
fwin->resizebar->descriptor.handle_expose = handleExpose;
fwin->resizebar->descriptor.parent = fwin;
fwin->resizebar->descriptor.parent_type = WCLASS_FRAME;
fwin->resizebar->descriptor.handle_mousedown = resizebarMouseDown;
}
if (fwin->left_button) {
fwin->left_button->descriptor.handle_expose = handleButtonExpose;
fwin->left_button->descriptor.parent = fwin;
fwin->left_button->descriptor.parent_type = WCLASS_FRAME;
fwin->left_button->descriptor.handle_mousedown = buttonMouseDown;
}
#ifdef XKB_BUTTON_HINT
if (fwin->language_button) {
fwin->language_button->descriptor.handle_expose = handleButtonExpose;
fwin->language_button->descriptor.parent = fwin;
fwin->language_button->descriptor.parent_type = WCLASS_FRAME;
fwin->language_button->descriptor.handle_mousedown = buttonMouseDown;
}
#endif
if (fwin->right_button) {
fwin->right_button->descriptor.parent = fwin;
fwin->right_button->descriptor.parent_type = WCLASS_FRAME;
fwin->right_button->descriptor.handle_expose = handleButtonExpose;
fwin->right_button->descriptor.handle_mousedown = buttonMouseDown;
}
checkTitleSize(fwin);
}
void
wFrameWindowDestroy(WFrameWindow *fwin)
{
int i;
if (fwin->left_button)
wCoreDestroy(fwin->left_button);
#ifdef XKB_BUTTON_HINT
if (fwin->language_button)
wCoreDestroy(fwin->language_button);
#endif
if (fwin->right_button)
wCoreDestroy(fwin->right_button);
if (fwin->resizebar)
wCoreDestroy(fwin->resizebar);
if (fwin->titlebar)
wCoreDestroy(fwin->titlebar);
RemoveFromStackList(fwin->core);
wCoreDestroy(fwin->core);
if (fwin->title)
wfree(fwin->title);
for (i=0; i < (fwin->flags.single_texture ? 1 : 3); i++) {
FREE_PIXMAP(fwin->title_back[i]);
if (wPreferences.new_style) {
FREE_PIXMAP(fwin->lbutton_back[i]);
#ifdef XKB_BUTTON_HINT
FREE_PIXMAP(fwin->languagebutton_back[i]);
#endif
FREE_PIXMAP(fwin->rbutton_back[i]);
}
}
wfree(fwin);
}
void
wFrameWindowChangeState(WFrameWindow *fwin, int state)
{
if (fwin->flags.state==state)
return;
fwin->flags.state = state;
fwin->flags.need_texture_change = 1;
wFrameWindowPaint(fwin);
}
static void
updateTitlebar(WFrameWindow *fwin)
{
int x, w;
int theight;
theight = WMFontHeight(*fwin->font) + (*fwin->title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
x = 0;
w = fwin->core->width + 1;
if (wPreferences.new_style) {
if (fwin->flags.hide_left_button || !fwin->left_button
|| fwin->flags.lbutton_dont_fit) {
x = 0;
#ifdef XKB_BUTTON_HINT
if(fwin->language_button)
wCoreConfigure(fwin->language_button, 0, 0,
fwin->language_button->width,
fwin->language_button->width);
#endif
} else {
#ifdef XKB_BUTTON_HINT
if(fwin->language_button)
wCoreConfigure(fwin->language_button, fwin->left_button->width, 0,
fwin->language_button->width,
fwin->language_button->width);
#endif
x = fwin->left_button->width;
w -= fwin->left_button->width;
}
#ifdef XKB_BUTTON_HINT
if (fwin->flags.hide_language_button || !fwin->language_button
|| fwin->flags.languagebutton_dont_fit) {
} else {
x += fwin->language_button->width;
w -= fwin->language_button->width;
}
#endif
}
#ifdef XKB_BUTTON_HINT
else {
int bsize = theight - 7;
if (fwin->flags.hide_left_button || !fwin->left_button
|| fwin->flags.lbutton_dont_fit) {
if(fwin->language_button)
wCoreConfigure(fwin->language_button, 3, (theight-bsize)/2,
fwin->language_button->width,
fwin->language_button->width);
}
else {
if(fwin->language_button)
wCoreConfigure(fwin->language_button,
6 + fwin->left_button->width, (theight-bsize)/2,
fwin->language_button->width,
fwin->language_button->width);
}
}
#endif
if (wPreferences.new_style) {
if (!fwin->flags.hide_right_button && fwin->right_button
&& !fwin->flags.rbutton_dont_fit) {
w -= fwin->right_button->width;
}
}
if (wPreferences.new_style || fwin->titlebar->width!=w)
fwin->flags.need_texture_remake = 1;
wCoreConfigure(fwin->titlebar, x, 0, w, theight);
}
void
wFrameWindowHideButton(WFrameWindow *fwin, int flags)
{
if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button) {
XUnmapWindow(dpy, fwin->right_button->window);
fwin->flags.hide_right_button = 1;
}
if ((flags & WFF_LEFT_BUTTON) && fwin->left_button) {
XUnmapWindow(dpy, fwin->left_button->window);
fwin->flags.hide_left_button = 1;
}
#ifdef XKB_BUTTON_HINT
if ((flags & WFF_LANGUAGE_BUTTON) && fwin->language_button) {
XUnmapWindow(dpy, fwin->language_button->window);
fwin->flags.hide_language_button = 1;
}
#endif
if (fwin->titlebar) {
if (wPreferences.new_style) {
updateTitlebar(fwin);
} else {
#ifdef XKB_BUTTON_HINT
updateTitlebar(fwin);
#else
XClearWindow(dpy, fwin->titlebar->window);
wFrameWindowPaint(fwin);
#endif
}
checkTitleSize(fwin);
}
}
void
wFrameWindowShowButton(WFrameWindow *fwin, int flags)
{
if ((flags & WFF_RIGHT_BUTTON) && fwin->right_button
&& fwin->flags.hide_right_button) {
if (!fwin->flags.rbutton_dont_fit)
XMapWindow(dpy, fwin->right_button->window);
fwin->flags.hide_right_button = 0;
}
#ifdef XKB_BUTTON_HINT
if ((flags & WFF_LANGUAGE_BUTTON) && fwin->language_button
&& fwin->flags.hide_language_button) {
if (!fwin->flags.languagebutton_dont_fit)
XMapWindow(dpy, fwin->language_button->window);
fwin->flags.hide_language_button = 0;
}
#endif
if ((flags & WFF_LEFT_BUTTON) && fwin->left_button
&& fwin->flags.hide_left_button) {
if (!fwin->flags.lbutton_dont_fit)
XMapWindow(dpy, fwin->left_button->window);
fwin->flags.hide_left_button = 0;
}
if (fwin->titlebar) {
if (wPreferences.new_style) {
updateTitlebar(fwin);
} else {
XClearWindow(dpy, fwin->titlebar->window);
wFrameWindowPaint(fwin);
}
checkTitleSize(fwin);
}
}
static void
#ifdef XKB_BUTTON_HINT
renderTexture(WScreen *scr, WTexture *texture, int width, int height,
int bwidth, int bheight, int left, int language, int right,
Pixmap *title, Pixmap *lbutton, Pixmap *languagebutton, Pixmap *rbutton)
#else
renderTexture(WScreen *scr, WTexture *texture, int width, int height,
int bwidth, int bheight, int left, int right,
Pixmap *title, Pixmap *lbutton, Pixmap *rbutton)
#endif
{
RImage *img;
RImage *limg, *rimg, *mimg;
#ifdef XKB_BUTTON_HINT
RImage *timg;
#endif
int x, w;
*title = None;
*lbutton = None;
*rbutton = None;
#ifdef XKB_BUTTON_HINT
*languagebutton = None;
#endif
img = wTextureRenderImage(texture, width, height, WREL_FLAT);
if (!img) {
wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
return;
}
if (wPreferences.new_style) {
if (left) {
limg = RGetSubImage(img, 0, 0, bwidth, bheight);
} else
limg = NULL;
x = 0;
w = img->width;
#ifdef XKB_BUTTON_HINT
if (language) {
timg = RGetSubImage(img, bwidth * left, 0, bwidth, bheight);
} else
timg = NULL;
#endif
if (limg) {
RBevelImage(limg, RBEV_RAISED2);
if (!RConvertImage(scr->rcontext, limg, lbutton)) {
wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
}
x += limg->width;
w -= limg->width;
RReleaseImage(limg);
}
#ifdef XKB_BUTTON_HINT
if (timg) {
RBevelImage(timg, RBEV_RAISED2);
if (!RConvertImage(scr->rcontext, timg, languagebutton)) {
wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
}
x += timg->width;
w -= timg->width;
RReleaseImage(timg);
}
#endif
if (right) {
rimg = RGetSubImage(img, width - bwidth, 0, bwidth, bheight);
} else
rimg = NULL;
if (rimg) {
RBevelImage(rimg, RBEV_RAISED2);
if (!RConvertImage(scr->rcontext, rimg, rbutton)) {
wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
}
w -= rimg->width;
RReleaseImage(rimg);
}
if (w!=width) {
mimg = RGetSubImage(img, x, 0, w, img->height);
RBevelImage(mimg, RBEV_RAISED2);
if (!RConvertImage(scr->rcontext, mimg, title)) {
wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
}
RReleaseImage(mimg);
} else {
RBevelImage(img, RBEV_RAISED2);
if (!RConvertImage(scr->rcontext, img, title)) {
wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
}
}
} else {
RBevelImage(img, RBEV_RAISED2);
if (!RConvertImage(scr->rcontext, img, title)) {
wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
}
}
RReleaseImage(img);
}
static void
renderResizebarTexture(WScreen *scr, WTexture *texture, int width, int height,
int cwidth, Pixmap *pmap)
{
RImage *img;
RColor light;
RColor dark;
*pmap = None;
img = wTextureRenderImage(texture, width, height, WREL_FLAT);
if (!img) {
wwarning(_("could not render texture: %s"),
RMessageForError(RErrorCode));
return;
}
light.alpha = 0;
light.red = light.green = light.blue = 80;
dark.alpha = 0;
dark.red = dark.green = dark.blue = 40;
ROperateLine(img, RSubtractOperation, 0, 0, width-1, 0, &dark);
ROperateLine(img, RAddOperation, 0, 1, width-1, 1, &light);
ROperateLine(img, RSubtractOperation, cwidth, 2, cwidth, height-1, &dark);
ROperateLine(img, RAddOperation, cwidth+1, 2, cwidth+1, height-1, &light);
if (width > 1)
ROperateLine(img, RSubtractOperation, width-cwidth-2, 2,
width-cwidth-2, height-1, &dark);
ROperateLine(img, RAddOperation, width-cwidth-1, 2, width-cwidth-1,
height-1, &light);
#ifdef SHADOW_RESIZEBAR
ROperateLine(img, RAddOperation, 0, 1, 0, height-1, &light);
ROperateLine(img, RSubtractOperation, width-1, 1, width-1, height-1,
&dark);
ROperateLine(img, RSubtractOperation, 0, height-1, width-1, height-1,
&dark);
#endif /* SHADOW_RESIZEBAR */
if (!RConvertImage(scr->rcontext, img, pmap)) {
wwarning(_("error rendering image: %s"), RMessageForError(RErrorCode));
}
RReleaseImage(img);
}
static void
updateTexture(WFrameWindow *fwin)
{
int i;
unsigned long pixel;
i = fwin->flags.state;
if (fwin->titlebar) {
if (fwin->title_texture[i]->any.type!=WTEX_SOLID) {
XSetWindowBackgroundPixmap(dpy, fwin->titlebar->window,
fwin->title_back[i]);
if (wPreferences.new_style) {
if (fwin->left_button && fwin->lbutton_back[i])
XSetWindowBackgroundPixmap(dpy, fwin->left_button->window,
fwin->lbutton_back[i]);
#ifdef XKB_BUTTON_HINT
if (fwin->language_button && fwin->languagebutton_back[i]) {
XSetWindowBackgroundPixmap(dpy, fwin->language_button->window,
fwin->languagebutton_back[i]);
}
#endif
if (fwin->right_button && fwin->rbutton_back[i])
XSetWindowBackgroundPixmap(dpy, fwin->right_button->window,
fwin->rbutton_back[i]);
}
} else {
pixel = fwin->title_texture[i]->solid.normal.pixel;
XSetWindowBackground(dpy, fwin->titlebar->window, pixel);
if (wPreferences.new_style) {
if (fwin->left_button)
XSetWindowBackground(dpy, fwin->left_button->window,
pixel);
#ifdef XKB_BUTTON_HINT
if (fwin->language_button)
XSetWindowBackground(dpy, fwin->language_button->window,
pixel);
#endif
if (fwin->right_button)
XSetWindowBackground(dpy, fwin->right_button->window,
pixel);
}
}
XClearWindow(dpy, fwin->titlebar->window);
if (fwin->left_button) {
XClearWindow(dpy, fwin->left_button->window);
handleButtonExpose(&fwin->left_button->descriptor, NULL);
}
#ifdef XKB_BUTTON_HINT
if (fwin->language_button) {
XClearWindow(dpy, fwin->language_button->window);
handleButtonExpose(&fwin->language_button->descriptor, NULL);
}
#endif
if (fwin->right_button) {
XClearWindow(dpy, fwin->right_button->window);
handleButtonExpose(&fwin->right_button->descriptor, NULL);
}
}
}
static void
remakeTexture(WFrameWindow *fwin, int state)
{
Pixmap pmap, lpmap, rpmap;
#ifdef XKB_BUTTON_HINT
Pixmap tpmap;
#endif
if (fwin->title_texture[state] && fwin->titlebar) {
FREE_PIXMAP(fwin->title_back[state]);
if (wPreferences.new_style) {
FREE_PIXMAP(fwin->lbutton_back[state]);
FREE_PIXMAP(fwin->rbutton_back[state]);
#ifdef XKB_BUTTON_HINT
FREE_PIXMAP(fwin->languagebutton_back[state]);
#endif
}
if (fwin->title_texture[state]->any.type!=WTEX_SOLID) {
int left, right;
#ifdef XKB_BUTTON_HINT
int language;
#endif
int width;
/* eventually surrounded by if new_style */
left = fwin->left_button && !fwin->flags.hide_left_button
&& !fwin->flags.lbutton_dont_fit;
#ifdef XKB_BUTTON_HINT
language = fwin->language_button && !fwin->flags.hide_language_button
&& !fwin->flags.languagebutton_dont_fit;
#endif
right = fwin->right_button && !fwin->flags.hide_right_button
&& !fwin->flags.rbutton_dont_fit;
width = fwin->core->width+1;
#ifdef XKB_BUTTON_HINT
renderTexture(fwin->screen_ptr, fwin->title_texture[state],
width, fwin->titlebar->height,
fwin->titlebar->height, fwin->titlebar->height,
left, language, right, &pmap, &lpmap, &tpmap, &rpmap);
#else
renderTexture(fwin->screen_ptr, fwin->title_texture[state],
width, fwin->titlebar->height,
fwin->titlebar->height, fwin->titlebar->height,
left, right, &pmap, &lpmap, &rpmap);
#endif
fwin->title_back[state] = pmap;
if (wPreferences.new_style) {
fwin->lbutton_back[state] = lpmap;
fwin->rbutton_back[state] = rpmap;
#ifdef XKB_BUTTON_HINT
fwin->languagebutton_back[state] = tpmap;
#endif
}
}
}
if (fwin->resizebar_texture && fwin->resizebar_texture[0]
&& fwin->resizebar && state == 0) {
FREE_PIXMAP(fwin->resizebar_back[0]);
if (fwin->resizebar_texture[0]->any.type!=WTEX_SOLID) {
renderResizebarTexture(fwin->screen_ptr,
fwin->resizebar_texture[0],
fwin->resizebar->width,
fwin->resizebar->height,
fwin->resizebar_corner_width,
&pmap);
fwin->resizebar_back[0] = pmap;
}
/* this part should be in updateTexture() */
if (fwin->resizebar_texture[0]->any.type!=WTEX_SOLID) {
XSetWindowBackgroundPixmap(dpy, fwin->resizebar->window,
fwin->resizebar_back[0]);
} else {
XSetWindowBackground(dpy, fwin->resizebar->window,
fwin->resizebar_texture[0]->solid.normal.pixel);
}
XClearWindow(dpy, fwin->resizebar->window);
}
}
void
wFrameWindowPaint(WFrameWindow *fwin)
{
WScreen *scr = fwin->screen_ptr;
if (fwin->flags.is_client_window_frame)
fwin->flags.justification = wPreferences.title_justification;
if (fwin->flags.need_texture_remake) {
int i;
fwin->flags.need_texture_remake = 0;
fwin->flags.need_texture_change = 0;
if (fwin->flags.single_texture) {
remakeTexture(fwin, 0);
updateTexture(fwin);
} else {
/* first render the texture for the current state... */
remakeTexture(fwin, fwin->flags.state);
/* ... and paint it */
updateTexture(fwin);
for (i=0; i < 3; i++) {
if (i!=fwin->flags.state)
remakeTexture(fwin, i);
}
}
}
if (fwin->flags.need_texture_change) {
fwin->flags.need_texture_change = 0;
updateTexture(fwin);
}
if (fwin->titlebar && !fwin->flags.repaint_only_resizebar
&& fwin->title_texture[fwin->flags.state]->any.type==WTEX_SOLID) {
wDrawBevel(fwin->titlebar->window, fwin->titlebar->width,
fwin->titlebar->height,
(WTexSolid*)fwin->title_texture[fwin->flags.state],
WREL_RAISED);
}
if (fwin->resizebar && !fwin->flags.repaint_only_titlebar
&& fwin->resizebar_texture[0]->any.type == WTEX_SOLID) {
Window win;
int w, h;
int cw;
GC light_gc, dim_gc;
WTexSolid *texture = (WTexSolid*)fwin->resizebar_texture[0];
w = fwin->resizebar->width;
h = fwin->resizebar->height;
cw = fwin->resizebar_corner_width;
light_gc = texture->light_gc;
dim_gc = texture->dim_gc;
win = fwin->resizebar->window;
XDrawLine(dpy, win, dim_gc, 0, 0, w, 0);
XDrawLine(dpy, win, light_gc, 0, 1, w, 1);
XDrawLine(dpy, win, dim_gc, cw, 2, cw, h);
XDrawLine(dpy, win, light_gc, cw+1, 2, cw+1, h);
XDrawLine(dpy, win, dim_gc, w-cw-2, 2, w-cw-2, h);
XDrawLine(dpy, win, light_gc, w-cw-1, 2, w-cw-1, h);
#ifdef SHADOW_RESIZEBAR
XDrawLine(dpy, win, light_gc, 0, 1, 0, h-1);
XDrawLine(dpy, win, dim_gc, w-1, 2, w-1, h-1);
XDrawLine(dpy, win, dim_gc, 1, h-1, cw, h-1);
XDrawLine(dpy, win, dim_gc, cw+2, h-1, w-cw-2, h-1);
XDrawLine(dpy, win, dim_gc, w-cw, h-1, w-1, h-1);
#endif /* SHADOW_RESIZEBAR */
}
if (fwin->titlebar && !fwin->flags.repaint_only_resizebar) {
int x, w;
int lofs = 6, rofs = 6;
int titlelen;
int allButtons = 1;
if (!wPreferences.new_style) {
if (fwin->left_button && !fwin->flags.hide_left_button
&& !fwin->flags.lbutton_dont_fit)
lofs += fwin->left_button->width + 3;
else
allButtons = 0;
#ifdef XKB_BUTTON_HINT
if (fwin->language_button && !fwin->flags.hide_language_button
&& !fwin->flags.languagebutton_dont_fit)
lofs += fwin->language_button->width;
else
allButtons = 0;
#endif
if (fwin->right_button && !fwin->flags.hide_right_button
&& !fwin->flags.rbutton_dont_fit)
rofs += fwin->right_button->width + 3;
else
allButtons = 0;
}
#ifdef XKB_BUTTON_HINT
fwin->languagebutton_image =
scr->b_pixmaps[WBUT_XKBGROUP1 + fwin->languagemode];
#endif
if (fwin->title) {
char *title;
title = ShrinkString(*fwin->font, fwin->title,
fwin->titlebar->width - lofs - rofs);
titlelen = strlen(title);
w = WMWidthOfString(*fwin->font, title, titlelen);
switch (fwin->flags.justification) {
case WTJ_LEFT:
x = lofs;
break;
case WTJ_RIGHT:
x = fwin->titlebar->width - w - rofs;
break;
default:
if (!allButtons)
x = lofs + (fwin->titlebar->width - w - lofs - rofs) / 2;
else
x = (fwin->titlebar->width - w) / 2;
break;
}
XSetForeground(dpy, *fwin->title_gc,
fwin->title_pixel[fwin->flags.state]);
WMDrawString(scr->wmscreen, fwin->titlebar->window,
*fwin->title_gc, *fwin->font, x, *fwin->title_clearance + TITLEBAR_EXTEND_SPACE,
title, titlelen);
wfree(title);
}
if (fwin->left_button)
handleButtonExpose(&fwin->left_button->descriptor, NULL);
if (fwin->right_button)
handleButtonExpose(&fwin->right_button->descriptor, NULL);
#ifdef XKB_BUTTON_HINT
if (fwin->language_button)
handleButtonExpose(&fwin->language_button->descriptor, NULL);
#endif
}
}
static void
reconfigure(WFrameWindow *fwin, int x, int y, int width, int height,
Bool dontMove)
{
int k = (wPreferences.new_style ? 4 : 3);
int resizedHorizontally = 0;
if (dontMove)
XResizeWindow(dpy, fwin->core->window, width, height);
else
XMoveResizeWindow(dpy, fwin->core->window, x, y, width, height);
/*
if (fwin->core->height != height && fwin->resizebar)
XMoveWindow(dpy, fwin->resizebar->window, 0,
height - fwin->resizebar->height);
*/
if (fwin->core->width != width) {
fwin->flags.need_texture_remake = 1;
resizedHorizontally = 1;
}
fwin->core->width = width;
fwin->core->height = height;
if (fwin->titlebar && resizedHorizontally) {
/* Check if the titlebar is wide enough to hold the buttons.
* Temporarily remove them if can't
*/
if (fwin->left_button) {
if (width < fwin->top_width*k && !fwin->flags.lbutton_dont_fit) {
if (!fwin->flags.hide_left_button) {
XUnmapWindow(dpy, fwin->left_button->window);
}
fwin->flags.lbutton_dont_fit = 1;
} else if (width >= fwin->top_width*k && fwin->flags.lbutton_dont_fit) {
if (!fwin->flags.hide_left_button) {
XMapWindow(dpy, fwin->left_button->window);
}
fwin->flags.lbutton_dont_fit = 0;
}
}
#ifdef XKB_BUTTON_HINT
if (fwin->language_button) {
if (width < fwin->top_width*k && !fwin->flags.languagebutton_dont_fit) {
if (!fwin->flags.hide_language_button) {
XUnmapWindow(dpy, fwin->language_button->window);
}
fwin->flags.languagebutton_dont_fit = 1;
} else if (width >= fwin->top_width*k && fwin->flags.languagebutton_dont_fit) {
if (!fwin->flags.hide_language_button) {
XMapWindow(dpy, fwin->language_button->window);
}
fwin->flags.languagebutton_dont_fit = 0;
}
}
#endif
if (fwin->right_button) {
if (width < fwin->top_width*2 && !fwin->flags.rbutton_dont_fit) {
if (!fwin->flags.hide_right_button) {
XUnmapWindow(dpy, fwin->right_button->window);
}
fwin->flags.rbutton_dont_fit = 1;
} else if (width >= fwin->top_width*2 && fwin->flags.rbutton_dont_fit) {
if (!fwin->flags.hide_right_button) {
XMapWindow(dpy, fwin->right_button->window);
}
fwin->flags.rbutton_dont_fit = 0;
}
}
if (wPreferences.new_style) {
if (fwin->right_button)
XMoveWindow(dpy, fwin->right_button->window,
width - fwin->right_button->width + 1, 0);
} else {
if (fwin->right_button)
XMoveWindow(dpy, fwin->right_button->window,
width - fwin->right_button->width - 3,
(fwin->titlebar->height - fwin->right_button->height)/2);
}
updateTitlebar(fwin);
checkTitleSize(fwin);
}
if (fwin->resizebar) {
wCoreConfigure(fwin->resizebar, 0,
fwin->core->height - fwin->resizebar->height,
fwin->core->width, fwin->resizebar->height);
fwin->resizebar_corner_width = RESIZEBAR_CORNER_WIDTH;
if (fwin->core->width < RESIZEBAR_CORNER_WIDTH*2 + RESIZEBAR_MIN_WIDTH) {
fwin->resizebar_corner_width = fwin->core->width/2;
}
}
}
void
wFrameWindowConfigure(WFrameWindow *fwin, int x, int y, int width, int height)
{
reconfigure(fwin, x, y, width, height, False);
}
void
wFrameWindowResize(WFrameWindow *fwin, int width, int height)
{
reconfigure(fwin, 0, 0, width, height, True);
}
int
wFrameWindowChangeTitle(WFrameWindow *fwin, char *new_title)
{
/* check if the title is the same as before */
if (fwin->title) {
if (new_title && (strcmp(fwin->title, new_title) == 0)) {
return 0;
}
} else {
if (!new_title)
return 0;
}
if (fwin->title)
wfree(fwin->title);
fwin->title = wstrdup(new_title);
if (fwin->titlebar) {
XClearWindow(dpy, fwin->titlebar->window);
wFrameWindowPaint(fwin);
}
checkTitleSize(fwin);
return 1;
}
#ifdef OLWM_HINTS
void
wFrameWindowUpdatePushButton(WFrameWindow *fwin, Bool pushed)
{
fwin->flags.right_button_pushed_in = pushed;
paintButton(fwin->right_button, fwin->title_texture[fwin->flags.state],
fwin->title_pixel[fwin->flags.state],
fwin->rbutton_image, pushed);
}
#endif /* OLWM_HINTS */
#ifdef XKB_BUTTON_HINT
void
wFrameWindowUpdateLanguageButton(WFrameWindow *fwin)
{
paintButton(fwin->language_button, fwin->title_texture[fwin->flags.state],
fwin->title_pixel[fwin->flags.state],
fwin->languagebutton_image, True);
}
#endif /* XKB_BUTTON_HINT */
/*********************************************************************/
static void
handleExpose(WObjDescriptor *desc, XEvent *event)
{
WFrameWindow *fwin = (WFrameWindow*)desc->parent;
if (fwin->titlebar && fwin->titlebar->window == event->xexpose.window)
fwin->flags.repaint_only_titlebar = 1;
if (fwin->resizebar && fwin->resizebar->window == event->xexpose.window)
fwin->flags.repaint_only_resizebar = 1;
wFrameWindowPaint(fwin);
fwin->flags.repaint_only_titlebar = 0;
fwin->flags.repaint_only_resizebar = 0;
}
static void
checkTitleSize(WFrameWindow *fwin)
{
int width;
if (!fwin->title) {
fwin->flags.incomplete_title = 0;
return;
}
if (!fwin->titlebar) {
fwin->flags.incomplete_title = 1;
return;
} else {
width = fwin->titlebar->width - 6 - 6;
}
if (!wPreferences.new_style) {
if (fwin->left_button && !fwin->flags.hide_left_button
&& !fwin->flags.lbutton_dont_fit)
width -= fwin->left_button->width + 3;
#ifdef XKB_BUTTON_HINT
if (fwin->language_button && !fwin->flags.hide_language_button
&& !fwin->flags.languagebutton_dont_fit)
width -= fwin->language_button->width + 3;
#endif
if (fwin->right_button && !fwin->flags.hide_right_button
&& !fwin->flags.rbutton_dont_fit)
width -= fwin->right_button->width + 3;
}
if (WMWidthOfString(*fwin->font, fwin->title, strlen(fwin->title)) > width) {
fwin->flags.incomplete_title = 1;
} else {
fwin->flags.incomplete_title = 0;
}
}
static void
paintButton(WCoreWindow *button, WTexture *texture, unsigned long color,
WPixmap *image, int pushed)
{
WScreen *scr = button->screen_ptr;
GC copy_gc = scr->copy_gc;
int x=0, y=0, d=0;
int left=0, width=0;
/* setup stuff according to the state */
if (pushed) {
if (image) {
if (image->width>=image->height*2) {
/* the image contains 2 pictures: the second is for the
* pushed state */
width = image->width/2;
left = image->width/2;
} else {
width = image->width;
}
}
XSetClipMask(dpy, copy_gc, None);
XSetForeground(dpy, copy_gc, scr->white_pixel);
d=1;
if (wPreferences.new_style) {
XFillRectangle(dpy, button->window, copy_gc, 0, 0,
button->width-1, button->height-1);
XSetForeground(dpy, copy_gc, scr->black_pixel);
XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
button->width-1, button->height-1);
} else {
XFillRectangle(dpy, button->window, copy_gc, 0, 0,
button->width, button->height);
XSetForeground(dpy, copy_gc, scr->black_pixel);
XDrawRectangle(dpy, button->window, copy_gc, 0, 0,
button->width, button->height);
}
} else {
XClearWindow(dpy, button->window);
if (image) {
if (image->width>=image->height*2)
width = image->width/2;
else
width = image->width;
}
d=0;
if (wPreferences.new_style) {
if (texture->any.type==WTEX_SOLID || pushed) {
wDrawBevel(button->window, button->width, button->height,
(WTexSolid*)texture, WREL_RAISED);
}
} else {
wDrawBevel(button->window, button->width, button->height,
scr->widget_texture, WREL_RAISED);
}
}
if (image) {
/* display image */
XSetClipMask(dpy, copy_gc, image->mask);
x = (button->width - width)/2 + d;
y = (button->height - image->height)/2 + d;
XSetClipOrigin(dpy, copy_gc, x-left, y);
if (!wPreferences.new_style) {
XSetForeground(dpy, copy_gc, scr->black_pixel);
if (!pushed) {
if (image->depth==1)
XCopyPlane(dpy, image->image, button->window, copy_gc,
left, 0, width, image->height, x, y, 1);
else
XCopyArea(dpy, image->image, button->window, copy_gc,
left, 0, width, image->height, x, y);
} else {
XSetForeground(dpy, copy_gc, scr->dark_pixel);
XFillRectangle(dpy, button->window, copy_gc, 0, 0,
button->width, button->height);
}
} else {
if (pushed) {
XSetForeground(dpy, copy_gc, scr->black_pixel);
} else {
XSetForeground(dpy, copy_gc, color);
XSetBackground(dpy, copy_gc, texture->any.color.pixel);
}
XFillRectangle(dpy, button->window, copy_gc, 0, 0,
button->width, button->height);
}
}
}
static void
handleButtonExpose(WObjDescriptor *desc, XEvent *event)
{
WFrameWindow *fwin = (WFrameWindow*)desc->parent;
WCoreWindow *button = (WCoreWindow*)desc->self;
#ifdef XKB_BUTTON_HINT
if (button == fwin->language_button) {
if (wPreferences.modelock){
paintButton(button, fwin->title_texture[fwin->flags.state],
fwin->title_pixel[fwin->flags.state],
fwin->languagebutton_image, False);
}
} else
#endif
if (button == fwin->left_button) {
paintButton(button, fwin->title_texture[fwin->flags.state],
fwin->title_pixel[fwin->flags.state],
fwin->lbutton_image, False);
} else {
Bool pushed = False;
#ifdef OLWM_HINTS
if (fwin->flags.right_button_pushed_in)
pushed = True;
#endif
/* emulate the olwm pushpin in the "out" state */
paintButton(button, fwin->title_texture[fwin->flags.state],
fwin->title_pixel[fwin->flags.state],
fwin->rbutton_image, pushed);
}
}
static void
titlebarMouseDown(WObjDescriptor *desc, XEvent *event)
{
WFrameWindow *fwin = desc->parent;
WCoreWindow *titlebar = desc->self;
if (IsDoubleClick(fwin->core->screen_ptr, event)) {
if (fwin->on_dblclick_titlebar)
(*fwin->on_dblclick_titlebar)(titlebar, fwin->child, event);
} else {
if (fwin->on_mousedown_titlebar)
(*fwin->on_mousedown_titlebar)(titlebar, fwin->child, event);
}
}
static void
resizebarMouseDown(WObjDescriptor *desc, XEvent *event)
{
WFrameWindow *fwin = desc->parent;
WCoreWindow *resizebar = desc->self;
if (fwin->on_mousedown_resizebar)
(*fwin->on_mousedown_resizebar)(resizebar, fwin->child, event);
}
static void
buttonMouseDown(WObjDescriptor *desc, XEvent *event)
{
WFrameWindow *fwin = desc->parent;
WCoreWindow *button = desc->self;
WPixmap *image;
XEvent ev;
int done=0, execute=1;
WTexture *texture;
unsigned long pixel;
int clickButton = event->xbutton.button;
if (IsDoubleClick(fwin->core->screen_ptr, event)) {
if (button == fwin->right_button && fwin->on_dblclick_right) {
(*fwin->on_dblclick_right)(button, fwin->child, event);
}
return;
}
if (button == fwin->left_button) {
image = fwin->lbutton_image;
} else {
image = fwin->rbutton_image;
}
#ifdef XKB_BUTTON_HINT
if (button == fwin->language_button) {
if (!wPreferences.modelock) return;
image = fwin->languagebutton_image;
}
#endif
pixel = fwin->title_pixel[fwin->flags.state];
texture = fwin->title_texture[fwin->flags.state];
paintButton(button, texture, pixel, image, True);
while (!done) {
WMMaskEvent(dpy, LeaveWindowMask|EnterWindowMask|ButtonReleaseMask
|ButtonPressMask|ExposureMask, &ev);
switch (ev.type) {
case LeaveNotify:
execute = 0;
paintButton(button, texture, pixel, image, False);
break;
case EnterNotify:
execute = 1;
paintButton(button, texture, pixel, image, True);
break;
case ButtonPress:
break;
case ButtonRelease:
if (ev.xbutton.button == clickButton)
done = 1;
break;
default:
WMHandleEvent(&ev);
}
}
paintButton(button, texture, pixel, image, False);
if (execute) {
if (button == fwin->left_button) {
if (fwin->on_click_left)
(*fwin->on_click_left)(button, fwin->child, &ev);
} else if (button == fwin->right_button) {
if (fwin->on_click_right)
(*fwin->on_click_right)(button, fwin->child, &ev);
}
#ifdef XKB_BUTTON_HINT
else if (button == fwin->language_button) {
if (fwin->on_click_language)
(*fwin->on_click_language)(button, fwin->child, &ev);
}
#endif
}
}